diff --git a/pkg/noun/manage.c b/pkg/noun/manage.c index d0bfb04f52..90a8eae3d4 100644 --- a/pkg/noun/manage.c +++ b/pkg/noun/manage.c @@ -2186,7 +2186,6 @@ u3m_reclaim(void) } /* _cm_pack_rewrite(): trace through arena, rewriting pointers. - * XX need to version; dynamic scope insanity! */ static void _cm_pack_rewrite(void) diff --git a/pkg/noun/v1/allocate.c b/pkg/noun/v1/allocate.c index 07f30c0f1f..4192fedd20 100644 --- a/pkg/noun/v1/allocate.c +++ b/pkg/noun/v1/allocate.c @@ -1,2078 +1,45 @@ /// @file -#include "v1/allocate.h" +#include "pkg/noun/allocate.h" +#include "pkg/noun/v1/allocate.h" -#include "hashtable.h" +#include "pkg/noun/v1/hashtable.h" #include "log.h" -#include "manage.h" +#include "pkg/noun/v1/manage.h" #include "options.h" #include "retrieve.h" #include "trace.h" #include "vortex.h" -u3_v1_road* u3a_v1_Road; - -#ifdef U3_MEMORY_DEBUG -c3_w u3_Code; -#endif - -/* _box_count(): adjust memory count. -*/ -#ifdef U3_CPU_DEBUG -static void -_box_count(c3_ws siz_ws) -{ - u3R_v1->all.fre_w += siz_ws; - - { - c3_w end_w = u3a_v1_heap(u3R_v1); - c3_w all_w = (end_w - u3R_v1->all.fre_w); - - if ( all_w > u3R_v1->all.max_w ) { - u3R_v1->all.max_w = all_w; - } - } -} -#else -static void -_box_count(c3_ws siz_ws) { } -#endif - -/* _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] -*/ -static c3_w -_v1_box_slot(c3_w siz_w) -{ - if ( siz_w < u3a_minimum ) { - return 0; - } - else { - c3_w i_w = 1; - - while ( 1 ) { - if ( i_w == u3a_fbox_no ) { - return (i_w - 1); - } - if ( siz_w < 16 ) { - return i_w; - } - siz_w = (siz_w + 1) >> 1; - i_w += 1; - } - } -} - -/* _box_make(): construct a box. -*/ -static u3a_box* -_box_make(void* box_v, c3_w siz_w, c3_w use_w) -{ - u3a_box* box_u = box_v; - c3_w* box_w = box_v; - - u3_assert(siz_w >= u3a_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_attach(): attach a box to the free list. -*/ -static void -_box_attach(u3a_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_box); (i_w + 1) < box_u->siz_w; i_w++ ) { - box_w[i_w] = 0xdeadbeef; - } - } -#endif - - _box_count(box_u->siz_w); - { - c3_w sel_w = _box_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_detach(): detach a box from the free list. -*/ -static void -_box_detach(u3a_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; - - _box_count(-(box_u->siz_w)); - - 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_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_free(): free and coalesce. -*/ -static void -_box_free(u3a_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_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_box* pox_u = (u3a_box*)(void *)(box_w - laz_w); - - if ( 0 == pox_u->use_w ) { - _box_detach(pox_u); - _box_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_box* nox_u = (u3a_box*)(void *)(box_w + box_u->siz_w); - - if ( 0 == nox_u->use_w ) { - _box_detach(nox_u); - _box_make(box_u, (box_u->siz_w + nox_u->siz_w), 0); - } - _box_attach(box_u); - } - } - else { - /* Try to coalesce with the block above. - */ - if ( (box_w + box_u->siz_w) != u3a_v1_into(u3R_v1->rut_p) ) { - u3a_box* nox_u = (u3a_box*)(void *)(box_w + box_u->siz_w); - - if ( 0 == nox_u->use_w ) { - _box_detach(nox_u); - _box_make(box_u, (box_u->siz_w + nox_u->siz_w), 0); - } - } - - /* Try to coalesce with the block below, or with the wilderness. - */ - if ( box_w == u3a_v1_into(u3R_v1->hat_p) ) { - u3R_v1->hat_p = u3a_v1_outa(box_w + box_u->siz_w); - } - else { - c3_w laz_w = *(box_w - 1); - u3a_box* pox_u = (u3a_box*)(void *)(box_w - laz_w); - - if ( 0 == pox_u->use_w ) { - _box_detach(pox_u); - _box_make(pox_u, (laz_w + box_u->siz_w), 0); - box_u = pox_u; - } - _box_attach(box_u); - } - } /* end south */ -} - -/* _me_align_pad(): pad to first point after pos_p aligned at (ald_w, alp_w). -*/ -static __inline__ c3_w -_me_align_pad(u3_post pos_p, c3_w ald_w, c3_w alp_w) -{ - c3_w adj_w = (ald_w - (alp_w + 1)); - c3_p off_p = (pos_p + adj_w); - c3_p orp_p = off_p &~ (ald_w - 1); - c3_p fin_p = orp_p + alp_w; - c3_w pad_w = (fin_p - pos_p); - - return pad_w; -} - -/* _me_align_dap(): pad to last point before pos_p aligned at (ald_w, alp_w). -*/ -static __inline__ c3_w -_me_align_dap(u3_post pos_p, c3_w ald_w, c3_w alp_w) -{ - c3_w adj_w = alp_w; - c3_p off_p = (pos_p - adj_w); - c3_p orp_p = (off_p &~ (ald_w - 1)); - c3_p fin_p = orp_p + alp_w; - c3_w pad_w = (pos_p - fin_p); - - return pad_w; -} - -/* _ca_box_make_hat(): in u3R_v1, allocate directly on the hat. -*/ -static u3a_box* -_ca_box_make_hat(c3_w len_w, c3_w ald_w, c3_w off_w, c3_w use_w) -{ - c3_w - pad_w, /* padding between returned pointer and box */ - siz_w; /* total size of allocation */ - u3_post - box_p, /* start of box */ - all_p; /* start of returned pointer */ - - if ( c3y == u3a_v1_is_north(u3R_v1) ) { - box_p = all_p = u3R_v1->hat_p; - 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); - - // hand-inlined: siz_w >= u3a_v1_open(u3R_v1) - // - if ( (siz_w >= (u3R_v1->cap_p - u3R_v1->hat_p)) ) { - return 0; - } - u3R_v1->hat_p += siz_w; - } - else { - box_p = all_p = u3R_v1->hat_p - len_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); - - // hand-inlined: siz_w >= u3a_v1_open(u3R_v1) - // - if ( siz_w >= (u3R_v1->hat_p - u3R_v1->cap_p) ) { - return 0; - } - box_p = u3R_v1->hat_p -= siz_w; - } - c3_dessert(!(ald_w <= 2 && off_w == 0) || (0 == pad_w)); - c3_dessert(pad_w <= 4); - - return _box_make(u3a_v1_into(box_p), siz_w, use_w); -} - -#if 0 -/* _me_road_all_hat(): in u3R_v1, allocate directly on the hat. -*/ -static u3a_box* -_ca_box_make_hat(c3_w len_w, c3_w alm_w, c3_w use_w) -{ - return _box_make(_me_road_all_hat(len_w), len_w, use_w); -} -#endif - -#if 0 // not yet used -/* _me_road_all_cap(): in u3R_v1, allocate directly on the cap. -*/ -static c3_w* -_me_road_all_cap(c3_w len_w) -{ - if ( len_w > u3a_v1_open(u3R_v1) ) { - u3m_bail(c3__meme); return 0; - } - - if ( c3y == u3a_v1_is_north(u3R_v1) ) { - u3R_v1->cap_p -= len_w; - return u3a_v1_into(u3R_v1->cap_p); - } - else { - u3_post all_p; - - all_p = u3R_v1->cap_p; - u3R_v1->cap_p += len_w; - return u3a_v1_into(all_p); - } -} -#endif - -#if 0 -/* u3a_v1_sane(): check allocator sanity. -*/ -void -u3a_v1_sane(void) -{ - c3_w i_w; - - for ( i_w = 0; i_w < u3a_v1_fbox_no; i_w++ ) { - u3a_v1_fbox* fre_u = u3R_v1->all.fre_u[i_w]; - - while ( fre_u ) { - if ( fre_u == u3R_v1->all.fre_u[i_w] ) { - u3_assert(fre_u->pre_u == 0); - } - else { - u3_assert(fre_u->pre_u != 0); - u3_assert(fre_u->pre_u->nex_u == fre_u); - if ( fre_u->nex_u != 0 ) { - u3_assert(fre_u->nex_u->pre_u == fre_u); - } - } - fre_u = fre_u->nex_u; - } - } -} -#endif - -/* _ca_reclaim_half(): reclaim from memoization cache. -*/ -static void -_v1_ca_reclaim_half(void) -{ - // XX u3l_log avoid here, as it can - // cause problems when handling errors - - if ( (0 == u3R_v1->cax.har_p) || - (0 == u3to(u3h_root, u3R_v1->cax.har_p)->use_w) ) - { - fprintf(stderr, "allocate: reclaim: memo cache: empty\r\n"); - u3m_bail(c3__meme); - } - -#if 1 - fprintf(stderr, "allocate: reclaim: half of %d entries\r\n", - u3to(u3h_root, u3R_v1->cax.har_p)->use_w); - - u3h_trim_to(u3R_v1->cax.har_p, u3to(u3h_root, u3R_v1->cax.har_p)->use_w / 2); -#else - /* brutal and guaranteed effective - */ - u3h_free(u3R_v1->cax.har_p); - u3R_v1->cax.har_p = u3h_new(); -#endif -} - -/* _v1_ca_v1_willoc(): u3a_v1_walloc() internals. -*/ -static void* -_v1_ca_v1_willoc(c3_w len_w, c3_w ald_w, c3_w alp_w) -{ - c3_w siz_w = c3_max(u3a_minimum, u3a_v1_boxed(len_w)); - c3_w sel_w = _box_slot(siz_w); - - // XX: this logic is totally bizarre, but preserve it. - // - if ( (sel_w != 0) && (sel_w != u3a_v1_fbox_no - 1) ) { - sel_w += 1; - } - - // u3l_log("walloc %d: *pfr_p %x", len_w, u3R_v1->all.fre_p[sel_w]); - while ( 1 ) { - u3p(u3a_v1_fbox) *pfr_p = &u3R_v1->all.fre_p[sel_w]; - - while ( 1 ) { - if ( 0 == *pfr_p ) { - if ( sel_w < (u3a_fbox_no - 1) ) { - sel_w += 1; - break; - } - else { - // nothing in top free list; chip away at the hat - // - u3a_box* box_u; - - // memory nearly empty; reclaim; should not be needed - // - // if ( (u3a_v1_open(u3R_v1) + u3R_v1->all.fre_w) < 65536 ) { _ca_reclaim_half(); } - box_u = _ca_box_make_hat(siz_w, ald_w, alp_w, 1); - - /* Flush a bunch of cell cache, then try again. - */ - if ( 0 == box_u ) { - if ( u3R_v1->all.cel_p ) { - u3a_v1_reflux(); - - return _ca_v1_willoc(len_w, ald_w, alp_w); - } - else { - _ca_reclaim_half(); - return _ca_v1_willoc(len_w, ald_w, alp_w); - } - } - else return u3a_boxto(box_u); - } - } - else { - c3_w pad_w = _me_align_pad(*pfr_p, ald_w, alp_w); - - if ( 1 == ald_w ) c3_assert(0 == pad_w); - - if ( (siz_w + pad_w) > u3to(u3a_fbox, *pfr_p)->box_u.siz_w ) { - /* This free block is too small. Continue searching. - */ - pfr_p = &(u3to(u3a_fbox, *pfr_p)->nex_p); - continue; - } - else { - u3a_box* box_u = &(u3to(u3a_fbox, *pfr_p)->box_u); - - /* We have found a free block of adequate size. Remove it - ** from the free list. - */ - siz_w += pad_w; - - _box_count(-(box_u->siz_w)); - { - if ( (0 != u3to(u3a_v1_fbox, *pfr_p)->pre_p) && - (u3to(u3a_v1_fbox, u3to(u3a_v1_fbox, *pfr_p)->pre_p)->nex_p - != (*pfr_p)) ) - { - u3_assert(!"loom: corrupt"); - } - - if( (0 != u3to(u3a_v1_fbox, *pfr_p)->nex_p) && - (u3to(u3a_v1_fbox, u3to(u3a_v1_fbox, *pfr_p)->nex_p)->pre_p - != (*pfr_p)) ) - { - u3_assert(!"loom: corrupt"); - } - - if ( 0 != u3to(u3a_v1_fbox, *pfr_p)->nex_p ) { - u3to(u3a_v1_fbox, u3to(u3a_v1_fbox, *pfr_p)->nex_p)->pre_p = - u3to(u3a_v1_fbox, *pfr_p)->pre_p; - } - *pfr_p = u3to(u3a_v1_fbox, *pfr_p)->nex_p; - } - - /* If we can chop off another block, do it. - */ - if ( (siz_w + u3a_minimum) <= box_u->siz_w ) { - /* Split the block. - */ - c3_w* box_w = ((c3_w *)(void *)box_u); - c3_w* end_w = box_w + siz_w; - c3_w lef_w = (box_u->siz_w - siz_w); - - _box_attach(_box_make(end_w, lef_w, 0)); - return u3a_boxto(_box_make(box_w, siz_w, 1)); - } - else { - u3_assert(0 == box_u->use_w); - box_u->use_w = 1; - -#ifdef U3_MEMORY_DEBUG - box_u->cod_w = u3_Code; -#endif - return u3a_boxto(box_u); - } - } - } - } - } -} - -/* _ca_walloc(): u3a_v1_walloc() internals. -*/ -static void* -_v1_ca_walloc(c3_w len_w, c3_w ald_w, c3_w alp_w) -{ - void* ptr_v; - - while ( 1 ) { - ptr_v = _ca_v1_willoc(len_w, ald_w, alp_w); - if ( 0 != ptr_v ) { - break; - } - _ca_reclaim_half(); - } - return ptr_v; -} - -/* u3a_v1_walloc(): allocate storage words on hat heap. -*/ -void* -u3a_v1_walloc(c3_w len_w) -{ - void* ptr_v; - - ptr_v = _ca_walloc(len_w, 1, 0); - -#if 0 - if ( (703 == u3_Code) && - u3a_v1_botox(ptr_v) == (u3a_box*)(void *)0x200dfe3e4 ) { - static int xuc_i; - - u3l_log("xuc_i %d", xuc_i); - if ( 1 == xuc_i ) { - u3a_box* box_u = u3a_v1_botox(ptr_v); - - box_u->cod_w = 999; - } - xuc_i++; - } -#endif - return ptr_v; -} - -/* u3a_v1_wealloc(): realloc in words. -*/ -void* -u3a_v1_wealloc(void* lag_v, c3_w len_w) -{ - if ( !lag_v ) { - return u3a_v1_walloc(len_w); - } - else { - u3a_box* box_u = u3a_v1_botox(lag_v); - c3_w* old_w = lag_v; - c3_w tiz_w = c3_min(box_u->siz_w, len_w); - { - c3_w* new_w = u3a_v1_walloc(len_w); - c3_w i_w; - - for ( i_w = 0; i_w < tiz_w; i_w++ ) { - new_w[i_w] = old_w[i_w]; - } - u3a_v1_wfree(lag_v); - return new_w; - } - } -} - -/* u3a_pile_prep(): initialize stack control. -*/ -void -u3a_pile_prep(u3a_pile* pil_u, c3_w len_w) -{ - // frame size, in words - // - c3_w wor_w = (len_w + 3) >> 2; - c3_o nor_o = u3a_v1_is_north(u3R_v1); - - pil_u->mov_ws = (c3y == nor_o) ? -wor_w : wor_w; - pil_u->off_ws = (c3y == nor_o) ? 0 : -wor_w; - pil_u->top_p = u3R_v1->cap_p; - -#ifdef U3_MEMORY_DEBUG - pil_u->rod_u = u3R_v1; -#endif -} - -/* u3a_v1_wfree(): free storage. -*/ -void -u3a_v1_wfree(void* tox_v) -{ - _box_free(u3a_v1_botox(tox_v)); -} - -/* u3a_v1_wtrim(): trim storage. - - old_w - old length - len_w - new length -*/ -void -u3a_v1_wtrim(void* tox_v, c3_w old_w, c3_w len_w) -{ - c3_w* nov_w = tox_v; - - if ( (old_w > len_w) - && ((old_w - len_w) >= u3a_minimum) ) - { - u3a_box* box_u = u3a_v1_botox(nov_w); - c3_w* box_w = (void*)u3a_v1_botox(nov_w); - - c3_w* end_w = c3_align(nov_w + len_w + 1, /* +1 for trailing allocation size */ - u3C.balign_d, - 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(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 */ - - _box_attach(_box_make(end_w, bsz_w, 0)); /* free the unneeded space */ - - box_u->siz_w = asz_w; - box_w[asz_w - 1] = asz_w; - } -} - -/* u3a_v1_calloc(): allocate and zero-initialize array -*/ -void* -u3a_v1_calloc(size_t num_i, size_t len_i) -{ - size_t byt_i = num_i * len_i; - c3_w* out_w; - - u3_assert(byt_i / len_i == num_i); - out_w = u3a_v1_malloc(byt_i); - memset(out_w, 0, byt_i); - - return out_w; -} - -/* u3a_v1_malloc(): aligned storage measured in bytes. - - Internally pads allocations to 16-byte alignment independent of DWORD - alignment ensured for word sized allocations. - -*/ -void* -u3a_v1_malloc(size_t len_i) -{ - c3_w len_w = (c3_w)((len_i + 3) >> 2); - c3_w *ptr_w = _ca_walloc(len_w +1, 4, 1); /* +1 for word storing pad size */ - c3_w *out_w = c3_align(ptr_w + 1, 16, C3_ALGHI); - c3_w pad_w = u3a_v1_outa(out_w) - u3a_v1_outa(ptr_w); - - out_w[-1] = pad_w - 1; /* the size of the pad doesn't include the word storing the size (-1) */ - - c3_dessert(&out_w[len_w] /* alloced space after alignment is sufficient */ - <= &((c3_w*)u3a_v1_botox(ptr_w))[u3a_v1_botox(ptr_w)->siz_w]); - c3_dessert(pad_w <= 4 && pad_w > 0); - c3_dessert(&out_w[-1] > ptr_w); - - return out_w; -} - -/* u3a_v1_cellblock(): allocate a block of cells on the hat. - - XXX beware when we stop boxing cells and QWORD align references. Alignment - not guaranteed to be preserved after a call. -*/ -static c3_o -u3a_v1_cellblock(c3_w num_w) -{ - u3p(u3a_v1_fbox) fre_p; - c3_w i_w; - - if ( c3y == u3a_v1_is_north(u3R_v1) ) { - if ( u3R_v1->cap_p <= (u3R_v1->hat_p + (num_w * u3a_minimum) + (1 << u3a_v1_page)) ) { - return c3n; - } - else { - u3_post cel_p = u3R_v1->all.cel_p; - u3_post hat_p = u3R_v1->hat_p; - u3R_v1->hat_p += (num_w * u3a_minimum); - - for ( i_w = 0; i_w < num_w; i_w++) { - u3_post all_p = hat_p; - void* box_v = u3a_v1_into(all_p); - u3a_box* box_u = box_v; - c3_w* box_w = box_v; - - // hand inline of _box_make(u3a_v1_into(all_p), u3a_minimum, 1) - { - box_u->siz_w = u3a_minimum; - box_w[u3a_minimum - 1] = u3a_minimum; - box_u->use_w = 1; -#ifdef U3_MEMORY_DEBUG - box_u->cod_w = 0; - box_u->eus_w = 0; -#endif - } - hat_p += u3a_minimum; - - fre_p = u3of(u3a_v1_fbox, box_u); - u3to(u3a_v1_fbox, fre_p)->nex_p = cel_p; - cel_p = fre_p; - } - - u3R_v1->all.cel_p = cel_p; - } - } - else { - if ( (u3R_v1->cap_p + (num_w * u3a_minimum) + (1 << u3a_v1_page)) >= u3R_v1->hat_p ) { - return c3n; - } - else { - u3_post cel_p = u3R_v1->all.cel_p; - u3_post hat_p = u3R_v1->hat_p; - u3R_v1->hat_p -= (num_w * u3a_minimum); - - for ( i_w = 0; i_w < num_w; i_w++ ) { - u3_post all_p = (hat_p -= u3a_minimum); - void* box_v = u3a_v1_into(all_p); - u3a_box* box_u = box_v; - c3_w* box_w = box_v; - - // hand inline of _box_make(u3a_v1_into(all_p), u3a_minimum, 1); - { - box_u->siz_w = u3a_minimum; - box_w[u3a_minimum - 1] = u3a_minimum; - box_u->use_w = 1; -# ifdef U3_MEMORY_DEBUG - box_u->cod_w = 0; - box_u->eus_w = 0; -# endif - } - fre_p = u3of(u3a_v1_fbox, box_u); - u3to(u3a_v1_fbox, fre_p)->nex_p = cel_p; - cel_p = fre_p; - } - - u3R_v1->all.cel_p = cel_p; - } - } - _box_count(num_w * u3a_minimum); - return c3y; -} - -/* u3a_v1_celloc(): allocate a cell. - XXX beware when we stop boxing cells and QWORD align references -*/ -c3_w* -u3a_v1_celloc(void) -{ -#ifdef U3_CPU_DEBUG - u3R_v1->pro.cel_d++; -#endif - -#ifdef U3_MEMORY_DEBUG - if ( u3C.wag_w & u3o_debug_ram ) { - return u3a_v1_walloc(c3_wiseof(u3a_v1_cell)); - } -#endif - - u3p(u3a_v1_fbox) cel_p; - - if ( !(cel_p = u3R_v1->all.cel_p) ) { - if ( u3R_v1 == &(u3H->rod_u) ) { - // no cell allocator on home road - // - return u3a_v1_walloc(c3_wiseof(u3a_v1_cell)); - } - else { - if ( c3n == u3a_v1_cellblock(4096) ) { - return u3a_v1_walloc(c3_wiseof(u3a_v1_cell)); - } - cel_p = u3R_v1->all.cel_p; - } - } - - { - u3a_box* box_u = &(u3to(u3a_v1_fbox, cel_p)->box_u); - - - box_u->use_w = 1; - u3R_v1->all.cel_p = u3to(u3a_v1_fbox, cel_p)->nex_p; - - _box_count(-(u3a_minimum)); - - return u3a_boxto(box_u); - } -} - -/* u3a_v1_cfree(): free a cell. -*/ -void -u3a_v1_cfree(c3_w* cel_w) -{ -#ifdef U3_MEMORY_DEBUG - if ( u3C.wag_w & u3o_debug_ram ) { - return u3a_v1_wfree(cel_w); - } -#endif - - if ( u3R_v1 == &(u3H->rod_u) ) { - return u3a_v1_wfree(cel_w); - } - else { - u3a_box* box_u = u3a_v1_botox(cel_w); - u3p(u3a_v1_fbox) fre_p = u3of(u3a_v1_fbox, box_u); - - _box_count(u3a_minimum); - - u3to(u3a_v1_fbox, fre_p)->nex_p = u3R_v1->all.cel_p; - u3R_v1->all.cel_p = fre_p; - } -} - -/* u3a_v1_realloc(): aligned realloc in bytes. -*/ -void* -u3a_v1_realloc(void* lag_v, size_t len_i) -{ - if ( !lag_v ) { - return u3a_v1_malloc(len_i); - } - else { - c3_w len_w = (c3_w)((len_i + 3) >> 2); - c3_w* lag_w = lag_v; - c3_w pad_w = lag_w[-1]; - c3_w* org_w = lag_w - (pad_w + 1); - u3a_box* box_u = u3a_v1_botox((void *)org_w); - c3_w* old_w = lag_v; - c3_w tiz_w = c3_min(box_u->siz_w, len_w); - { - c3_w* new_w = u3a_v1_malloc(len_i); - c3_w i_w; - - for ( i_w = 0; i_w < tiz_w; i_w++ ) { - new_w[i_w] = old_w[i_w]; - } - u3a_v1_wfree(org_w); - return new_w; - } - } -} - -/* 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); -} - -/* _me_wash_north(): clean up mug slots after copy. -*/ -static void _me_wash_north(u3_noun dog); -static void -_me_wash_north_in(u3_noun som) -{ - if ( _(u3a_v1_is_cat(som)) ) return; - if ( !_(u3a_v1_north_is_junior(u3R_v1, som)) ) return; - - _me_wash_north(som); -} -static void -_me_wash_north(u3_noun dog) -{ - u3_assert(c3y == u3a_v1_is_dog(dog)); - // u3_assert(c3y == u3a_v1_north_is_junior(u3R_v1, dog)); - { - u3a_v1_noun* dog_u = u3a_v1_to_ptr(dog); - - if ( dog_u->mug_w == 0 ) return; - - dog_u->mug_w = 0; // power wash - // if ( dog_u->mug_w >> 31 ) { dog_u->mug_w = 0; } - - if ( _(u3a_v1_is_pom(dog)) ) { - u3a_v1_cell* god_u = (u3a_v1_cell *)(void *)dog_u; - - _me_wash_north_in(god_u->hed); - _me_wash_north_in(god_u->tel); - } - } -} - -/* _me_wash_south(): clean up mug slots after copy. -*/ -static void _me_wash_south(u3_noun dog); -static void -_me_wash_south_in(u3_noun som) -{ - if ( _(u3a_v1_is_cat(som)) ) return; - if ( !_(u3a_v1_south_is_junior(u3R_v1, som)) ) return; - - _me_wash_south(som); -} -static void -_me_wash_south(u3_noun dog) -{ - u3_assert(c3y == u3a_v1_is_dog(dog)); - // u3_assert(c3y == u3a_v1_south_is_junior(u3R_v1, dog)); - { - u3a_v1_noun* dog_u = u3a_v1_to_ptr(dog); - - if ( dog_u->mug_w == 0 ) return; - - dog_u->mug_w = 0; // power wash - // if ( dog_u->mug_w >> 31 ) { dog_u->mug_w = 0; } - - if ( _(u3a_v1_is_pom(dog)) ) { - u3a_v1_cell* god_u = (u3a_v1_cell *)(void *)dog_u; - - _me_wash_south_in(god_u->hed); - _me_wash_south_in(god_u->tel); - } - } -} - -/* u3a_v1_wash(): wash all lazy mugs. RETAIN. -*/ -void -u3a_v1_wash(u3_noun som) -{ - if ( _(u3a_v1_is_cat(som)) ) { - return; - } - if ( _(u3a_v1_is_north(u3R_v1)) ) { - if ( _(u3a_v1_north_is_junior(u3R_v1, som)) ) { - _me_wash_north(som); - } - } - else { - if ( _(u3a_v1_south_is_junior(u3R_v1, som)) ) { - _me_wash_south(som); - } - } -} - -/* _me_gain_use(): increment use count. -*/ -static void -_me_gain_use(u3_noun dog) -{ - c3_w* dog_w = u3a_v1_to_ptr(dog); - u3a_box* box_u = u3a_v1_botox(dog_w); - - if ( 0x7fffffff == box_u->use_w ) { - u3l_log("fail in _me_gain_use"); - u3m_bail(c3__fail); - } - else { - if ( box_u->use_w == 0 ) { - u3m_bail(c3__foul); - } - box_u->use_w += 1; - -#ifdef U3_MEMORY_DEBUG - // enable to (maybe) help track down leaks - // - // if ( u3_Code && !box_u->cod_w ) { box_u->cod_w = u3_Code; } -#endif - } -} - -#undef VERBOSE_TAKE - -/* _ca_take_atom(): reallocate an indirect atom off the stack. -*/ -static inline u3_atom -_ca_take_atom(u3a_v1_atom* old_u) -{ - c3_w* new_w = u3a_v1_walloc(old_u->len_w + c3_wiseof(u3a_v1_atom)); - u3a_v1_atom* new_u = (u3a_v1_atom*)(void *)new_w; - u3_noun new = u3a_v1_to_pug(u3a_v1_outa(new_u)); - -#ifdef VERBOSE_TAKE - u3l_log("%s: atom %p to %p", ( c3y == u3a_v1_is_north(u3R_v1) ) - ? "north" - : "south", - old_u, - new_u); -#endif - - // XX use memcpy? - // - new_u->mug_w = old_u->mug_w; - new_u->len_w = old_u->len_w; - { - c3_w i_w; - - for ( i_w=0; i_w < old_u->len_w; i_w++ ) { - new_u->buf_w[i_w] = old_u->buf_w[i_w]; - } - } - - // borrow mug slot to record new destination in [old_u] - // - old_u->mug_w = new; - - return new; -} - -/* _ca_take_cell(): reallocate a cell off the stack. -*/ -static inline u3_cell -_ca_take_cell(u3a_v1_cell* old_u, u3_noun hed, u3_noun tel) -{ - // XX use u3a_v1_celloc? - // - c3_w* new_w = u3a_v1_walloc(c3_wiseof(u3a_v1_cell)); - u3a_v1_cell* new_u = (u3a_v1_cell*)(void *)new_w; - u3_cell new = u3a_v1_to_pom(u3a_v1_outa(new_u)); - -#ifdef VERBOSE_TAKE - u3l_log("%s: cell %p to %p", ( c3y == u3a_v1_is_north(u3R_v1) ) - ? "north" - : "south", - old_u, - new_u); -#endif - - new_u->mug_w = old_u->mug_w; - new_u->hed = hed; - new_u->tel = tel; - - // borrow mug slot to record new destination in [old_u] - // - old_u->mug_w = new; - - return new; -} - -/* _ca_take: stack frame for recording cell travesal -** (u3_none == hed) == head-frame -*/ -typedef struct _ca_take -{ - u3_weak hed; // taken head - u3_cell old; // old cell -} _ca_take; - -/* _ca_take_next_south: take next noun, pushing cells on stack. -*/ -static inline u3_noun -_ca_take_next_north(u3a_pile* pil_u, u3_noun veb) -{ - while ( 1 ) { - // direct atoms and senior refs are not counted. - // - if ( (c3y == u3a_v1_is_cat(veb)) - || (c3y == u3a_v1_north_is_senior(u3R_v1, veb)) ) - { - return veb; - } - // not junior; normal (heap) refs on our road are counted. - // - else if ( c3n == u3a_v1_north_is_junior(u3R_v1, veb) ) { - _me_gain_use(veb); // bypass branches in u3k() - return veb; - } - // junior (stack) refs are copied. - // - else { - u3a_v1_noun* veb_u = u3a_v1_to_ptr(veb); - - // 32-bit mug_w: already copied [veb] and [mug_w] is the new ref. - // - if ( veb_u->mug_w >> 31 ) { - u3_noun nov = (u3_noun)veb_u->mug_w; - - u3_assert( c3y == u3a_v1_north_is_normal(u3R_v1, nov) ); - -#ifdef VERBOSE_TAKE - u3l_log("north: %p is already %p", veb_u, u3a_v1_to_ptr(nov)); -#endif - - _me_gain_use(nov); // bypass branches in u3k() - return nov; - } - else if ( c3y == u3a_v1_is_atom(veb) ) { - return _ca_take_atom((u3a_v1_atom*)veb_u); - } - else { - u3a_v1_cell* old_u = (u3a_v1_cell*)veb_u; - _ca_take* fam_u = u3a_v1_push(pil_u); - - fam_u->hed = u3_none; - fam_u->old = veb; - - veb = old_u->hed; - continue; - } - } - } -} - -/* _ca_take_next_south: take next noun, pushing cells on stack. -*/ -static inline u3_noun -_ca_take_next_south(u3a_pile* pil_u, u3_noun veb) -{ - while ( 1 ) { - // direct atoms and senior refs are not counted. - // - if ( (c3y == u3a_v1_is_cat(veb)) - || (c3y == u3a_v1_south_is_senior(u3R_v1, veb)) ) - { - return veb; - } - // not junior; a normal pointer in our road -- refcounted - // - else if ( c3n == u3a_v1_south_is_junior(u3R_v1, veb) ) { - _me_gain_use(veb); // bypass branches in u3k() - return veb; - } - // junior (stack) refs are copied. - // - else { - u3a_v1_noun* veb_u = u3a_v1_to_ptr(veb); - - // 32-bit mug_w: already copied [veb] and [mug_w] is the new ref. - // - if ( veb_u->mug_w >> 31 ) { - u3_noun nov = (u3_noun)veb_u->mug_w; - - u3_assert( c3y == u3a_v1_south_is_normal(u3R_v1, nov) ); - -#ifdef VERBOSE_TAKE - u3l_log("south: %p is already %p", veb_u, u3a_v1_to_ptr(nov)); -#endif - - _me_gain_use(nov); // bypass branches in u3k() - return nov; - } - else if ( c3y == u3a_v1_is_atom(veb) ) { - return _ca_take_atom((u3a_v1_atom*)veb_u); - } - else { - u3a_v1_cell* old_u = (u3a_v1_cell*)veb_u; - _ca_take* fam_u = u3a_v1_push(pil_u); - - fam_u->hed = u3_none; - fam_u->old = veb; - - veb = old_u->hed; - continue; - } - } - } -} - -/* _ca_take_north(): in a north road, gain, copying juniors (from stack). -*/ -static u3_noun -_ca_take_north(u3_noun veb) -{ - u3_noun pro; - _ca_take* fam_u; - u3a_pile pil_u; - u3a_pile_prep(&pil_u, sizeof(*fam_u)); - - // commence taking - // - pro = _ca_take_next_north(&pil_u, veb); - - // process cell results - // - if ( c3n == u3a_pile_done(&pil_u) ) { - fam_u = u3a_v1_peek(&pil_u); - - do { - // head-frame: stash copy and continue into the tail - // - if ( u3_none == fam_u->hed ) { - u3a_v1_cell* old_u = u3a_v1_to_ptr(fam_u->old); - fam_u->hed = pro; - pro = _ca_take_next_north(&pil_u, old_u->tel); - fam_u = u3a_v1_peek(&pil_u); - } - // tail-frame: copy cell and pop the stack - // - else { - u3a_v1_cell* old_u = u3a_v1_to_ptr(fam_u->old); - pro = _ca_take_cell(old_u, fam_u->hed, pro); - fam_u = u3a_v1_pop(&pil_u); - } - } while ( c3n == u3a_pile_done(&pil_u) ); - } - - return pro; -} -/* _ca_take_south(): in a south road, gain, copying juniors (from stack). -*/ -static u3_noun -_ca_take_south(u3_noun veb) -{ - u3_noun pro; - _ca_take* fam_u; - u3a_pile pil_u; - u3a_pile_prep(&pil_u, sizeof(*fam_u)); - - // commence taking - // - pro = _ca_take_next_south(&pil_u, veb); - - // process cell results - // - if ( c3n == u3a_pile_done(&pil_u) ) { - fam_u = u3a_v1_peek(&pil_u); - - do { - // head-frame: stash copy and continue into the tail - // - if ( u3_none == fam_u->hed ) { - u3a_v1_cell* old_u = u3a_v1_to_ptr(fam_u->old); - fam_u->hed = pro; - pro = _ca_take_next_south(&pil_u, old_u->tel); - fam_u = u3a_v1_peek(&pil_u); - } - // tail-frame: copy cell and pop the stack - // - else { - u3a_v1_cell* old_u = u3a_v1_to_ptr(fam_u->old); - pro = _ca_take_cell(old_u, fam_u->hed, pro); - fam_u = u3a_v1_pop(&pil_u); - } - } while ( c3n == u3a_pile_done(&pil_u) ); - } - - return pro; -} - -/* u3a_v1_left(): true of junior if preserved. -*/ -c3_o -u3a_v1_left(u3_noun som) -{ - if ( _(u3a_v1_is_cat(som)) || - !_(u3a_v1_is_junior(u3R_v1, som)) ) - { - return c3y; - } - else { - u3a_v1_noun* dog_u = u3a_v1_to_ptr(som); - - return __(0 != (dog_u->mug_w >> 31)); - } -} - -/* _me_gain_north(): gain on a north road. -*/ -static u3_noun -_me_gain_north(u3_noun dog) -{ - if ( c3y == u3a_v1_north_is_senior(u3R_v1, dog) ) { - /* senior pointers are not refcounted - */ - return dog; - } - else { - /* junior nouns are disallowed - */ - u3_assert(!_(u3a_v1_north_is_junior(u3R_v1, dog))); - - /* normal pointers are refcounted - */ - _me_gain_use(dog); - return dog; - } -} - -/* _me_gain_south(): gain on a south road. -*/ -static u3_noun -_me_gain_south(u3_noun dog) -{ - if ( c3y == u3a_v1_south_is_senior(u3R_v1, dog) ) { - /* senior pointers are not refcounted - */ - return dog; - } - else { - /* junior nouns are disallowed - */ - u3_assert(!_(u3a_v1_south_is_junior(u3R_v1, dog))); - - /* normal nouns are refcounted - */ - _me_gain_use(dog); - return dog; - } -} - -/* _me_lose_north(): lose on a north road. -*/ -static void -_me_lose_north(u3_noun dog) -{ -top: - if ( c3y == u3a_v1_north_is_normal(u3R_v1, dog) ) { - c3_w* dog_w = u3a_v1_to_ptr(dog); - u3a_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_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_cfree(dog_w); - if ( !_(u3a_v1_is_cat(t_dog)) ) { - dog = t_dog; - goto top; - } - } - else { - u3a_v1_wfree(dog_w); - } - } - } - } -} - -/* _me_lose_south(): lose on a south road. -*/ -static void -_me_lose_south(u3_noun dog) -{ -top: - if ( c3y == u3a_v1_south_is_normal(u3R_v1, dog) ) { - c3_w* dog_w = u3a_v1_to_ptr(dog); - u3a_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_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_south(h_dog); - } - u3a_v1_cfree(dog_w); - if ( !_(u3a_v1_is_cat(t_dog)) ) { - dog = t_dog; - goto top; - } - } - else { - u3a_v1_wfree(dog_w); - } - } - } - } -} - -/* u3a_v1_gain(): gain a reference count in normal space. -*/ -u3_noun -u3a_v1_gain(u3_noun som) -{ - u3t_on(mal_o); - u3_assert(u3_none != som); - - if ( !_(u3a_v1_is_cat(som)) ) { - som = _(u3a_v1_is_north(u3R_v1)) - ? _me_gain_north(som) - : _me_gain_south(som); - } - u3t_off(mal_o); - - return som; -} - -/* u3a_v1_lose(): lose a reference count. -*/ -void -u3a_v1_lose(u3_noun som) -{ - u3t_on(mal_o); - if ( !_(u3a_v1_is_cat(som)) ) { - if ( _(u3a_v1_is_north(u3R_v1)) ) { - _me_lose_north(som); - } else { - _me_lose_south(som); - } - } - u3t_off(mal_o); -} - -/* u3a_v1_use(): reference count. -*/ -c3_w -u3a_v1_use(u3_noun som) -{ - if ( _(u3a_v1_is_cat(som)) ) { - return 1; - } - else { - c3_w* dog_w = u3a_v1_to_ptr(som); - u3a_box* box_u = u3a_v1_botox(dog_w); - - return box_u->use_w; - } -} - -/* _ca_wed_who(): unify [a] and [b] on [rod_u], keeping the senior -** -** NB: this leaks a reference when it unifies in a senior road -*/ -static c3_o -_ca_wed_who(u3a_v1_road* rod_u, u3_noun* a, u3_noun* b) -{ - c3_t asr_t = ( c3y == u3a_v1_is_senior(rod_u, *a) ); - c3_t bsr_t = ( c3y == u3a_v1_is_senior(rod_u, *b) ); - c3_t nor_t = ( c3y == u3a_v1_is_north(rod_u) ); - c3_t own_t = ( rod_u == u3R_v1 ); - - // both are on [rod_u]; gain a reference to whichever we keep - // - if ( !asr_t && !bsr_t ) { - // keep [a]; it's deeper in the heap - // - // (N && >) || (S && <) - // - if ( (*a > *b) == nor_t ) { - _me_gain_use(*a); - if ( own_t ) { u3z(*b); } - *b = *a; - } - // keep [b]; it's deeper in the heap - // - else { - _me_gain_use(*b); - if ( own_t ) { u3z(*a); } - *a = *b; - } - - return c3y; - } - // keep [a]; it's senior - // - else if ( asr_t && !bsr_t ) { - if ( own_t ) { u3z(*b); } - *b = *a; - return c3y; - } - // keep [b]; it's senior - // - else if ( !asr_t && bsr_t ) { - if ( own_t ) { u3z(*a); } - *a = *b; - return c3y; - } - - // both [a] and [b] are senior; we can't unify on [rod_u] - // - return c3n; -} - -/* u3a_v1_wed(): unify noun references. -*/ -void -u3a_v1_wed(u3_noun* a, u3_noun* b) -{ - if ( *a != *b ) { - u3_v1_road* rod_u = u3R_v1; - - // while not at home, attempt to unify - // - // we try to unify on our road, and retry on senior roads - // until we succeed or reach the home road. - // - // we can't perform this kind of butchery on the home road, - // where asynchronous things can allocate. - // (XX anything besides u3t_samp?) - // - // when unifying on a higher road, we can't free nouns, - // because we can't track junior nouns that point into - // that road. - // - // this is just an implementation issue -- we could set use - // counts to 0 without actually freeing. but the allocator - // would have to be actually designed for this. - // (alternately, we could keep a deferred free-list) - // - // not freeing may generate spurious leaks, so we disable - // senior unification when debugging memory. this will - // cause a very slow boot process as the compiler compiles - // itself, constantly running into duplicates. - // - while ( (rod_u != &u3H->rod_u) && - (c3n == _ca_wed_who(rod_u, a, b)) ) - { -#ifdef U3_MEMORY_DEBUG - break; -#else - rod_u = u3to(u3_v1_road, rod_u->par_p); -#endif - } - } -} - -/* u3a_v1_luse(): check refcount sanity. -*/ -void -u3a_v1_luse(u3_noun som) -{ - if ( 0 == u3a_v1_use(som) ) { - fprintf(stderr, "loom: insane %d 0x%x\r\n", som, som); - abort(); - } - if ( _(u3du(som)) ) { - u3a_v1_luse(u3h(som)); - u3a_v1_luse(u3t(som)); - } -} - -/* u3a_v1_mark_ptr(): mark a pointer for gc. Produce size if first mark. -*/ -c3_w -u3a_v1_mark_ptr(void* ptr_v) -{ - if ( _(u3a_v1_is_north(u3R_v1)) ) { - if ( !((ptr_v >= u3a_v1_into(u3R_v1->rut_p)) && - (ptr_v < u3a_v1_into(u3R_v1->hat_p))) ) - { - return 0; - } - } - else { - if ( !((ptr_v >= u3a_v1_into(u3R_v1->hat_p)) && - (ptr_v < u3a_v1_into(u3R_v1->rut_p))) ) - { - return 0; - } - } - { - u3a_box* box_u = u3a_v1_botox(ptr_v); - c3_w siz_w; - -#ifdef U3_MEMORY_DEBUG - if ( 0 == box_u->eus_w ) { - siz_w = box_u->siz_w; - } - else if ( 0xffffffff == box_u->eus_w ) { // see u3a_v1_prof() - siz_w = 0xffffffff; - box_u->eus_w = 0; - } - else { - siz_w = 0; - } - box_u->eus_w += 1; -#else - c3_ws use_ws = (c3_ws)box_u->use_w; - - if ( use_ws == 0 ) { - fprintf(stderr, "%p is bogus\r\n", ptr_v); - siz_w = 0; - } - else { - u3_assert(use_ws != 0); - - if ( 0x80000000 == (c3_w)use_ws ) { // see u3a_v1_prof() - use_ws = -1; - siz_w = 0xffffffff; - } - else if ( use_ws < 0 ) { - use_ws -= 1; - siz_w = 0; - } - else { - use_ws = -1; - siz_w = box_u->siz_w; - } - box_u->use_w = (c3_w)use_ws; - } -#endif - return siz_w; - } -} - -u3_post -u3a_v1_rewritten(u3_post ptr_v) +/* u3a_v1_reclaim(): clear ad-hoc persistent caches to reclaim memory. +*/ +void +u3a_v1_reclaim(void) { - u3a_box* box_u = u3a_v1_botox(u3a_v1_into(ptr_v)); - c3_w* box_w = (c3_w*) box_u; - return (u3_post)box_w[box_u->siz_w - 1]; + // clear the memoization cache + // + u3h_free(u3R->cax.har_p); + u3R->cax.har_p = u3h_new(); } u3_noun u3a_v1_rewritten_noun(u3_noun som) { - if ( c3y == u3a_v1_is_cat(som) ) { + if ( c3y == u3a_is_cat(som) ) { return som; } u3_post som_p = u3a_v1_rewritten(u3a_v1_to_off(som)); - if ( c3y == u3a_v1_is_pug(som) ) { - som_p = u3a_v2_to_pug(som_p); // XX alias? + if ( c3y == u3a_is_pug(som) ) { + som_p = u3a_v1_to_pug(som_p); // XX alias? } else { - som_p = u3a_v2_to_pom(som_p); + som_p = u3a_v1_to_pom(som_p); } return som_p; } -/* u3a_v1_mark_mptr(): mark a malloc-allocated ptr for gc. -*/ -c3_w -u3a_v1_mark_mptr(void* ptr_v) -{ - c3_w* ptr_w = ptr_v; - c3_w pad_w = ptr_w[-1]; - c3_w* org_w = ptr_w - (pad_w + 1); - - return u3a_v1_mark_ptr(org_w); -} - -/* u3a_v1_mark_noun(): mark a noun for gc. Produce size. -*/ -c3_w -u3a_v1_mark_noun(u3_noun som) -{ - c3_w siz_w = 0; - - while ( 1 ) { - if ( _(u3a_v1_is_senior(u3R_v1, som)) ) { - return siz_w; - } - else { - c3_w* dog_w = u3a_v1_to_ptr(som); - c3_w new_w = u3a_v1_mark_ptr(dog_w); - - if ( 0 == new_w || 0xffffffff == new_w ) { // see u3a_v1_mark_ptr() - return siz_w; - } - else { - siz_w += new_w; - if ( _(u3du(som)) ) { - siz_w += u3a_v1_mark_noun(u3h(som)); - som = u3t(som); - } - else return siz_w; - } - } - } -} - -/* u3a_v1_count_noun(): count size of pointer. -*/ -c3_w -u3a_v1_count_ptr(void* ptr_v) -{ - if ( _(u3a_v1_is_north(u3R_v1)) ) { - if ( !((ptr_v >= u3a_v1_into(u3R_v1->rut_p)) && - (ptr_v < u3a_v1_into(u3R_v1->hat_p))) ) - { - return 0; - } - } - else { - if ( !((ptr_v >= u3a_v1_into(u3R_v1->hat_p)) && - (ptr_v < u3a_v1_into(u3R_v1->rut_p))) ) - { - return 0; - } - } - { - u3a_box* box_u = u3a_v1_botox(ptr_v); - c3_w siz_w; - - c3_ws use_ws = (c3_ws)box_u->use_w; - - if ( use_ws == 0 ) { - fprintf(stderr, "%p is bogus\r\n", ptr_v); - siz_w = 0; - } - else { - u3_assert(use_ws != 0); - - if ( use_ws < 0 ) { - siz_w = 0; - } - else { - use_ws = -use_ws; - siz_w = box_u->siz_w; - } - box_u->use_w = (c3_w)use_ws; - } - return siz_w; - } -} - -/* u3a_v1_count_noun(): count size of noun. -*/ -c3_w -u3a_v1_count_noun(u3_noun som) -{ - c3_w siz_w = 0; - - while ( 1 ) { - if ( _(u3a_v1_is_senior(u3R_v1, som)) ) { - return siz_w; - } - else { - c3_w* dog_w = u3a_v1_to_ptr(som); - c3_w new_w = u3a_v1_count_ptr(dog_w); - - if ( 0 == new_w ) { - return siz_w; - } - else { - siz_w += new_w; - if ( _(u3du(som)) ) { - siz_w += u3a_v1_count_noun(u3h(som)); - som = u3t(som); - } - else return siz_w; - } - } - } -} - -/* u3a_v1_discount_ptr(): clean up after counting a pointer. -*/ -c3_w -u3a_v1_discount_ptr(void* ptr_v) -{ - if ( _(u3a_v1_is_north(u3R_v1)) ) { - if ( !((ptr_v >= u3a_v1_into(u3R_v1->rut_p)) && - (ptr_v < u3a_v1_into(u3R_v1->hat_p))) ) - { - return 0; - } - } - else { - if ( !((ptr_v >= u3a_v1_into(u3R_v1->hat_p)) && - (ptr_v < u3a_v1_into(u3R_v1->rut_p))) ) - { - return 0; - } - } - u3a_box* box_u = u3a_v1_botox(ptr_v); - c3_w siz_w; - - c3_ws use_ws = (c3_ws)box_u->use_w; - - if ( use_ws == 0 ) { - fprintf(stderr, "%p is bogus\r\n", ptr_v); - siz_w = 0; - } - else { - u3_assert(use_ws != 0); - - if ( use_ws < 0 ) { - use_ws = -use_ws; - siz_w = box_u->siz_w; - } - else { - siz_w = 0; - } - box_u->use_w = (c3_w)use_ws; - } - - return siz_w; -} - -/* u3a_v1_discount_noun(): clean up after counting a noun. -*/ -c3_w -u3a_v1_discount_noun(u3_noun som) -{ - c3_w siz_w = 0; - - while ( 1 ) { - if ( _(u3a_v1_is_senior(u3R_v1, som)) ) { - return siz_w; - } - else { - c3_w* dog_w = u3a_v1_to_ptr(som); - c3_w new_w = u3a_v1_discount_ptr(dog_w); - - if ( 0 == new_w ) { - return siz_w; - } - else { - siz_w += new_w; - if ( _(u3du(som)) ) { - siz_w += u3a_v1_discount_noun(u3h(som)); - som = u3t(som); - } - else return siz_w; - } - } - } -} - -/* u3a_v1_print_time: print microsecond time. -*/ -void -u3a_v1_print_time(c3_c* str_c, c3_c* cap_c, c3_d mic_d) -{ - u3_assert( 0 != str_c ); - - c3_w sec_w = (mic_d / 1000000); - c3_w mec_w = (mic_d % 1000000) / 1000; - c3_w mic_w = (mic_d % 1000); - - if ( sec_w ) { - sprintf(str_c, "%s s/%d.%03d.%03d", cap_c, sec_w, mec_w, mic_w); - } - else if ( mec_w ) { - sprintf(str_c, "%s ms/%d.%03d", cap_c, mec_w, mic_w); - } - else { - sprintf(str_c, "%s \xc2\xb5s/%d", cap_c, mic_w); - } -} - -/* u3a_v1_print_memory: print memory amount. -*/ -void -u3a_v1_print_memory(FILE* fil_u, c3_c* cap_c, c3_w wor_w) -{ - u3_assert( 0 != fil_u ); - - c3_z byt_z = ((c3_z)wor_w * 4); - c3_z gib_z = (byt_z / 1000000000); - c3_z mib_z = (byt_z % 1000000000) / 1000000; - c3_z kib_z = (byt_z % 1000000) / 1000; - c3_z bib_z = (byt_z % 1000); - - if ( byt_z ) { - if ( gib_z ) { - fprintf(fil_u, "%s: GB/%" PRIc3_z ".%03" PRIc3_z ".%03" PRIc3_z ".%03" PRIc3_z "\r\n", - cap_c, gib_z, mib_z, kib_z, bib_z); - } - else if ( mib_z ) { - fprintf(fil_u, "%s: MB/%" PRIc3_z ".%03" PRIc3_z ".%03" PRIc3_z "\r\n", - cap_c, mib_z, kib_z, bib_z); - } - else if ( kib_z ) { - fprintf(fil_u, "%s: KB/%" PRIc3_z ".%03" PRIc3_z "\r\n", - cap_c, kib_z, bib_z); - } - else if ( bib_z ) { - fprintf(fil_u, "%s: B/%" PRIc3_z "\r\n", - cap_c, bib_z); - } - } -} - -/* u3a_v1_maid(): maybe print memory. -*/ -c3_w -u3a_v1_maid(FILE* fil_u, c3_c* cap_c, c3_w wor_w) -{ - if ( 0 != fil_u ) { - u3a_v1_print_memory(fil_u, cap_c, wor_w); - } - return wor_w; -} - -/* _ca_print_memory(): un-captioned u3a_v1_print_memory(). -*/ -static void -_ca_print_memory(FILE* fil_u, c3_w wor_w) -{ - c3_w byt_w = (wor_w * 4); - c3_w gib_w = (byt_w / 1000000000); - c3_w mib_w = (byt_w % 1000000000) / 1000000; - c3_w kib_w = (byt_w % 1000000) / 1000; - c3_w bib_w = (byt_w % 1000); - - if ( gib_w ) { - fprintf(fil_u, "GB/%d.%03d.%03d.%03d\r\n", - gib_w, mib_w, kib_w, bib_w); - } - else if ( mib_w ) { - fprintf(fil_u, "MB/%d.%03d.%03d\r\n", mib_w, kib_w, bib_w); - } - else if ( kib_w ) { - fprintf(fil_u, "KB/%d.%03d\r\n", kib_w, bib_w); - } - else { - fprintf(fil_u, "B/%d\r\n", bib_w); - } -} - -/* u3a_v1_prof(): mark/measure/print memory profile. RETAIN. -*/ -c3_w -u3a_v1_prof(FILE* fil_u, c3_w den_w, u3_noun mas) -{ - c3_w tot_w = 0; - u3_noun h_mas, t_mas; - - if ( c3n == u3r_cell(mas, &h_mas, &t_mas) ) { - fprintf(fil_u, "%.*smistyped mass\r\n", den_w, ""); - return tot_w; - } - else if ( _(u3du(h_mas)) ) { - fprintf(fil_u, "%.*smistyped mass head\r\n", den_w, ""); - { - c3_c* lab_c = u3m_pretty(h_mas); - fprintf(fil_u, "h_mas: %s", lab_c); - c3_free(lab_c); - } - return tot_w; - } - else { - { - c3_c* lab_c = u3m_pretty(h_mas); - fprintf(fil_u, "%*s%s: ", den_w, "", lab_c); - c3_free(lab_c); - } - - u3_noun it_mas, tt_mas; - - if ( c3n == u3r_cell(t_mas, &it_mas, &tt_mas) ) { - fprintf(fil_u, "%*smistyped mass tail\r\n", den_w, ""); - return tot_w; - } - else if ( c3y == it_mas ) { - tot_w += u3a_v1_mark_noun(tt_mas); - _ca_print_memory(fil_u, tot_w); - -#if 1 - /* The basic issue here is that tt_mas is included in .sac - * (the whole profile), so they can't both be roots in the - * normal sense. When we mark .sac later on, we want tt_mas - * to appear unmarked, but its children should be already - * marked. - * - * see u3a_v1_mark_ptr(). - */ - if ( _(u3a_v1_is_dog(tt_mas)) ) { - u3a_box* box_u = u3a_v1_botox(u3a_v1_to_ptr(tt_mas)); -#ifdef U3_MEMORY_DEBUG - if ( 1 == box_u->eus_w ) { - box_u->eus_w = 0xffffffff; - } - else { - box_u->eus_w -= 1; - } -#else - if ( -1 == (c3_w)box_u->use_w ) { - box_u->use_w = 0x80000000; - } - else { - box_u->use_w += 1; - } -#endif - } -#endif - - return tot_w; - } - else if ( c3n == it_mas ) { - fprintf(fil_u, "\r\n"); - - while ( _(u3du(tt_mas)) ) { - tot_w += u3a_v1_prof(fil_u, den_w+2, u3h(tt_mas)); - tt_mas = u3t(tt_mas); - } - - fprintf(fil_u, "%*s--", den_w, ""); - _ca_print_memory(fil_u, tot_w); - - return tot_w; - - } - else { - fprintf(fil_u, "%*smistyped (strange) mass tail\r\n", den_w, ""); - return tot_w; - } - } -} - -/* u3a_v1_mark_road(): mark ad-hoc persistent road structures. -*/ -c3_w -u3a_v1_mark_road(FILE* fil_u) -{ - c3_w tot_w = 0; - tot_w += u3a_v1_maid(fil_u, " namespace", u3a_v1_mark_noun(u3R_v1->ski.gul)); - tot_w += u3a_v1_maid(fil_u, " trace stack", u3a_v1_mark_noun(u3R_v1->bug.tax)); - tot_w += u3a_v1_maid(fil_u, " trace buffer", u3a_v1_mark_noun(u3R_v1->bug.mer)); - tot_w += u3a_v1_maid(fil_u, " profile batteries", u3a_v1_mark_noun(u3R_v1->pro.don)); - tot_w += u3a_v1_maid(fil_u, " profile doss", u3a_v1_mark_noun(u3R_v1->pro.day)); - tot_w += u3a_v1_maid(fil_u, " new profile trace", u3a_v1_mark_noun(u3R_v1->pro.trace)); - tot_w += u3a_v1_maid(fil_u, " memoization cache", u3h_mark(u3R_v1->cax.har_p)); - return u3a_v1_maid(fil_u, "total road stuff", tot_w); -} - -/* u3a_v1_reclaim(): clear ad-hoc persistent caches to reclaim memory. -*/ -void -u3a_v1_reclaim(void) -{ - // clear the memoization cache - // - u3h_free(u3R_v1->cax.har_p); - u3R_v1->cax.har_p = u3h_new(); -} - /* u3a_v1_rewrite_compact(): rewrite pointers in ad-hoc persistent road structures. * XX need to version */ @@ -2080,404 +47,32 @@ void // u3a_v1_rewrite_compact(u3a_v1_road *rod_u) u3a_v1_rewrite_compact(void) { - u3a_v1_rewrite_noun(u3R_v1->ski.gul); - u3a_v1_rewrite_noun(u3R_v1->bug.tax); - u3a_v1_rewrite_noun(u3R_v1->bug.mer); - u3a_v1_rewrite_noun(u3R_v1->pro.don); - u3a_v1_rewrite_noun(u3R_v1->pro.day); - u3a_v1_rewrite_noun(u3R_v1->pro.trace); - u3h_rewrite(u3R_v1->cax.har_p); - - u3R_v1->ski.gul = u3a_v1_rewritten_noun(u3R_v1->ski.gul); - u3R_v1->bug.tax = u3a_v1_rewritten_noun(u3R_v1->bug.tax); - u3R_v1->bug.mer = u3a_v1_rewritten_noun(u3R_v1->bug.mer); - u3R_v1->pro.don = u3a_v1_rewritten_noun(u3R_v1->pro.don); - u3R_v1->pro.day = u3a_v1_rewritten_noun(u3R_v1->pro.day); - u3R_v1->pro.trace = u3a_v1_rewritten_noun(u3R_v1->pro.trace); - u3R_v1->cax.har_p = u3a_v1_rewritten(u3R_v1->cax.har_p); -} - -/* _ca_print_box(): heuristically print the contents of an allocation box. -*/ -static c3_c* -_ca_print_box(u3a_box* box_u) -{ - // the loom offset pointing to the contents of box_u - // - c3_w box_w = u3a_v1_outa(u3a_boxto(box_u)); - // box_u might not be a cell, we use the struct to inspect further - // - u3a_v1_cell* cel_u = (u3a_v1_cell*)box_u; - - if ( // a cell will never be bigger than the minimum allocation size - // - (u3a_minimum < box_u->siz_w) || - // this condition being true potentially corresponds to - // box_u containing an indirect atom of only one word. - // if the condition is false, we know box_u contains a cell. - // - ( (1 == (c3_w)cel_u->hed) && - (0x80000000 & (c3_w)cel_u->tel) ) ) - { - // box_u might not be an indirect atom, - // but it's always safe to print it as if it is one - // - u3a_v1_atom* vat_u = (u3a_v1_atom*)box_u; - u3_atom veb = u3a_v1_to_pug(box_w); - - // skip atoms larger than 10 words - // XX print mugs or something - // - if ( 10 > vat_u->len_w ) { -#if 0 - /* For those times when you've really just got to crack open - * the box and see what's inside - */ - { - int i; - for ( i = 0; i < box_u->siz_w; i++ ) { - fprintf(stderr, "%08x ", (unsigned int)(((c3_w*)box_u)[i])); - } - fprintf(stderr, "\r\n"); - } -#endif - return 0; - } - - return u3m_pretty(veb); - } - else { - // box_u is definitely a cell - // - return u3m_pretty(u3a_v1_to_pom(box_w)); - } -} - -/* _ca_print_leak(): print the details of a leaked allocation box. -*/ -#ifdef U3_MEMORY_DEBUG - -static void -_ca_print_leak(c3_c* cap_c, u3a_box* box_u, c3_w eus_w, c3_w use_w) -{ - fprintf(stderr, "%s: %p mug=%x (marked=%u swept=%u)\r\n", - cap_c, - box_u, - ((u3a_v1_noun *)(u3a_boxto(box_u)))->mug_w, - eus_w, - use_w); - - if ( box_u->cod_w ) { - c3_c* cod_c = u3m_pretty(box_u->cod_w); - fprintf(stderr, "code: %s\r\n", cod_c); - c3_free(cod_c); - } - - u3a_v1_print_memory(stderr, " size", box_u->siz_w); - - { - c3_c* dat_c = _ca_print_box(box_u); - fprintf(stderr, " data: %s\r\n", dat_c); - c3_free(dat_c); - } -} - -#else - -static void -_ca_print_leak(c3_c* cap_c, u3a_box* box_u, c3_ws use_ws) -{ - fprintf(stderr, "%s: %p mug=%x swept=%d\r\n", - cap_c, - box_u, - ((u3a_v1_noun *)(u3a_boxto(box_u)))->mug_w, - use_ws); - - u3a_v1_print_memory(stderr, " size", box_u->siz_w); - - { - c3_c* dat_c = _ca_print_box(box_u); - fprintf(stderr, " data: %s\r\n", dat_c); - c3_free(dat_c); - } -} - -#endif - -/* u3a_v1_idle(): measure free-lists in [rod_u] -*/ -c3_w -u3a_v1_idle(u3a_v1_road* rod_u) -{ - c3_w i_w, fre_w = 0; - - for ( i_w = 0; i_w < u3a_v1_fbox_no; i_w++ ) { - u3p(u3a_v1_fbox) fre_p = rod_u->all.fre_p[i_w]; - - while ( fre_p ) { - u3a_v1_fbox* fox_u = u3to(u3a_v1_fbox, fre_p); - - fre_w += fox_u->box_u.siz_w; - fre_p = fox_u->nex_p; - } - } - - return fre_w; -} - -/* u3a_v1_sweep(): sweep a fully marked road. -*/ -c3_w -u3a_v1_sweep(void) -{ - c3_w neg_w, pos_w, leq_w, weq_w; - - /* Measure allocated memory by counting the free list. - */ - { - c3_w end_w = u3a_v1_heap(u3R_v1); - c3_w fre_w = u3a_v1_idle(u3R_v1); - -#ifdef U3_CPU_DEBUG - if ( fre_w != u3R_v1->all.fre_w ) { - fprintf(stderr, "fre discrepancy (%x): %x, %x, %x\r\n", u3R_v1->par_p, - fre_w, u3R_v1->all.fre_w, (u3R_v1->all.fre_w - fre_w)); - } -#endif - neg_w = (end_w - fre_w); - } - - /* Sweep through the arena, repairing and counting leaks. - */ - pos_w = leq_w = weq_w = 0; - { - u3_post box_p = _(u3a_v1_is_north(u3R_v1)) ? u3R_v1->rut_p : u3R_v1->hat_p; - u3_post end_p = _(u3a_v1_is_north(u3R_v1)) ? u3R_v1->hat_p : u3R_v1->rut_p; - c3_w* box_w = u3a_v1_into(box_p); - c3_w* end_w = u3a_v1_into(end_p); - - while ( box_w < end_w ) { - u3a_box* box_u = (void *)box_w; - -#ifdef U3_MEMORY_DEBUG - /* I suspect these printfs fail hilariously in the case - * of non-direct atoms. We shouldn't unconditionally run - * u3a_v1_to_pom(). In general, the condition - * box_u->siz_w > u3a_minimum is sufficient, but not necessary, - * for the box to represent an atom. The atoms between - * 2^31 and 2^32 are the exceptions. - * - * Update: so, apparently u3.md is incorrect, and a pug is just - * an indirect atom. This code should be altered to handle - * that. - */ - if ( box_u->use_w != box_u->eus_w ) { - if ( box_u->eus_w != 0 ) { - if ( box_u->use_w == 0 ) { - _ca_print_leak("dank", box_u, box_u->eus_w, box_u->use_w); - } - else { - _ca_print_leak("weak", box_u, box_u->eus_w, box_u->use_w); - } - - weq_w += box_u->siz_w; - } - else { - _ca_print_leak("leak", box_u, box_u->eus_w, box_u->use_w); - - leq_w += box_u->siz_w; - } - - box_u->use_w = box_u->eus_w; - } - else { - if ( box_u->use_w ) { - pos_w += box_u->siz_w; - } - } - box_u->eus_w = 0; -#else - c3_ws use_ws = (c3_ws)box_u->use_w; - - if ( use_ws > 0 ) { - _ca_print_leak("leak", box_u, use_ws); - - leq_w += box_u->siz_w; - box_u->use_w = 0; - - _box_attach(box_u); - } - else if ( use_ws < 0 ) { - pos_w += box_u->siz_w; - box_u->use_w = (c3_w)(0 - use_ws); - } -#endif - box_w += box_u->siz_w; - } - } - -#ifdef U3_MEMORY_DEBUG - { - c3_w tot_w = u3a_v1_full(u3R_v1); - c3_w caf_w = u3a_v1_temp(u3R_v1); - -#ifdef U3_CPU_DEBUG - if ( (0 != u3R_v1->par_p) && (u3R_v1->all.max_w > 1000000) ) { - u3a_v1_print_memory(stderr, "available", (tot_w - pos_w)); - u3a_v1_print_memory(stderr, "allocated", pos_w); - u3a_v1_print_memory(stderr, "volatile", caf_w); - - u3a_v1_print_memory(stderr, "maximum", u3R_v1->all.max_w); - } -#endif - -#if 0 - u3a_v1_print_memory(stderr, "available", (tot_w - pos_w)); - u3a_v1_print_memory(stderr, "allocated", pos_w); - u3a_v1_print_memory(stderr, "volatile", caf_w); -#endif - } -#endif - - u3a_v1_print_memory(stderr, "leaked", leq_w); - u3a_v1_print_memory(stderr, "weaked", weq_w); - - u3_assert( (pos_w + leq_w + weq_w) == neg_w ); - u3_assert( (0 == leq_w) && (0 == weq_w) ); - - return neg_w; -} - -static u3_post -_ca_pack_move_north(c3_w* box_w, c3_w* end_w, u3_post new_p) -{ - u3a_box* old_u; - c3_w siz_w; - - // relocate allocation boxes - // - // new locations have been recorded in the trailing size word, - // and are recalculated and asserted to ensure sanity - // - while ( box_w < end_w ) { - old_u = (void *)box_w; - siz_w = old_u->siz_w; - - old_u->use_w &= 0x7fffffff; - - if ( old_u->use_w ) { - c3_w* new_w = (void*)u3a_v1_botox(u3a_v1_into(new_p)); - - u3_assert( box_w[siz_w - 1] == new_p ); - - // note: includes leading size - // - if ( 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]; - } - } - else { - u3_assert( new_w == box_w ); - } - - // restore trailing size - // - new_w[siz_w - 1] = siz_w; - - new_p += siz_w; - } - - box_w += siz_w; - } - - return new_p; -} - -// XX untested! -// -static u3_post -_ca_pack_move_south(c3_w* box_w, c3_w* end_w, u3_post new_p) -{ - u3a_box* old_u; - c3_w siz_w; - c3_o yuz_o; - - // offset initial addresses (point to the head of the first box) - // - siz_w = box_w[-1]; - box_w -= siz_w; - new_p -= siz_w; - - // relocate allocation boxes - // - // new locations have been recorded in the leading size word, - // and are recalculated and asserted to ensure sanity - // - while ( 1 ) { - old_u = (void *)box_w; - - old_u->use_w &= 0x7fffffff; - - if ( old_u->use_w ) { - c3_w* new_w = (void*)u3a_v1_botox(u3a_v1_into(new_p)); - - u3_assert( old_u->siz_w == new_p ); - - // note: includes trailing size - // - if ( new_w > box_w ) { - c3_w i_w; - - for ( i_w = 1; i_w < siz_w; i_w++ ) { - new_w[i_w] = box_w[i_w]; - } - } - else { - u3_assert( new_w == box_w ); - } - - // restore leading size - // - new_w[0] = siz_w; - - yuz_o = c3y; - } - else { - yuz_o = c3n; - } - - // move backwards only if there is more work to be done - // - if ( box_w > end_w ) { - siz_w = box_w[-1]; - box_w -= siz_w; - - if ( c3y == yuz_o ) { - new_p -= siz_w; - } - } - else { - u3_assert( end_w == box_w ); - break; - } - } + u3a_v1_rewrite_noun(u3R->ski.gul); + u3a_v1_rewrite_noun(u3R->bug.tax); + u3a_v1_rewrite_noun(u3R->bug.mer); + u3a_v1_rewrite_noun(u3R->pro.don); + u3a_v1_rewrite_noun(u3R->pro.day); + u3a_v1_rewrite_noun(u3R->pro.trace); + u3h_v1_rewrite(u3R->cax.har_p); - return new_p; + u3R->ski.gul = u3a_v1_rewritten_noun(u3R->ski.gul); + u3R->bug.tax = u3a_v1_rewritten_noun(u3R->bug.tax); + u3R->bug.mer = u3a_v1_rewritten_noun(u3R->bug.mer); + u3R->pro.don = u3a_v1_rewritten_noun(u3R->pro.don); + u3R->pro.day = u3a_v1_rewritten_noun(u3R->pro.day); + u3R->pro.trace = u3a_v1_rewritten_noun(u3R->pro.trace); + u3R->cax.har_p = u3a_v1_rewritten(u3R->cax.har_p); } - void u3a_v1_rewrite_noun(u3_noun som) { - if ( c3n == u3a_v1_is_cell(som) ) { + if ( c3n == u3a_is_cell(som) ) { return; } - if ( c3n == u3a_v1_rewrite_ptr(u3a_v1_to_ptr((som))) ) return; + if ( c3n == u3a_rewrite_ptr(u3a_v1_to_ptr((som))) ) return; - u3a_v1_cell* cel = u3a_v1_to_ptr(som); + u3a_cell* cel = u3a_v1_to_ptr(som); u3a_v1_rewrite_noun(cel->hed); u3a_v1_rewrite_noun(cel->tel); @@ -2485,85 +80,3 @@ u3a_v1_rewrite_noun(u3_noun som) cel->hed = u3a_v1_rewritten_noun(cel->hed); cel->tel = u3a_v1_rewritten_noun(cel->tel); } - -#if 0 -/* _ca_detect(): in u3a_v1_detect(). -*/ -static c3_d -_ca_detect(u3p(u3h_root) har_p, u3_noun fum, u3_noun som, c3_d axe_d) -{ - while ( 1 ) { - if ( som == fum ) { - return axe_d; - } - else if ( !_(u3du(fum)) || (u3_none != u3h_get(har_p, fum)) ) { - return 0; - } - else { - c3_d eax_d; - - u3h_put(har_p, fum, 0); - - if ( 0 != (eax_d = _ca_detect(har_p, u3h(fum), som, 2ULL * axe_d)) ) { - return c3y; - } - else { - fum = u3t(fum); - axe_d = (2ULL * axe_d) + 1; - } - } - } -} - -/* u3a_v1_detect(): for debugging, check if (som) is referenced from (fum). -** -** (som) and (fum) are both RETAINED. -*/ -c3_d -u3a_v1_detect(u3_noun fum, u3_noun som) -{ - u3p(u3h_root) har_p = u3h_new(); - c3_o ret_o; - - ret_o = _ca_detect(har_p, fum, som, 1); - u3h_free(har_p); - - return ret_o; -} -#endif - -#ifdef U3_MEMORY_DEBUG -/* u3a_v1_lush(): leak push. -*/ -c3_w -u3a_v1_lush(c3_w lab_w) -{ - c3_w cod_w = u3_Code; - - u3_Code = lab_w; - return cod_w; -} - -/* u3a_v1_lop(): leak pop. -*/ -void -u3a_v1_lop(c3_w lab_w) -{ - u3_Code = lab_w; -} -#else -/* u3a_v1_lush(): leak push. -*/ -c3_w -u3a_v1_lush(c3_w lab_w) -{ - return 0; -} - -/* u3a_v1_lop(): leak pop. -*/ -void -u3a_v1_lop(c3_w lab_w) -{ -} -#endif diff --git a/pkg/noun/v1/allocate.h b/pkg/noun/v1/allocate.h index 5f1990a2a2..6091eb5865 100644 --- a/pkg/noun/v1/allocate.h +++ b/pkg/noun/v1/allocate.h @@ -12,68 +12,6 @@ /** Structures. **/ - /* u3a_v1_road: contiguous allocation and execution context. - */ - typedef struct _u3a_v1_road { - u3p(struct _u3a_v1_road) par_p; // parent road - u3p(struct _u3a_v1_road) kid_p; // child road list - u3p(struct _u3a_v1_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_v1_fbox) fre_p[u3a_fbox_no]; // heap by node size log - u3p(u3a_v1_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_v1_road; - typedef u3a_v1_road u3_v1_road; - /** Macros. Should be better commented. **/ /* Inside a noun. @@ -99,134 +37,12 @@ */ # define u3a_v1_to_pom(off) (off | 0xc0000000) - /* u3a_v1_h(): get head of cell [som]. Bail if [som] is not cell. - */ -# define u3a_v1_h(som) \ - ( _(u3a_v1_is_cell(som)) \ - ? ( ((u3a_v1_cell *)u3a_v1_to_ptr(som))->hed )\ - : u3m_bail(c3__exit) ) - - /* u3a_v1_t(): get tail of cell [som]. Bail if [som] is not cell. - */ -# define u3a_v1_t(som) \ - ( _(u3a_v1_is_cell(som)) \ - ? ( ((u3a_v1_cell *)u3a_v1_to_ptr(som))->tel )\ - : u3m_bail(c3__exit) ) - -# define u3a_v1_north_is_senior(r, dog) \ - __((u3a_v1_to_off(dog) < (r)->rut_p) || \ - (u3a_v1_to_off(dog) >= (r)->mat_p)) - -# define u3a_v1_north_is_junior(r, dog) \ - __((u3a_v1_to_off(dog) >= (r)->cap_p) && \ - (u3a_v1_to_off(dog) < (r)->mat_p)) - -# define u3a_v1_north_is_normal(r, dog) \ - c3a(!(u3a_v1_north_is_senior(r, dog)), \ - !(u3a_v1_north_is_junior(r, dog))) - -# define u3a_v1_south_is_senior(r, dog) \ - __((u3a_v1_to_off(dog) < (r)->mat_p) || \ - (u3a_v1_to_off(dog) >= (r)->rut_p)) - -# define u3a_v1_south_is_junior(r, dog) \ - __((u3a_v1_to_off(dog) < (r)->cap_p) && \ - (u3a_v1_to_off(dog) >= (r)->mat_p)) - -# define u3a_v1_south_is_normal(r, dog) \ - c3a(!(u3a_v1_south_is_senior(r, dog)), \ - !(u3a_v1_south_is_junior(r, dog))) - -# define u3a_v1_is_junior(r, som) \ - ( _(u3a_v1_is_cat(som)) \ - ? c3n \ - : _(u3a_is_north(r)) \ - ? u3a_v1_north_is_junior(r, som) \ - : u3a_v1_south_is_junior(r, som) ) - -# define u3a_v1_is_senior(r, som) \ - ( _(u3a_v1_is_cat(som)) \ - ? c3y \ - : _(u3a_is_north(r)) \ - ? u3a_v1_north_is_senior(r, som) \ - : u3a_v1_south_is_senior(r, som) ) - -# define u3a_v1_is_mutable(r, som) \ - ( _(u3a_v1_is_atom(som)) \ - ? c3n \ - : _(u3a_v1_is_senior(r, som)) \ - ? c3n \ - : _(u3a_v1_is_junior(r, som)) \ - ? c3n \ - : (u3a_v1_botox(u3a_v1_to_ptr(som))->use_w == 1) \ - ? c3y : c3n ) - - - - /** Globals. - **/ - /// Current road (thread-local). - extern u3_v1_road* u3a_v1_Road; -# define u3R_v1 u3a_v1_Road - /** Functions. **/ /** Allocation. **/ - /* Word-aligned allocation. + /* Reference and arena control. */ - /* u3a_v1_walloc(): allocate storage measured in words. - */ - void* - u3a_v1_walloc(void); - - /* u3a_v1_celloc(): allocate a cell. Faster, sometimes. - */ - c3_w* - u3a_v1_celloc(void); - - /* u3a_v1_wtrim(): trim storage. - */ - void - u3a_v1_wtrim(void* tox_v, c3_w old_w, c3_w len_w); - - /* u3a_v1_wealloc(): word realloc. - */ - void* - u3a_v1_wealloc(void* lag_v, c3_w len_w); - - /* C-style aligned allocation - *not* compatible with above. - */ - /* u3a_v1_malloc(): aligned storage measured in bytes. - */ - void* - u3a_v1_malloc(size_t len_i); - - /* u3a_v1_calloc(): aligned storage measured in bytes. - */ - void* - u3a_v1_calloc(size_t num_i, size_t len_i); - - /* u3a_v1_realloc(): aligned realloc in bytes. - */ - void* - u3a_v1_realloc(void* lag_v, size_t len_i); - - /* u3a_v1_free(): free for aligned malloc. - */ - void - u3a_v1_free(void* tox_v); - - /* u3a_v1_mark_noun(): mark a noun for gc. Produce size. - */ - c3_w - u3a_v1_mark_noun(u3_noun som); - - /* u3a_v1_mark_road(): mark ad-hoc persistent road structures. - */ - c3_w - u3a_v1_mark_road(FILE* fil_u); - /* u3a_v1_reclaim(): clear ad-hoc persistent caches to reclaim memory. */ void @@ -252,22 +68,4 @@ u3_noun u3a_v1_rewritten_noun(u3_noun som); - /* u3a_v1_discount_noun(): clean up after counting a noun. - */ - c3_w - u3a_v1_discount_noun(u3_noun som); - - /* u3a_v1_count_ptr(): count a pointer for gc. Produce size. */ - c3_w - u3a_v1_count_ptr(void* ptr_v); - - /* u3a_v1_discount_ptr(): discount a pointer for gc. Produce size. */ - c3_w - u3a_v1_discount_ptr(void* ptr_v); - - /* u3a_v1_prof(): mark/measure/print memory profile. RETAIN. - */ - c3_w - u3a_v1_prof(FILE* fil_u, c3_w den_w, u3_noun mas); - #endif /* ifndef U3_ALLOCATE_H */ diff --git a/pkg/noun/v1/hashtable.c b/pkg/noun/v1/hashtable.c index 92b403eda3..1a2cb6b6c9 100644 --- a/pkg/noun/v1/hashtable.c +++ b/pkg/noun/v1/hashtable.c @@ -1,686 +1,44 @@ /// @file -#include "v1/hashtable.h" +#include "pkg/noun/hashtable.h" +#include "pkg/noun/v1/hashtable.h" -#include "v1/allocate.h" +#include "pkg/noun/allocate.h" +#include "pkg/noun/v1/allocate.h" #include "imprison.h" #include "retrieve.h" #include "xtract.h" -/* CUT_END(): extract [b_w] low bits from [a_w] -*/ -#define CUT_END(a_w, b_w) ((a_w) & ((1 << (b_w)) - 1)) - -/* BIT_SET(): [1] if bit [b_w] is set in [a_w] -*/ -#define BIT_SET(a_w, b_w) ((a_w) & (1 << (b_w))) - -static c3_o -_ch_v1_trim_slot(u3h_v1_root* har_u, u3h_v1_slot *sot_w, c3_w lef_w, c3_w rem_w); - -c3_w -_ch_v1_skip_slot(c3_w mug_w, c3_w lef_w); - -/* u3h_v1_new_cache(): create hashtable with bounded size. -*/ -u3p(u3h_v1_root) -u3h_v1_new_cache(c3_w max_w) -{ - u3h_v1_root* har_u = u3a_v1_walloc(c3_wiseof(u3h_v1_root)); - u3p(u3h_v1_root) har_p = u3of(u3h_v1_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; -} -/* u3h_v1_new(): create hashtable. -*/ -u3p(u3h_v1_root) -u3h_v1_new(void) -{ - return u3h_v1_new_cache(0); -} - -/* _ch_v1_popcount(): number of bits set in word. A standard intrinsic. +/* _ch_popcount(): number of bits set in word. A standard intrinsic. +** NB: copy of _ch_popcount in pkg/noun/hashtable.c */ static c3_w -_ch_v1_popcount(c3_w num_w) +_ch_popcount(c3_w num_w) { return __builtin_popcount(num_w); } -/* _ch_v1_buck_new(): create new bucket. -*/ -static u3h_v1_buck* -_ch_v1_buck_new(c3_w len_w) -{ - u3h_v1_buck* hab_u = u3a_v1_walloc(c3_wiseof(u3h_v1_buck) + - (len_w * c3_wiseof(u3h_v1_slot))); - hab_u->len_w = len_w; - return hab_u; -} - -/* _ch_v1_node_new(): create new node. -*/ -static u3h_v1_node* -_ch_v1_node_new(c3_w len_w) -{ - u3h_v1_node* han_u = u3a_v1_walloc(c3_wiseof(u3h_v1_node) + - (len_w * c3_wiseof(u3h_v1_slot))); - han_u->map_w = 0; - return han_u; -} - -static void _ch_v1_slot_put(u3h_v1_slot*, u3_noun, c3_w, c3_w, c3_w*); - -/* _ch_v1_node_add(): add to node. -*/ -static u3h_v1_node* -_ch_v1_node_add(u3h_v1_node* han_u, c3_w lef_w, c3_w rem_w, u3_noun kev, c3_w *use_w) -{ - c3_w bit_w, inx_w, map_w, i_w; - - lef_w -= 5; - bit_w = (rem_w >> lef_w); - rem_w = CUT_END(rem_w, lef_w); - map_w = han_u->map_w; - inx_w = _ch_v1_popcount(CUT_END(map_w, bit_w)); - - if ( BIT_SET(map_w, bit_w) ) { - _ch_v1_slot_put(&(han_u->sot_w[inx_w]), kev, lef_w, rem_w, use_w); - return han_u; - } - else { - // nothing was at this slot. - // Optimize: use u3a_v1_wealloc. - // - c3_w len_w = _ch_v1_popcount(map_w); - u3h_v1_node* nah_u = _ch_v1_node_new(1 + len_w); - nah_u->map_w = han_u->map_w | (1 << bit_w); - - for ( i_w = 0; i_w < inx_w; i_w++ ) { - nah_u->sot_w[i_w] = han_u->sot_w[i_w]; - } - nah_u->sot_w[inx_w] = u3h_v1_noun_be_warm(u3h_v1_noun_to_slot(kev)); - for ( i_w = inx_w; i_w < len_w; i_w++ ) { - nah_u->sot_w[i_w + 1] = han_u->sot_w[i_w]; - } - - u3a_v1_wfree(han_u); - *use_w += 1; - return nah_u; - } -} - -/* ch_buck_add(): add to bucket. -*/ -static u3h_v1_buck* -_ch_v1_buck_add(u3h_v1_buck* hab_u, u3_noun kev, c3_w *use_w) -{ - c3_w i_w; - - // if our key is equal to any of the existing keys in the bucket, - // then replace that key-value pair with kev. - // - for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - u3_noun kov = u3h_v1_slot_to_noun(hab_u->sot_w[i_w]); - if ( c3y == u3r_sing(u3h_v1(kev), u3h_v1(kov)) ) { - hab_u->sot_w[i_w] = u3h_v1_noun_to_slot(kev); - u3z(kov); - return hab_u; - } - } - - // create mutant bucket with added key-value pair. - // Optimize: use u3a_v1_wealloc(). - { - u3h_v1_buck* bah_u = _ch_v1_buck_new(1 + hab_u->len_w); - bah_u->sot_w[0] = u3h_v1_noun_be_warm(u3h_v1_noun_to_slot(kev)); - - for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - bah_u->sot_w[i_w + 1] = hab_u->sot_w[i_w]; - } - - u3a_v1_wfree(hab_u); - *use_w += 1; - return bah_u; - } -} - -/* _ch_v1_some_add(): add to node or bucket. -*/ -static void* -_ch_v1_some_add(void* han_v, c3_w lef_w, c3_w rem_w, u3_noun kev, c3_w *use_w) -{ - if ( 0 == lef_w ) { - return _ch_v1_buck_add((u3h_v1_buck*)han_v, kev, use_w); - } - else return _ch_v1_node_add((u3h_v1_node*)han_v, lef_w, rem_w, kev, use_w); -} - -/* _ch_v1_two(): create a new node with two leaves underneath -*/ -u3h_v1_slot -_ch_v1_two(u3h_v1_slot had_w, u3h_v1_slot add_w, c3_w lef_w, c3_w ham_w, c3_w mad_w) -{ - void* ret; - - if ( 0 == lef_w ) { - u3h_v1_buck* hab_u = _ch_v1_buck_new(2); - ret = hab_u; - hab_u->sot_w[0] = had_w; - hab_u->sot_w[1] = add_w; - } - else { - c3_w hop_w, tad_w; - lef_w -= 5; - hop_w = ham_w >> lef_w; - tad_w = mad_w >> lef_w; - if ( hop_w == tad_w ) { - // fragments collide: store in a child node. - u3h_v1_node* han_u = _ch_v1_node_new(1); - ret = han_u; - han_u->map_w = 1 << hop_w; - ham_w = CUT_END(ham_w, lef_w); - mad_w = CUT_END(mad_w, lef_w); - han_u->sot_w[0] = _ch_v1_two(had_w, add_w, lef_w, ham_w, mad_w); - } - else { - u3h_v1_node* han_u = _ch_v1_node_new(2); - ret = han_u; - han_u->map_w = (1 << hop_w) | (1 << tad_w); - // smaller mug fragments go in earlier slots - if ( hop_w < tad_w ) { - han_u->sot_w[0] = had_w; - han_u->sot_w[1] = add_w; - } - else { - han_u->sot_w[0] = add_w; - han_u->sot_w[1] = had_w; - } - } - } - - return u3h_v1_node_to_slot(ret); -} - -/* _ch_v1_slot_put(): store a key-value pair in a non-null slot -*/ -static void -_ch_v1_slot_put(u3h_v1_slot* sot_w, u3_noun kev, c3_w lef_w, c3_w rem_w, c3_w* use_w) -{ - if ( c3n == u3h_v1_slot_is_noun(*sot_w) ) { - void* hav_v = _ch_v1_some_add(u3h_v1_slot_to_node(*sot_w), - lef_w, - rem_w, - kev, - use_w); - - u3_assert( c3y == u3h_v1_slot_is_node(*sot_w) ); - *sot_w = u3h_v1_node_to_slot(hav_v); - } - else { - u3_noun kov = u3h_v1_slot_to_noun(*sot_w); - u3h_v1_slot add_w = u3h_v1_noun_be_warm(u3h_v1_noun_to_slot(kev)); - if ( c3y == u3r_sing(u3h_v1(kev), u3h_v1(kov)) ) { - // replace old value - u3z(kov); - *sot_w = add_w; - } - else { - c3_w ham_w = CUT_END(u3r_mug(u3h_v1(kov)), lef_w); - *sot_w = _ch_v1_two(*sot_w, add_w, lef_w, ham_w, rem_w); - *use_w += 1; - } - } -} - -/* u3h_v1_put(): insert in hashtable. -** -** `key` is RETAINED; `val` is transferred. -*/ -void -u3h_v1_put(u3p(u3h_v1_root) har_p, u3_noun key, u3_noun val) -{ - u3h_v1_root* har_u = u3to(u3h_v1_root, har_p); - u3_noun kev = u3nc(u3k(key), val); - c3_w mug_w = u3r_mug(key); - c3_w inx_w = (mug_w >> 25); // 6 bits - c3_w rem_w = CUT_END(mug_w, 25); - u3h_v1_slot* sot_w = &(har_u->sot_w[inx_w]); - - if ( c3y == u3h_v1_slot_is_null(*sot_w) ) { - *sot_w = u3h_v1_noun_be_warm(u3h_v1_noun_to_slot(kev)); - har_u->use_w += 1; - } - else { - _ch_v1_slot_put(sot_w, kev, 25, rem_w, &(har_u->use_w)); - } - - if ( har_u->max_w > 0 ) { - u3h_v1_trim_to(har_p, har_u->max_w); - } -} - -/* _ch_v1_uni_with(): key/value callback, put into [*wit] +/* _ch_free_buck(): free bucket +** NB: copy of _ch_free_buck in pkg/noun/hashtable.c */ static void -_ch_v1_uni_with(u3_noun kev, void* wit) -{ - u3p(u3h_v1_root) har_p = *(u3p(u3h_v1_root)*)wit; - u3_noun key, val; - u3x_cell(kev, &key, &val); - - u3h_v1_put(har_p, key, u3k(val)); -} - -/* u3h_v1_uni(): unify hashtables, copying [rah_p] into [har_p] -*/ -void -u3h_v1_uni(u3p(u3h_v1_root) har_p, u3p(u3h_v1_root) rah_p) -{ - u3h_v1_walk_with(rah_p, _ch_v1_uni_with, &har_p); -} - -/* _ch_v1_trim_node(): trim one entry from a node slot or its children -*/ -static c3_o -_ch_v1_trim_node(u3h_v1_root* har_u, u3h_v1_slot* sot_w, c3_w lef_w, c3_w rem_w) -{ - c3_w bit_w, map_w, inx_w; - u3h_v1_slot* tos_w; - u3h_v1_node* han_u = (u3h_v1_node*) u3h_v1_slot_to_node(*sot_w); - - lef_w -= 5; - bit_w = (rem_w >> lef_w); - map_w = han_u->map_w; - - if ( !BIT_SET(map_w, bit_w) ) { - har_u->arm_u.mug_w = _ch_v1_skip_slot(har_u->arm_u.mug_w, lef_w); - return c3n; - } - - rem_w = CUT_END(rem_w, lef_w); - inx_w = _ch_v1_popcount(CUT_END(map_w, bit_w)); - tos_w = &(han_u->sot_w[inx_w]); - - if ( c3n == _ch_v1_trim_slot(har_u, tos_w, lef_w, rem_w) ) { - // nothing trimmed - return c3n; - } - else if ( 0 != *tos_w ) { - // something trimmed, but slot still has value - return c3y; - } - else { - // shrink! - c3_w i_w, ken_w, len_w = _ch_v1_popcount(map_w); - u3h_v1_slot kes_w; - - if ( 2 == len_w && ((ken_w = (0 == inx_w) ? 1 : 0), - (kes_w = han_u->sot_w[ken_w]), - (c3y == u3h_v1_slot_is_noun(kes_w))) ) { - // only one side left, and the other is a noun. debucketize. - *sot_w = kes_w; - u3a_v1_wfree(han_u); - } - else { - // shrink node in place; don't reallocate, we could be low on memory - // - han_u->map_w &= ~(1 << bit_w); - --len_w; - - for ( i_w = inx_w; i_w < len_w; i_w++ ) { - han_u->sot_w[i_w] = han_u->sot_w[i_w + 1]; - } - } - return c3y; - } -} - -/* _ch_v1_trim_kev(): trim a single entry slot -*/ -static c3_o -_ch_v1_trim_kev(u3h_v1_slot *sot_w) -{ - if ( _(u3h_v1_slot_is_warm(*sot_w)) ) { - *sot_w = u3h_v1_noun_be_cold(*sot_w); - return c3n; - } - else { - u3_noun kev = u3h_v1_slot_to_noun(*sot_w); - *sot_w = 0; - u3z(kev); - return c3y; - } -} - -/* _ch_v1_trim_node(): trim one entry from a bucket slot -*/ -static c3_o -_ch_v1_trim_buck(u3h_v1_root* har_u, u3h_v1_slot* sot_w) -{ - c3_w i_w, len_w; - u3h_v1_buck* hab_u = u3h_v1_slot_to_node(*sot_w); - - for ( len_w = hab_u->len_w; - har_u->arm_u.inx_w < len_w; - har_u->arm_u.inx_w += 1 ) - { - if ( c3y == _ch_v1_trim_kev(&(hab_u->sot_w[har_u->arm_u.inx_w])) ) { - if ( 2 == len_w ) { - // 2 things in bucket: debucketize to key-value pair, the next - // run will point at this pair (same mug_w, no longer in bucket) - *sot_w = hab_u->sot_w[ (0 == har_u->arm_u.inx_w) ? 1 : 0 ]; - u3a_v1_wfree(hab_u); - har_u->arm_u.inx_w = 0; - } - else { - // shrink bucket in place; don't reallocate, we could be low on memory - hab_u->len_w = --len_w; - - for ( i_w = har_u->arm_u.inx_w; i_w < len_w; ++i_w ) { - hab_u->sot_w[i_w] = hab_u->sot_w[i_w + 1]; - } - // leave the arm pointing at the next index in the bucket - ++(har_u->arm_u.inx_w); - } - return c3y; - } - } - - har_u->arm_u.mug_w = (har_u->arm_u.mug_w + 1) & 0x7FFFFFFF; // modulo 2^31 - har_u->arm_u.inx_w = 0; - return c3n; -} - -/* _ch_v1_trim_some(): trim one entry from a bucket or node slot -*/ -static c3_o -_ch_v1_trim_some(u3h_v1_root* har_u, u3h_v1_slot* sot_w, c3_w lef_w, c3_w rem_w) -{ - if ( 0 == lef_w ) { - return _ch_v1_trim_buck(har_u, sot_w); - } - else { - return _ch_v1_trim_node(har_u, sot_w, lef_w, rem_w); - } -} - -/* _ch_v1_skip_slot(): increment arm over hash prefix. -*/ -c3_w -_ch_v1_skip_slot(c3_w mug_w, c3_w lef_w) -{ - c3_w hig_w = mug_w >> lef_w; - c3_w new_w = CUT_END(hig_w + 1, (31 - lef_w)); // modulo 2^(31 - lef_w) - return new_w << lef_w; -} - -/* _ch_v1_trim_slot(): trim one entry from a non-bucket slot -*/ -static c3_o -_ch_v1_trim_slot(u3h_v1_root* har_u, u3h_v1_slot *sot_w, c3_w lef_w, c3_w rem_w) -{ - if ( c3y == u3h_v1_slot_is_noun(*sot_w) ) { - har_u->arm_u.mug_w = _ch_v1_skip_slot(har_u->arm_u.mug_w, lef_w); - return _ch_v1_trim_kev(sot_w); - } - else { - return _ch_v1_trim_some(har_u, sot_w, lef_w, rem_w); - } -} - -/* _ch_v1_trim_root(): trim one entry from a hashtable -*/ -static c3_o -_ch_v1_trim_root(u3h_v1_root* har_u) -{ - c3_w mug_w = har_u->arm_u.mug_w; - c3_w inx_w = mug_w >> 25; // 6 bits - u3h_v1_slot* sot_w = &(har_u->sot_w[inx_w]); - - if ( c3y == u3h_v1_slot_is_null(*sot_w) ) { - har_u->arm_u.mug_w = _ch_v1_skip_slot(har_u->arm_u.mug_w, 25); - return c3n; - } - - return _ch_v1_trim_slot(har_u, sot_w, 25, CUT_END(mug_w, 25)); -} - -/* u3h_v1_trim_to(): trim to n key-value pairs -*/ -void -u3h_v1_trim_to(u3p(u3h_v1_root) har_p, c3_w n_w) -{ - u3h_v1_root* har_u = u3to(u3h_v1_root, har_p); - - while ( har_u->use_w > n_w ) { - if ( c3y == _ch_v1_trim_root(har_u) ) { - har_u->use_w -= 1; - } - } -} - -/* _ch_v1_buck_hum(): read in bucket. -*/ -static c3_o -_ch_v1_buck_hum(u3h_v1_buck* hab_u, c3_w mug_w) -{ - c3_w i_w; - - for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - if ( mug_w == u3r_mug(u3h_v1(u3h_v1_slot_to_noun(hab_u->sot_w[i_w]))) ) { - return c3y; - } - } - return c3n; -} - -/* _ch_v1_node_hum(): read in node. -*/ -static c3_o -_ch_v1_node_hum(u3h_v1_node* han_u, c3_w lef_w, c3_w rem_w, c3_w mug_w) -{ - c3_w bit_w, map_w; - - lef_w -= 5; - bit_w = (rem_w >> lef_w); - rem_w = CUT_END(rem_w, lef_w); - map_w = han_u->map_w; - - if ( !BIT_SET(map_w, bit_w) ) { - return c3n; - } - else { - c3_w inx_w = _ch_v1_popcount(CUT_END(map_w, bit_w)); - c3_w sot_w = han_u->sot_w[inx_w]; - - if ( _(u3h_v1_slot_is_noun(sot_w)) ) { - u3_noun kev = u3h_v1_slot_to_noun(sot_w); - - if ( mug_w == u3r_mug(u3h_v1(kev)) ) { - return c3y; - } - else { - return c3n; - } - } - else { - void* hav_v = u3h_v1_slot_to_node(sot_w); - - if ( 0 == lef_w ) { - return _ch_v1_buck_hum(hav_v, mug_w); - } - else return _ch_v1_node_hum(hav_v, lef_w, rem_w, mug_w); - } - } -} - -/* u3h_v1_hum(): check presence in hashtable. -** -** `key` is RETAINED. -*/ -c3_o -u3h_v1_hum(u3p(u3h_v1_root) har_p, c3_w mug_w) -{ - u3h_v1_root* har_u = u3to(u3h_v1_root, har_p); - c3_w inx_w = (mug_w >> 25); - c3_w rem_w = CUT_END(mug_w, 25); - c3_w sot_w = har_u->sot_w[inx_w]; - - if ( _(u3h_v1_slot_is_null(sot_w)) ) { - return c3n; - } - else if ( _(u3h_v1_slot_is_noun(sot_w)) ) { - u3_noun kev = u3h_v1_slot_to_noun(sot_w); - - if ( mug_w == u3r_mug(u3h_v1(kev)) ) { - return c3y; - } - else { - return c3n; - } - } - else { - u3h_v1_node* han_u = u3h_v1_slot_to_node(sot_w); - - return _ch_v1_node_hum(han_u, 25, rem_w, mug_w); - } -} - -/* _ch_v1_buck_git(): read in bucket. -*/ -static u3_weak -_ch_v1_buck_git(u3h_v1_buck* hab_u, u3_noun key) +_ch_free_buck(u3h_buck* hab_u) { c3_w i_w; for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - u3_noun kev = u3h_v1_slot_to_noun(hab_u->sot_w[i_w]); - if ( _(u3r_sing(key, u3h_v1(kev))) ) { - return u3t(kev); - } + u3z(u3h_slot_to_noun(hab_u->sot_w[i_w])); } - return u3_none; + u3a_wfree(hab_u); } -/* _ch_v1_node_git(): read in node. -*/ -static u3_weak -_ch_v1_node_git(u3h_v1_node* han_u, c3_w lef_w, c3_w rem_w, u3_noun key) -{ - c3_w bit_w, map_w; - - lef_w -= 5; - bit_w = (rem_w >> lef_w); - rem_w = CUT_END(rem_w, lef_w); - map_w = han_u->map_w; - - if ( !BIT_SET(map_w, bit_w) ) { - return u3_none; - } - else { - c3_w inx_w = _ch_v1_popcount(CUT_END(map_w, bit_w)); - c3_w sot_w = han_u->sot_w[inx_w]; - - if ( _(u3h_v1_slot_is_noun(sot_w)) ) { - u3_noun kev = u3h_v1_slot_to_noun(sot_w); - - if ( _(u3r_sing(key, u3h_v1(kev))) ) { - return u3t(kev); - } - else { - return u3_none; - } - } - else { - void* hav_v = u3h_v1_slot_to_node(sot_w); - - if ( 0 == lef_w ) { - return _ch_v1_buck_git(hav_v, key); - } - else return _ch_v1_node_git(hav_v, lef_w, rem_w, key); - } - } -} - -/* u3h_v1_git(): read from hashtable. -** -** `key` is RETAINED; result is RETAINED. -*/ -u3_weak -u3h_v1_git(u3p(u3h_v1_root) har_p, u3_noun key) -{ - u3h_v1_root* har_u = u3to(u3h_v1_root, har_p); - c3_w mug_w = u3r_mug(key); - c3_w inx_w = (mug_w >> 25); - c3_w rem_w = CUT_END(mug_w, 25); - c3_w sot_w = har_u->sot_w[inx_w]; - - if ( _(u3h_v1_slot_is_null(sot_w)) ) { - return u3_none; - } - else if ( _(u3h_v1_slot_is_noun(sot_w)) ) { - u3_noun kev = u3h_v1_slot_to_noun(sot_w); - - if ( _(u3r_sing(key, u3h_v1(kev))) ) { - har_u->sot_w[inx_w] = u3h_v1_noun_be_warm(sot_w); - return u3t(kev); - } - else { - return u3_none; - } - } - else { - u3h_v1_node* han_u = u3h_v1_slot_to_node(sot_w); - - return _ch_v1_node_git(han_u, 25, rem_w, key); - } -} - -/* u3h_v1_get(): read from hashtable, incrementing refcount. -** -** `key` is RETAINED; result is PRODUCED. -*/ -u3_weak -u3h_v1_get(u3p(u3h_v1_root) har_p, u3_noun key) -{ - u3_noun pro = u3h_v1_git(har_p, key); - - if ( u3_none != pro ) { - u3k(pro); - } - return pro; -} - -/* _ch_v1_free_buck(): free bucket +/* _ch_free_node(): free node. */ static void -_ch_v1_free_buck(u3h_v1_buck* hab_u) +_ch_free_node(u3h_node* han_u, c3_w lef_w) { - c3_w i_w; - - for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - u3z(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 len_w = _ch_popcount(han_u->map_w); c3_w i_w; lef_w -= 5; @@ -688,63 +46,64 @@ _ch_v1_free_node(u3h_v1_node* han_u, c3_w lef_w) 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)) ) { - u3z(u3h_v1_slot_to_noun(sot_w)); + if ( _(u3h_slot_is_noun(sot_w)) ) { + u3z(u3h_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); + _ch_free_buck(hav_v); } else { - _ch_v1_free_node(hav_v, lef_w); + _ch_free_node(hav_v, lef_w); } } } - u3a_v1_wfree(han_u); + u3a_wfree(han_u); } /* u3h_v1_free(): free hashtable. */ void -u3h_v1_free(u3p(u3h_v1_root) har_p) +u3h_v1_free(u3p(u3h_root) har_p) { - u3h_v1_root* har_u = u3to(u3h_v1_root, har_p); + u3h_root* har_u = u3to(u3h_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)) ) { - u3z(u3h_v1_slot_to_noun(sot_w)); + if ( _(u3h_slot_is_noun(sot_w)) ) { + u3z(u3h_slot_to_noun(sot_w)); } - else if ( _(u3h_v1_slot_is_node(sot_w)) ) { - u3h_v1_node* han_u = u3h_v1_slot_to_node(sot_w); + else if ( _(u3h_slot_is_node(sot_w)) ) { + u3h_node* han_u = u3h_slot_to_node(sot_w); - _ch_v1_free_node(han_u, 25); + _ch_free_node(han_u, 25); } } - u3a_v1_wfree(har_u); + u3a_free(har_u); } -/* _ch_v1_walk_buck(): walk bucket for gc. +/* _ch_walk_buck(): walk bucket for gc. +** NB: copy of _ch_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) +_ch_walk_buck(u3h_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); + fun_f(u3h_slot_to_noun(hab_u->sot_w[i_w]), wit); } } -/* _ch_v1_walk_node(): walk node for gc. +/* _ch_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) +_ch_walk_node(u3h_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 len_w = _ch_popcount(han_u->map_w); c3_w i_w; lef_w -= 5; @@ -752,18 +111,18 @@ _ch_v1_walk_node(u3h_v1_node* han_u, c3_w lef_w, void (*fun_f)(u3_noun, void*), 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); + if ( _(u3h_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_slot_to_noun(sot_w); fun_f(kev, wit); } else { - void* hav_v = u3h_v1_slot_to_node(sot_w); + void* hav_v = u3h_slot_to_node(sot_w); if ( 0 == lef_w ) { - _ch_v1_walk_buck(hav_v, fun_f, wit); + _ch_walk_buck(hav_v, fun_f, wit); } else { - _ch_v1_walk_node(hav_v, lef_w, fun_f, wit); + _ch_walk_node(hav_v, lef_w, fun_f, wit); } } } @@ -773,25 +132,25 @@ _ch_v1_walk_node(u3h_v1_node* han_u, c3_w lef_w, void (*fun_f)(u3_noun, void*), * argument; RETAINS. */ void -u3h_v1_walk_with(u3p(u3h_v1_root) har_p, +u3h_v1_walk_with(u3p(u3h_root) har_p, void (*fun_f)(u3_noun, void*), void* wit) { - u3h_v1_root* har_u = u3to(u3h_v1_root, har_p); + u3h_root* har_u = u3to(u3h_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); + if ( _(u3h_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_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_slot_to_node(sot_w); + else if ( _(u3h_slot_is_node(sot_w)) ) { + u3h_node* han_u = u3h_slot_to_node(sot_w); - _ch_v1_walk_node(han_u, 25, fun_f, wit); + _ch_walk_node(han_u, 25, fun_f, wit); } } } @@ -808,199 +167,34 @@ _ch_v1_walk_plain(u3_noun kev, void* wit) /* 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(u3p(u3h_root) har_p, void (*fun_f)(u3_noun)) { u3h_v1_walk_with(har_p, _ch_v1_walk_plain, fun_f); } -/* _ch_v1_take_noun(): take key and call [fun_f] on val. -*/ -static u3h_v1_slot -_ch_v1_take_noun(u3h_v1_slot sot_w, u3_funk fun_f) -{ - u3_noun kov = u3h_v1_slot_to_noun(sot_w); - u3_noun kev = u3nc(u3a_v1_take(u3h_v1(kov)), - fun_f(u3t(kov))); - - return u3h_v1_noun_to_slot(kev); -} - -/* _ch_v1_take_buck(): take bucket and contents -*/ -static u3h_v1_slot -_ch_v1_take_buck(u3h_v1_slot sot_w, u3_funk fun_f) -{ - u3h_v1_buck* hab_u = u3h_v1_slot_to_node(sot_w); - u3h_v1_buck* bah_u = _ch_v1_buck_new(hab_u->len_w); - c3_w i_w; - - for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - bah_u->sot_w[i_w] = _ch_v1_take_noun(hab_u->sot_w[i_w], fun_f); - } - - return u3h_v1_node_to_slot(bah_u); -} - -/* _ch_v1_take_node(): take node and contents -*/ -static u3h_v1_slot -_ch_v1_take_node(u3h_v1_slot sot_w, c3_w lef_w, u3_funk fun_f) -{ - u3h_v1_node* han_u = u3h_v1_slot_to_node(sot_w); - c3_w len_w = _ch_v1_popcount(han_u->map_w); - u3h_v1_node* nah_u = _ch_v1_node_new(len_w); - c3_w i_w; - - nah_u->map_w = han_u->map_w; - lef_w -= 5; - - for ( i_w = 0; i_w < len_w; i_w++ ) { - c3_w tos_w = han_u->sot_w[i_w]; - nah_u->sot_w[i_w] = ( c3y == u3h_v1_slot_is_noun(tos_w) ) - ? _ch_v1_take_noun(tos_w, fun_f) - : ( 0 == lef_w ) - ? _ch_v1_take_buck(tos_w, fun_f) - : _ch_v1_take_node(tos_w, lef_w, fun_f); - } - - return u3h_v1_node_to_slot(nah_u); -} - -/* u3h_v1_take_with(): gain hashtable, copying junior keys -** and calling [fun_f] on values -*/ -u3p(u3h_v1_root) -u3h_v1_take_with(u3p(u3h_v1_root) har_p, u3_funk fun_f) -{ - u3h_v1_root* har_u = u3to(u3h_v1_root, har_p); - u3p(u3h_v1_root) rah_p = u3h_v1_new_cache(har_u->max_w); - u3h_v1_root* rah_u = u3to(u3h_v1_root, rah_p); - c3_w i_w; - - rah_u->use_w = har_u->use_w; - rah_u->arm_u = har_u->arm_u; - - for ( i_w = 0; i_w < 64; i_w++ ) { - c3_w sot_w = har_u->sot_w[i_w]; - rah_u->sot_w[i_w] = ( c3y == u3h_v1_slot_is_noun(sot_w) ) - ? _ch_v1_take_noun(sot_w, fun_f) - : _ch_v1_take_node(sot_w, 25, fun_f); - } - - return rah_p; -} - -/* u3h_v1_take(): gain hashtable, copying junior nouns -*/ -u3p(u3h_v1_root) -u3h_v1_take(u3p(u3h_v1_root) har_p) -{ - return u3h_v1_take_with(har_p, u3a_v1_take); -} - -/* _ch_v1_mark_buck(): mark bucket for gc. -*/ -c3_w -_ch_v1_mark_buck(u3h_v1_buck* hab_u) -{ - c3_w tot_w = 0; - c3_w i_w; - - for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - tot_w += u3a_v1_mark_noun(u3h_v1_slot_to_noun(hab_u->sot_w[i_w])); - } - tot_w += u3a_v1_mark_ptr(hab_u); - - return tot_w; -} - -/* _ch_v1_mark_node(): mark node for gc. -*/ -c3_w -_ch_v1_mark_node(u3h_v1_node* han_u, c3_w lef_w) -{ - c3_w tot_w = 0; - 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); - - tot_w += u3a_v1_mark_noun(kev); - } - else { - void* hav_v = u3h_v1_slot_to_node(sot_w); - - if ( 0 == lef_w ) { - tot_w += _ch_v1_mark_buck(hav_v); - } else { - tot_w += _ch_v1_mark_node(hav_v, lef_w); - } - } - } - - tot_w += u3a_v1_mark_ptr(han_u); - - return tot_w; -} - -/* u3h_v1_mark(): mark hashtable for gc. -*/ -c3_w -u3h_v1_mark(u3p(u3h_v1_root) har_p) -{ - c3_w tot_w = 0; - 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); - - tot_w += u3a_v1_mark_noun(kev); - } - else if ( _(u3h_v1_slot_is_node(sot_w)) ) { - u3h_v1_node* han_u = u3h_v1_slot_to_node(sot_w); - - tot_w += _ch_v1_mark_node(han_u, 25); - } - } - - tot_w += u3a_v1_mark_ptr(har_u); - - return tot_w; -} - -/* _ch_v1_rewrite_buck(): rewrite buck for compaction. +/* _ch_rewrite_buck(): rewrite buck for compaction. */ void -_ch_v1_rewrite_buck(u3h_v1_buck* hab_u) +_ch_rewrite_buck(u3h_buck* hab_u) { - if ( c3n == u3a_v1_rewrite_ptr(hab_u) ) return; + if ( c3n == u3a_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_v1_slot_to_noun(hab_u->sot_w[i_w]); - hab_u->sot_w[i_w] = u3h_v1_noun_to_slot(u3a_v1_rewritten_noun(som)); + u3_noun som = u3h_slot_to_noun(hab_u->sot_w[i_w]); + hab_u->sot_w[i_w] = u3h_noun_to_slot(u3a_v1_rewritten_noun(som)); u3a_v1_rewrite_noun(som); } } -/* _ch_v1_rewrite_node(): rewrite node for compaction. +/* _ch_rewrite_node(): rewrite node for compaction. */ void -_ch_v1_rewrite_node(u3h_v1_node* han_u, c3_w lef_w) +_ch_rewrite_node(u3h_node* han_u, c3_w lef_w) { - if ( c3n == u3a_v1_rewrite_ptr(han_u) ) return; + if ( c3n == u3a_rewrite_ptr(han_u) ) return; - c3_w len_w = _ch_v1_popcount(han_u->map_w); + c3_w len_w = _ch_popcount(han_u->map_w); c3_w i_w; lef_w -= 5; @@ -1008,22 +202,22 @@ _ch_v1_rewrite_node(u3h_v1_node* han_u, c3_w lef_w) 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); - han_u->sot_w[i_w] = u3h_v1_noun_to_slot(u3a_v1_rewritten_noun(kev)); + if ( _(u3h_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_slot_to_noun(sot_w); + han_u->sot_w[i_w] = u3h_noun_to_slot(u3a_v1_rewritten_noun(kev)); u3a_v1_rewrite_noun(kev); } else { void* hav_v = u3h_v1_slot_to_node(sot_w); - u3h_v1_node* nod_u = u3to(u3h_v1_node,u3a_v1_rewritten(u3of(u3h_v1_node,hav_v))); + u3h_node* nod_u = u3to(u3h_node, u3a_v1_rewritten(u3of(u3h_node,hav_v))); - han_u->sot_w[i_w] = u3h_v2_node_to_slot(nod_u); + han_u->sot_w[i_w] = u3h_v1_node_to_slot(nod_u); if ( 0 == lef_w ) { - _ch_v1_rewrite_buck(hav_v); + _ch_rewrite_buck(hav_v); } else { - _ch_v1_rewrite_node(hav_v, lef_w); + _ch_rewrite_node(hav_v, lef_w); } } } @@ -1032,198 +226,29 @@ _ch_v1_rewrite_node(u3h_v1_node* han_u, c3_w lef_w) /* u3h_v1_rewrite(): rewrite pointers during compaction. */ void -u3h_v1_rewrite(u3p(u3h_v1_root) har_p) +u3h_v1_rewrite(u3p(u3h_root) har_p) { - u3h_v1_root* har_u = u3to(u3h_v1_root, har_p); + u3h_root* har_u = u3to(u3h_root, har_p); c3_w i_w; - if ( c3n == u3a_v1_rewrite_ptr(har_u) ) return; + if ( c3n == u3a_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_v1_slot_is_noun(sot_w)) ) { - u3_noun kev = u3h_v1_slot_to_noun(sot_w); - har_u->sot_w[i_w] = u3h_v1_noun_to_slot(u3a_v1_rewritten_noun(kev)); + if ( _(u3h_slot_is_noun(sot_w)) ) { + u3_noun kev = u3h_slot_to_noun(sot_w); + har_u->sot_w[i_w] = u3h_noun_to_slot(u3a_v1_rewritten_noun(kev)); u3a_v1_rewrite_noun(kev); } - else if ( _(u3h_v1_slot_is_node(sot_w)) ) { - u3h_v1_node* han_u = u3h_v1_slot_to_node(sot_w); - u3h_v1_node* nod_u = u3to(u3h_v1_node,u3a_v1_rewritten(u3of(u3h_v1_node,han_u))); - - har_u->sot_w[i_w] = u3h_v2_node_to_slot(nod_u); - - _ch_v1_rewrite_node(han_u, 25); - } - } -} - -/* _ch_v1_count_buck(): count bucket for gc. -*/ -c3_w -_ch_v1_count_buck(u3h_v1_buck* hab_u) -{ - c3_w tot_w = 0; - c3_w i_w; - - for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - tot_w += u3a_v1_count_noun(u3h_v1_slot_to_noun(hab_u->sot_w[i_w])); - } - tot_w += u3a_v1_count_ptr(hab_u); - - return tot_w; -} - -/* _ch_v1_count_node(): count node for gc. -*/ -c3_w -_ch_v1_count_node(u3h_v1_node* han_u, c3_w lef_w) -{ - c3_w tot_w = 0; - 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); + else if ( _(u3h_slot_is_node(sot_w)) ) { + u3h_node* han_u = u3h_v1_slot_to_node(sot_w); + u3h_node* nod_u = u3to(u3h_node, u3a_v1_rewritten(u3of(u3h_node,han_u))); - tot_w += u3a_v1_count_noun(kev); - } - else { - void* hav_v = u3h_v1_slot_to_node(sot_w); + har_u->sot_w[i_w] = u3h_v1_node_to_slot(nod_u); - if ( 0 == lef_w ) { - tot_w += _ch_v1_count_buck(hav_v); - } else { - tot_w += _ch_v1_count_node(hav_v, lef_w); - } + _ch_rewrite_node(han_u, 25); } } - - tot_w += u3a_v1_count_ptr(han_u); - - return tot_w; -} - -/* u3h_v1_count(): count hashtable for gc. -*/ -c3_w -u3h_v1_count(u3p(u3h_v1_root) har_p) -{ - c3_w tot_w = 0; - 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); - - tot_w += u3a_v1_count_noun(kev); - } - else if ( _(u3h_v1_slot_is_node(sot_w)) ) { - u3h_v1_node* han_u = u3h_v1_slot_to_node(sot_w); - - tot_w += _ch_v1_count_node(han_u, 25); - } - } - - tot_w += u3a_v1_count_ptr(har_u); - - return tot_w; -} - -/* _ch_v1_discount_buck(): discount bucket for gc. -*/ -c3_w -_ch_v1_discount_buck(u3h_v1_buck* hab_u) -{ - c3_w tot_w = 0; - c3_w i_w; - - for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) { - tot_w += u3a_v1_discount_noun(u3h_v1_slot_to_noun(hab_u->sot_w[i_w])); - } - tot_w += u3a_v1_discount_ptr(hab_u); - - return tot_w; -} - -/* _ch_v1_discount_node(): discount node for gc. -*/ -c3_w -_ch_v1_discount_node(u3h_v1_node* han_u, c3_w lef_w) -{ - c3_w tot_w = 0; - 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); - - tot_w += u3a_v1_discount_noun(kev); - } - else { - void* hav_v = u3h_v1_slot_to_node(sot_w); - - if ( 0 == lef_w ) { - tot_w += _ch_v1_discount_buck(hav_v); - } else { - tot_w += _ch_v1_discount_node(hav_v, lef_w); - } - } - } - - tot_w += u3a_v1_discount_ptr(han_u); - - return tot_w; -} - -/* u3h_v1_discount(): discount hashtable for gc. -*/ -c3_w -u3h_v1_discount(u3p(u3h_v1_root) har_p) -{ - c3_w tot_w = 0; - 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); - - tot_w += u3a_v1_discount_noun(kev); - } - else if ( _(u3h_v1_slot_is_node(sot_w)) ) { - u3h_v1_node* han_u = u3h_v1_slot_to_node(sot_w); - - tot_w += _ch_v1_discount_node(han_u, 25); - } - } - - tot_w += u3a_v1_discount_ptr(har_u); - - return tot_w; -} - -/* u3h_v1_wyt(): number of entries -*/ -c3_w -u3h_v1_wyt(u3p(u3h_v1_root) har_p) -{ - u3h_v1_root* har_u = u3to(u3h_v1_root, har_p); - return har_u->use_w; } diff --git a/pkg/noun/v1/hashtable.h b/pkg/noun/v1/hashtable.h index 367d794831..437827b232 100644 --- a/pkg/noun/v1/hashtable.h +++ b/pkg/noun/v1/hashtable.h @@ -1,190 +1,49 @@ #ifndef U3_HASHTABLE_V1_H #define U3_HASHTABLE_V1_H +#include "pkg/noun/hashtable.h" + #include "c3.h" #include "types.h" /** Data structures. **/ - /** Straightforward implementation of the classic Bagwell - *** HAMT (hash array mapped trie), using a mug hash. - *** - *** Because a mug is 31 bits, the root table has 64 slots. - *** The 31 bits of a mug are divided into the first lookup, - *** which is 6 bits (corresponding to the 64 entries in the - *** root table), followed by 5 more branchings of 5 bits each, - *** 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. - **/ - /* u3h_v1_slot: map slot. - ** - ** Either a key-value cell or a loom offset, decoded as a pointer - ** to a u3h_v1_node, or a u3h_v1_buck at the bottom. Matches the u3_noun - ** format - coordinate with allocate.h. The top two bits are: - ** - ** 00 - empty (in the root table only) - ** 01 - table (node or buck) - ** 02 - entry, stale - ** 03 - entry, fresh - */ - typedef c3_w u3h_v1_slot; - - /* u3h_v1_node: map node. - */ - typedef struct { - c3_w map_w; // bitmap for [sot_w] - u3h_v1_slot sot_w[0]; // filled slots - } u3h_v1_node; - - /* u3h_v1_root: hash root table - */ - typedef struct { - c3_w max_w; // number of cache lines (0 for no trimming) - c3_w use_w; // number of lines currently filled - struct { - c3_w mug_w; // current hash - c3_w inx_w; // index into current hash bucket - c3_o buc_o; // XX remove - } arm_u; // clock arm - u3h_v1_slot sot_w[64]; // slots - } u3h_v1_root; - - /* u3h_v1_buck: bottom bucket. - */ - typedef struct { - c3_w len_w; // length of [sot_w] - u3h_v1_slot sot_w[0]; // filled slots - } u3h_v1_buck; /** HAMT macros. *** *** Coordinate with u3_noun definition! **/ - /* u3h_v1_slot_is_null(): yes iff slot is empty - ** u3h_v1_slot_is_noun(): yes iff slot contains a key/value cell - ** u3h_v1_slot_is_node(): yes iff slot contains a subtable/bucket - ** u3h_v1_slot_is_warm(): yes iff fresh bit is set - ** u3h_v1_slot_to_node(): slot to node pointer + /* u3h_v1_slot_to_node(): slot to node pointer ** u3h_v1_node_to_slot(): node pointer to slot - ** u3h_v1_slot_to_noun(): slot to cell - ** u3h_v1_noun_to_slot(): cell to slot - ** u3h_v1_noun_be_warm(): warm mutant - ** u3h_v1_noun_be_cold(): cold mutant */ -# define u3h_v1_slot_is_null(sot) ((0 == ((sot) >> 30)) ? c3y : c3n) -# define u3h_v1_slot_is_node(sot) ((1 == ((sot) >> 30)) ? c3y : c3n) -# define u3h_v1_slot_is_noun(sot) ((1 == ((sot) >> 31)) ? c3y : c3n) -# define u3h_v1_slot_is_warm(sot) (((sot) & 0x40000000) ? c3y : c3n) # define u3h_v1_slot_to_node(sot) (u3a_into((sot) & 0x3fffffff)) # define u3h_v1_node_to_slot(ptr) (u3a_outa(ptr) | 0x40000000) -# define u3h_v1_noun_be_warm(sot) ((sot) | 0x40000000) -# define u3h_v1_noun_be_cold(sot) ((sot) & ~0x40000000) -# define u3h_v1_slot_to_noun(sot) (0x40000000 | (sot)) -# define u3h_v1_noun_to_slot(som) (u3h_v1_noun_be_warm(som)) /** Functions. *** *** Needs: delete and merge functions; clock reclamation function. **/ - /* u3h_v1_new_cache(): create hashtable with bounded size. - */ - u3p(u3h_v1_root) - u3h_v1_new_cache(c3_w clk_w); - - /* u3h_v1_new(): create hashtable. - */ - u3p(u3h_v1_root) - u3h_v1_new(void); - - /* u3h_v1_put(): insert in hashtable. - ** - ** `key` is RETAINED; `val` is transferred. - */ - void - u3h_v1_put(u3p(u3h_v1_root) har_p, u3_noun key, u3_noun val); - - /* u3h_v1_uni(): unify hashtables, copying [rah_p] into [har_p] - */ - void - u3h_v1_uni(u3p(u3h_v1_root) har_p, u3p(u3h_v1_root) rah_p); - - /* u3h_v1_get(): read from hashtable. - ** - ** `key` is RETAINED; result is PRODUCED. - */ - u3_weak - u3h_v1_get(u3p(u3h_v1_root) har_p, u3_noun key); - - /* u3h_v1_git(): read from hashtable, retaining result. - ** - ** `key` is RETAINED; result is RETAINED. - */ - u3_weak - u3h_v1_git(u3p(u3h_v1_root) har_p, u3_noun key); - - /* u3h_v1_trim_to(): trim to n key-value pairs - */ - void - u3h_v1_trim_to(u3p(u3h_v1_root) har_p, c3_w n_w); - /* u3h_v1_free(): free hashtable. - * XX need to version */ void - u3h_v1_free(u3p(u3h_v1_root) har_p); - - /* u3h_v1_mark(): mark hashtable for gc. - */ - c3_w - u3h_v1_mark(u3p(u3h_v1_root) har_p); + u3h_v1_free(u3p(u3h_root) har_p); /* u3h_v1_rewrite(): rewrite hashtable for compaction. */ void - u3h_v1_rewrite(u3p(u3h_v1_root) har_p); - - /* u3h_v1_count(): count hashtable for gc. - */ - c3_w - u3h_v1_count(u3p(u3h_v1_root) har_p); - - /* u3h_v1_discount(): discount hashtable for gc. - */ - c3_w - u3h_v1_discount(u3p(u3h_v1_root) har_p); + u3h_v1_rewrite(u3p(u3h_root) har_p); /* u3h_v1_walk_with(): traverse hashtable with key, value fn and data * argument; RETAINS. - * XX need to version */ void - u3h_v1_walk_with(u3p(u3h_v1_root) har_p, + 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_v1_root) har_p, void (*fun_f)(u3_noun)); - - /* u3h_v1_take_with(): gain hashtable, copying junior keys - ** and calling [fun_f] on values - */ - u3p(u3h_v1_root) - u3h_v1_take_with(u3p(u3h_v1_root) har_p, u3_funk fun_f); - - /* u3h_v1_take(): gain hashtable, copying junior nouns - */ - u3p(u3h_v1_root) - u3h_v1_take(u3p(u3h_v1_root) har_p); - - /* u3h_v1_wyt(): number of entries - */ - c3_w - u3h_v1_wyt(u3p(u3h_v1_root) har_p); + 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 index 2853954b78..da57d7a4f9 100644 --- a/pkg/noun/v1/jets.c +++ b/pkg/noun/v1/jets.c @@ -1,2343 +1,29 @@ /// @file -#include "jets.h" +#include "pkg/noun/vortex.h" -#include "allocate.h" -#include "v1/hashtable.h" -#include "imprison.h" -#include "jets/k.h" -#include "jets/q.h" -#include "log.h" -#include "manage.h" -#include "nock.h" -#include "options.h" -#include "retrieve.h" -#include "serial.h" -#include "trace.h" -#include "urcrypt/urcrypt.h" -#include "vortex.h" -#include "xtract.h" +#include "pkg/noun/jets.h" +#include "pkg/noun/v1/jets.h" +#include "pkg/noun/v2/jets.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. -**/ - -/* _cj_count(): count and link dashboard entries. -*/ -static c3_w -_cj_count(u3j_core* par_u, u3j_core* dev_u) -{ - c3_w len_l = 0; - c3_w i_w; - - if ( dev_u ) { - for ( i_w = 0; 0 != dev_u[i_w].cos_c; i_w++ ) { - u3j_core* kid_u = &dev_u[i_w]; - - if ( par_u ) { - kid_u->par_u = par_u; - } - len_l += _cj_count(kid_u, kid_u->dev_u); - } - } - return 1 + len_l; -} - -/* _cj_core_loc(): location noun from u3j_core. - */ -static u3_noun -_cj_core_loc(u3_noun pel, u3j_core* cop_u) -{ - c3_w i_w; - u3_noun nam = u3i_string(cop_u->cos_c), - huc = u3_nul, - pat; - - if ( cop_u->huc_u ) { - for ( i_w = 0; 0 != cop_u->huc_u[i_w].nam_c; ++i_w ) { - u3j_hood* huc_u = &(cop_u->huc_u[i_w]); - u3_noun fol = ( c3n == huc_u->kic_o ) - ? u3nc(0, huc_u->axe_l) - : u3nt(9, huc_u->axe_l, u3nc(0, - (0 == huc_u->sax_l) ? 1 : huc_u->sax_l)); - huc = u3kdb_put(huc, u3i_string(huc_u->nam_c), fol); - } - } - - pat = ( 0 == cop_u->axe_l ) - ? u3nt(c3y, c3y, pel) - : ( (3 == cop_u->axe_l) && (c3y == u3h(u3h(pel))) ) - ? u3nt(c3y, c3n, pel) - : u3nt(c3n, cop_u->axe_l, pel); - - return u3nt(pat, nam, huc); -} - -/* _cj_hash(): noun from pasted-in battery hash - */ -static u3_noun -_cj_hash(c3_c* has_c) -{ - c3_w i_w, len_w = strlen(has_c); - if ( 64 != len_w ) { - u3l_log("bash not 64 characters: %s", has_c); - u3_assert(0); - } - u3_assert( 64 == len_w ); - c3_y dig_y[32]; - for ( i_w = 0; i_w < 64; ) { - c3_y hi_y = has_c[i_w++], - lo_y = has_c[i_w++], - hid_y = hi_y >= 'a' ? (hi_y - 'a') + 10 : hi_y - '0', - lod_y = lo_y >= 'a' ? (lo_y - 'a') + 10 : lo_y - '0'; - dig_y[32-(i_w>>1)] = hid_y << 4 | lod_y; - } - u3_noun pro = u3i_bytes(32, dig_y); - return pro; -} - -// in the jam jet file -c3_w* u3qe_jam_buf(u3_noun, c3_w* bit_w); - -/* _cj_bash(): battery hash. RETAIN. - */ -static u3_noun -_cj_bash(u3_noun bat) -{ - if ( u3C.wag_w & u3o_hashless ) { - return u3_nul; - } - - u3_weak pro; - u3a_road* rod_u = u3R; - while ( 1 ) { - pro = u3h_v1_get(rod_u->jed.bas_p, bat); - - if ( u3_none != pro ) { - break; - } - - if ( rod_u->par_p ) { - rod_u = u3to(u3_road, rod_u->par_p); - } - else { - u3i_slab sab_u; - c3_w bit_w = u3s_jam_fib(&sab_u, bat); - c3_w met_w = (bit_w + 0x7) >> 3; - // XX assumes little-endian - // - c3_y* fat_y = sab_u.buf_y; - c3_y dig_y[32]; - urcrypt_shay(fat_y, met_w, dig_y); - - pro = u3i_bytes(32, dig_y); - u3h_v1_put(u3R->jed.bas_p, bat, u3k(pro)); - u3i_slab_free(&sab_u); - break; - } - } - return pro; -} - -/* _cj_mine_par_old(): register hooks and parent location within existing - * axis in ancestor list or u3_none. - */ -static u3_weak -_cj_mine_par_old(u3_noun lan, u3_noun axe, u3_noun pel, u3_noun loc) -{ - u3_noun par; - u3_weak pro; - - if ( u3_nul == lan ) { - pro = u3_none; - u3z(axe); u3z(pel); u3z(loc); - } - else if ( c3y == u3r_sing(axe, u3h(par = u3h(lan))) ) { - u3_noun lol = u3kdb_put(u3k(u3t(par)), pel, loc), - rap = u3nc(axe, lol); - pro = u3nc(rap, u3k(u3t(lan))); - } - else { - u3_weak nex = _cj_mine_par_old(u3k(u3t(lan)), axe, pel, loc); - if ( u3_none == nex ) { - pro = u3_none; - } - else { - pro = u3nc(u3k(par), nex); - } - } - - u3z(lan); - return pro; -} - -/* _cj_mine_par_new(): insert ancestor within lan at sorted index. - */ -static u3_noun -_cj_mine_par_new(u3_noun lan, u3_noun axe, u3_noun pel, u3_noun loc) -{ - u3_weak pro; - - if ( (u3_nul == lan) || (c3y == u3qa_lth(axe, u3h(u3h(lan)))) ) { - u3_noun par = u3nc(axe, u3kdb_put(u3_nul, pel, loc)); - pro = u3nc(par, lan); - } - else { - pro = u3nc(u3k(u3h(lan)), - _cj_mine_par_new(u3k(u3t(lan)), axe, pel, loc)); - u3z(lan); - } - - return pro; -} - -/* _cj_mine_par(): register a location as an ancestor - * in a list of ancestors. - */ -static u3_noun -_cj_mine_par(u3_noun lan, u3_noun axe, u3_noun pel, u3_noun loc) -{ - u3_weak old = _cj_mine_par_old(u3k(lan), u3k(axe), u3k(pel), u3k(loc)); - if ( u3_none != old ) { - u3z(lan); u3z(axe); u3z(pel); u3z(loc); - return old; - } - else { - return _cj_mine_par_new(lan, axe, pel, loc); - } -} - - -/* _cj_gust(): add location to registry. -*/ -static u3_noun -_cj_gust(u3_weak reg, u3_noun axe, u3_noun pel, u3_noun loc) -{ - u3_noun ger; - if ( u3_none == reg ) { - reg = u3nc(u3_nul, u3_nul); - } - - ger = ( 0 == axe ) - ? u3nc(u3kdb_put(u3k(u3h(reg)), pel, loc), u3k(u3t(reg))) - : u3nc(u3k(u3h(reg)), _cj_mine_par(u3k(u3t(reg)), axe, pel, loc)); - - u3z(reg); - return ger; -} - -/* _cj_axis(): axis from formula, or 0. `fol` is RETAINED. -*/ -static c3_l -_cj_axis(u3_noun fol) -{ - u3_noun p_fol, q_fol, r_fol; - - while ( _(u3du(fol)) && (11 == u3h(fol)) ) - { fol = u3t(u3t(fol)); } - - if ( !_(u3r_trel(fol, &p_fol, &q_fol, &r_fol)) ) { - if ( !_(u3r_cell(fol, &p_fol, &q_fol)) || - (0 != p_fol) || - (!_(u3a_is_cat(q_fol))) ) - { - u3l_log("axis: bad a"); - return 0; - } - return q_fol; - } - else { - if ( 9 != p_fol ) - { u3l_log("axis: bad b"); return 0; } - if ( !_(u3a_is_cat(q_fol)) ) - { u3l_log("axis: bad c"); return 0; } - if ( !_(u3du(r_fol)) || (0 != u3h(r_fol)) || (1 != u3t(r_fol)) ) - { u3l_log("axis: bad d"); return 0; } - - return q_fol; - } -} - -/* _cj_warm_hump(): generate axis-to-arm map. RETAIN. -*/ -static u3_noun -_cj_warm_hump(c3_l jax_l, u3_noun huc) -{ - u3_noun hap = u3_nul; - u3j_core* cop_u; - - /* Compute axes of all correctly declared arms. - */ - if ( jax_l && (cop_u = &u3D.ray_u[jax_l])->arm_u ) { - u3j_harm* jet_u; - c3_l i_l; - - for ( i_l = 0; (jet_u = &cop_u->arm_u[i_l])->fcs_c; i_l++ ) { - c3_l axe_l = 0; - - if ( '.' == *(jet_u->fcs_c) ) { - c3_d axe_d = 0; - - if ( (1 != sscanf(jet_u->fcs_c+1, "%" SCNu64, &axe_d)) || - axe_d >> 32ULL || - ((1 << 31) & (axe_l = (c3_w)axe_d)) || - (axe_l < 2) ) - { - u3l_log("jets: activate: bad fcs %s", jet_u->fcs_c); - } - } - else { - u3_noun nam = u3i_string(jet_u->fcs_c); - u3_noun fol = u3kdb_get(u3k(huc), nam); - - if ( u3_none == fol ) { - u3l_log("jets: activate: bad fcs %s", jet_u->fcs_c); - } - else { - axe_l = _cj_axis(fol); - u3z(fol); - } - } - if ( 0 != axe_l ) { - hap = u3kdb_put(hap, axe_l, i_l); - } - } - } - return hap; -} - -/* _cj_install(): install dashboard entries. -*/ -static c3_w -_cj_install(u3j_core* ray_u, c3_w jax_l, u3_noun pel, u3_noun lab, u3j_core* dev_u) -{ - c3_w i_w; - u3_assert(u3R == &(u3H->rod_u)); - - if ( dev_u ) { - for ( i_w = 0; 0 != dev_u[i_w].cos_c; i_w++ ) { - u3j_core* kid_u = &dev_u[i_w]; - u3_noun loc = _cj_core_loc(u3k(pel), kid_u), - bal = u3nc(u3k(u3h(u3t(loc))), u3k(lab)); - - kid_u->jax_l = jax_l; - ray_u[jax_l] = *kid_u; - - if ( kid_u->bas_u ) { - c3_w j_w; - for ( j_w = 0; 0 != kid_u->bas_u[j_w]; j_w++ ) { - u3_noun key = _cj_hash(kid_u->bas_u[j_w]), - hot = u3h_v1_get(u3R->jed.hot_p, key), - old = ( u3_none == hot ) ? u3_none : u3k(u3h(hot)), - reg = _cj_gust(old, kid_u->axe_l, u3k(pel), u3k(loc)), - huc = u3t(u3t(loc)), - hap = _cj_warm_hump(jax_l, huc), - toh = u3nq(reg, jax_l, hap, u3k(bal)); - - u3h_v1_put(u3R->jed.hot_p, key, toh); - u3z(key); u3z(hot); - } - } - - jax_l = _cj_install(ray_u, ++jax_l, loc, bal, kid_u->dev_u); - } - } - u3z(pel); - u3z(lab); - return jax_l; -} - -#if 0 -/* _cj_by_gut(): (~(get by a) b), unifying; RETAINS a, b, AND result. -*/ -static u3_weak -_cj_by_gut(u3_noun a, u3_noun b) -{ - if ( u3_nul == a ) { - return u3_none; - } - else { - u3_noun l_a, n_a, r_a; - u3_noun pn_a, qn_a; - - u3x_trel(a, &n_a, &l_a, &r_a); - u3x_cell(n_a, &pn_a, &qn_a); - { - if ( (c3y == u3r_sing(b, pn_a)) ) { - return qn_a; - } - else { - if ( c3y == u3qc_gor(b, pn_a) ) { - return _cj_by_gut(l_a, b); - } - else return _cj_by_gut(r_a, b); - } - } - } -} -#endif - -/* _cj_chum(): decode chum as string. -*/ -static c3_c* -_cj_chum(u3_noun chu) -{ - if ( _(u3ud(chu)) ) { - return u3r_string(chu); - } - else { - u3_noun h_chu = u3h(chu); - u3_noun t_chu = u3t(chu); - - if ( !_(u3a_is_cat(t_chu)) ) { - return 0; - } else { - c3_c* h_chu_c = u3r_string(h_chu); - c3_c buf[33]; - - memset(buf, 0, 33); - snprintf(buf, 32, "%s%d", h_chu_c, t_chu); - - c3_free(h_chu_c); - return strdup(buf); - } - } -} - -/* _cj_je_fsck: fsck:je, or none. -*/ -static u3_noun -_cj_je_fsck(u3_noun clu) -{ - u3_noun p_clu, q_clu, r_clu; - u3_noun huk; - c3_c* nam_c; - c3_l axe_l; - - if ( c3n == u3r_trel(clu, &p_clu, &q_clu, &r_clu) ) { - u3z(clu); return u3_none; - } - if ( 0 == (nam_c = _cj_chum(p_clu)) ) { - u3z(clu); return u3_none; - } - while ( _(u3du(q_clu)) && (11 == u3h(q_clu)) ) { - q_clu = u3t(u3t(q_clu)); - } - if ( !_(u3du(q_clu)) ) { - u3z(clu); c3_free(nam_c); return u3_none; - } - - if ( (1 == u3h(q_clu)) && (0 == u3t(q_clu)) ) { - axe_l = 0; - } - else { - if ( (0 != u3h(q_clu)) || !_(u3a_is_cat(axe_l = u3t(q_clu))) ) { - u3z(clu); c3_free(nam_c); return u3_none; - } - } - - { - huk = 0; - - while ( _(u3du(r_clu)) ) { - u3_noun ir_clu, tr_clu, pir_clu, qir_clu; - - if ( (c3n == u3r_cell(r_clu, &ir_clu, &tr_clu)) || - (c3n == u3r_cell(ir_clu, &pir_clu, &qir_clu)) || - (c3n == u3ud(pir_clu)) ) - { - u3z(huk); u3z(clu); c3_free(nam_c); return u3_none; - } - huk = u3kdb_put(huk, u3k(pir_clu), u3k(qir_clu)); - r_clu = tr_clu; - } - } - u3z(clu); - - { - u3_noun pro = u3nt(u3i_string(nam_c), axe_l, huk); - c3_free(nam_c); - return pro; - } -} - -/* _cj_find_cold(): search cold state for `bat`s [bash registry]. - * RETAIN. - */ -static u3_weak -_cj_find_cold(u3_noun bat) -{ - u3a_road* rod_u = u3R; - - while ( 1 ) { - u3_weak bar = u3h_v1_get(rod_u->jed.cod_p, bat); - - if ( u3_none != bar ) { - return bar; - } - - if ( rod_u->par_p ) { - rod_u = u3to(u3_road, rod_u->par_p); - } - else return u3_none; - } -} - -/* _cj_find_warm(): search warm state for `loc`s activation. - * RETAIN. - */ -static u3_weak -_cj_find_warm(u3_noun loc) -{ - u3a_road* rod_u = u3R; - - while ( 1 ) { - u3_weak ank = u3h_v1_get(rod_u->jed.war_p, loc); - - if ( u3_none != ank ) { - return ank; - } - - if ( rod_u->par_p ) { - rod_u = u3to(u3_road, rod_u->par_p); - } - else return u3_none; - } -} - -static u3_weak _cj_spot(u3_noun cor, u3_weak* bas); - -/* _cj_reg_find(): locate core within registry. RETAIN. - */ -static u3_weak -_cj_reg_find(u3_noun reg, u3_noun cor) -{ - u3_noun rut = u3h(reg), - pas = u3t(reg), - rum = u3qdb_get(rut, u3t(cor)); - if ( u3_nul != rum ) { - u3_noun loc = u3k(u3t(rum)); - u3z(rum); - return loc; - } - else { - while ( u3_nul != pas ) { - u3_noun pap = u3h(pas), - axe = u3h(pap), - lol = u3t(pap); - u3_weak par = u3r_at(axe, cor), - pel; - if ( u3_none != par ) { - pel = _cj_spot(par, NULL); - if ( u3_none != pel ) { - u3_noun nit = u3qdb_get(lol, pel); - u3z(pel); - if ( u3_nul != nit ) { - u3_noun loc = u3k(u3t(nit)); - u3z(nit); - return loc; - } - } - } - pas = u3t(pas); - } - return u3_none; - } -} - -/* _cj_jit(): generate arbitrary warm jet-associated data. RETAIN. -*/ -static u3_noun -_cj_jit(c3_l jax_l, u3_noun bat) -{ - return u3_nul; -} - -/* _cj_loc_axe(): axis-within-core from location (0 for root). RETAIN. - */ -static u3_noun -_cj_loc_axe(u3_noun loc) -{ - u3_noun pat = u3h(loc); - return ( c3n == u3h(pat) ) - ? u3k(u3h(u3t(pat))) - : (c3y == u3h(u3t(pat))) ? 0 : 3; -} - -/* _cj_loc_pel(): parent location (or root noun, if root) of loc. RETAIN. - */ -static u3_noun -_cj_loc_pel(u3_noun loc) -{ - return u3k(u3t(u3t(u3h(loc)))); -} - -/* _cj_spot_cold(): spot, cold dashboard only. *bar is set to - * the [bash registry] found for battery. RETAIN. - */ -static u3_weak -_cj_spot_cold(u3_noun cor, u3_weak* bar) -{ - *bar = _cj_find_cold(u3h(cor)); - if ( u3_none == *bar ) { - return u3_none; - } - else { - return _cj_reg_find(u3t(*bar), cor); - } -} - -/* _cj_spot_hot(): try to locate core by hot dashboard. if found, - * the activation (warm state) is returned and the - * location is produced at *loc. RETAIN. - */ -static u3_weak -_cj_spot_hot(u3_noun cor, u3_noun bas, u3_noun* loc) -{ - u3_noun bat = u3h(cor); - u3_weak act = u3_none, - hot = u3h_v1_get(u3H->rod_u.jed.hot_p, bas); - if ( u3_none != hot ) { - u3_noun reg, jax, hap, bal; - c3_l jax_l; - u3x_qual(hot, ®, &jax, &hap, &bal); - jax_l = (c3_l) jax; - if ( u3_none != (*loc = _cj_reg_find(reg, cor)) ) { - act = u3nq(jax_l, u3k(hap), u3k(bal), _cj_jit(jax_l, bat)); - } - u3z(hot); - } - return act; -} - -/* _cj_spot(): find location of cor. expensive. RETAIN. - * bas is complicated to make it easy to cache bashes. - * you can safely ignore it by passing NULL. Otherwise, - * if it points to u3_none, and no location is found, - * a bash will be PRODUCED there. if it contains a bash, - * that will be used instead of calling _cj_bash. - */ -static u3_weak -_cj_spot(u3_noun cor, u3_weak* bas) -{ - u3_weak bak = u3_none, - bar = u3_none, - reg = u3_none, - loc = _cj_spot_cold(cor, &bar); - - if ( NULL == bas ) { - bas = &bak; - } - - if ( u3_none != bar ) { - if ( (u3_none == *bas) ) { - *bas = u3k(u3h(bar)); - } - reg = u3k(u3t(bar)); - u3z(bar); - } - - if ( u3_none == loc ) { - if ( u3_none == *bas ) { - *bas = _cj_bash(u3h(cor)); - } - - if ( !(u3C.wag_w & u3o_hashless) ) { - u3_weak act = _cj_spot_hot(cor, *bas, &loc); - if ( u3_none != act ) { - reg = _cj_gust(reg, _cj_loc_axe(loc), _cj_loc_pel(loc), u3k(loc)); - u3h_v1_put(u3R->jed.cod_p, u3h(cor), u3nc(u3k(*bas), u3k(reg))); - /* caution: could overwrites old value, debug batteries etc. - ** old value contains old _cj_jit (from different - ** battery). if we change jit to (map battery *), - ** will need to merge with that map here. - */ - u3h_v1_put(u3R->jed.war_p, loc, act); - } - } - } - if ( u3_none != bak ) { - u3z(bak); - } - if ( u3_none != reg ) { - u3z(reg); - } - return loc; -} - -/* _cj_cast(): create a u3j_fink that can be used to efficiently verify - * that another core is located where this one is. RETAIN. - */ -static u3p(u3j_fink) -_cj_cast(u3_noun cor, u3_noun loc) -{ - c3_w i_w = 0; - u3_noun j, par, bat, dyn, pax, - rev = u3_nul, - pat = u3h(loc); - u3j_fink* fin_u; - - while ( c3n == u3h(pat) ) { - bat = u3h(cor); - dyn = u3t(pat); - pax = u3h(dyn); - loc = u3t(dyn); - pat = u3h(loc); - rev = u3nc(u3nc(u3k(bat), u3k(pax)), rev); - // pax already known-valid - cor = u3r_at(pax, cor); - ++i_w; - } - - fin_u = u3a_walloc(c3_wiseof(u3j_fink) + - (i_w * c3_wiseof(u3j_fist))); - fin_u->len_w = i_w; - fin_u->sat = u3k(cor); - for ( j = rev; i_w-- > 0; j = u3t(j) ) { - u3j_fist* fis_u = &(fin_u->fis_u[i_w]); - par = u3h(j); - fis_u->bat = u3k(u3h(par)); - fis_u->pax = u3k(u3t(par)); - } - u3z(rev); - u3_assert( u3_nul == j ); - - return u3of(u3j_fink, fin_u); -} - -/* _cj_fine(): check that a core matches a u3j_fink. RETAIN. - */ -static c3_o -_cj_fine(u3_noun cor, u3p(u3j_fink) fin_p) -{ - u3j_fink* fin_u = u3to(u3j_fink, fin_p); - c3_w i_w; - for ( i_w = 0; i_w < fin_u->len_w; ++i_w ) { - u3j_fist* fis_u = &(fin_u->fis_u[i_w]); - if ( c3n == u3r_sing(fis_u->bat, u3h(cor)) ) { - return c3n; - } - else { - cor = u3r_at(fis_u->pax, cor); - } - } - return u3r_sing(fin_u->sat, cor); -} - -/* _cj_nail(): resolve hot state for arm at axis within cores located - * at loc. a label will be PRODUCED at *lab, unconditionally. - * Arguments are RETAINED. Return value is yes if a jet driver - * is present. - */ -static c3_o -_cj_nail(u3_noun loc, u3_noun axe, - u3_noun* lab, u3j_core** cop_u, u3j_harm** ham_u) -{ - c3_o ret_o; - u3_noun jax, hap, bal, jit; - u3_weak act; - act = _cj_find_warm(loc); - u3_assert(u3_none != act); - u3x_qual(act, &jax, &hap, &bal, &jit); - - *lab = u3k(bal); - if ( 0 == jax ) { - ret_o = c3n; - } - else { - u3_weak inx = u3kdb_get(u3k(hap), u3k(axe)); - if ( u3_none == inx ) { - ret_o = c3n; - } - else { - c3_l jax_l = jax, - inx_l = inx; - *cop_u = &(u3D.ray_u[jax_l]); - *ham_u = &((*cop_u)->arm_u[inx_l]); - ret_o = c3y; - } - } - - u3z(act); - return ret_o; -} - -/* _cj_hot_mean(): in parent, declare a core. RETAINS. -*/ -static c3_l -_cj_hot_mean(c3_l par_l, u3_noun nam) -{ - u3j_core* par_u; - u3j_core* dev_u; - - if ( 0 != par_l ) { - par_u = &u3D.ray_u[par_l]; - dev_u = par_u->dev_u; - } - else { - par_u = 0; - dev_u = u3D.dev_u; - } - - { - c3_w i_l = 0; - u3j_core* cop_u; - - while ( (cop_u = &dev_u[i_l])->cos_c ) { - if ( _(u3r_sing_c(cop_u->cos_c, nam)) ) { -#if 0 - u3l_log("hot: bound jet %d/%s/%s/", - cop_u->jax_l, - cop_u->cos_c, - par_u ? par_u->cos_c : "~"); -#endif - return cop_u->jax_l; - } - i_l++; - } - } - return 0; -} - -/* u3j_boot(): initialize jet system. -*/ -c3_w -u3j_boot(c3_o nuu_o) -{ - u3_assert(u3R == &(u3H->rod_u)); - - u3D.len_l = _cj_count(0, u3D.dev_u); - u3D.all_l = (2 * u3D.len_l) + 1024; // horrid heuristic - - u3D.ray_u = c3_malloc(u3D.all_l * sizeof(u3j_core)); - memset(u3D.ray_u, 0, (u3D.all_l * sizeof(u3j_core))); - - if ( c3n == nuu_o ) { - u3h_v1_free(u3R->jed.hot_p); - } - u3R->jed.hot_p = u3h_v1_new(); - - return _cj_install(u3D.ray_u, 1, - (c3_l) (long long) u3D.dev_u[0].par_u, - u3_nul, - u3D.dev_u); -} - -/* _cj_soft(): kick softly by arm axis. -*/ -static u3_noun -_cj_soft(u3_noun cor, u3_noun axe) -{ - u3_noun arm = u3x_at(axe, cor); - - return u3n_nock_on(cor, u3k(arm)); -} - - void - find_error(u3_noun cor, - u3_noun old, - u3_noun new); - -/* _cj_kick_z(): try to kick by jet. If no kick, produce u3_none. -** -** `cor` is RETAINED iff there is no kick, TRANSFERRED if one. -** `axe` is RETAINED. -*/ -static u3_weak -_cj_kick_z(u3_noun cor, u3j_core* cop_u, u3j_harm* ham_u, u3_atom axe) -{ - if ( 0 == ham_u->fun_f ) { - return u3_none; - } - - if ( !_(ham_u->liv) ) { - return u3_none; - } - else { -#ifdef U3_MEMORY_DEBUG - c3_w cod_w; - - { - char soc_c[5]; - - memset(soc_c, 0, 5); - strncpy(soc_c, cop_u->cos_c, 4); - soc_c[4] = 0; - cod_w = u3i_string(soc_c); - cod_w = u3a_lush(cod_w); - } -#endif - - if ( _(ham_u->ice) ) { - u3_weak pro = ham_u->fun_f(cor); - -#ifdef U3_MEMORY_DEBUG - u3a_lop(cod_w); -#endif - if ( u3_none != pro ) { - u3z(cor); - return pro; - } - } - else { - u3_weak pro, ame; - - ham_u->ice = c3y; - pro = ham_u->fun_f(cor); - ham_u->ice = c3n; - -#ifdef U3_MEMORY_DEBUG - u3a_lop(cod_w); -#endif - if ( u3_none == pro ) { - u3z(cor); - return pro; - } - ham_u->liv = c3n; - ame = _cj_soft(cor, axe); - ham_u->liv = c3y; - - if ( c3n == u3r_sing(ame, pro) ) { - u3l_log("test: %s %s: mismatch: good %x, bad %x", - cop_u->cos_c, - (!strcmp(".2", ham_u->fcs_c)) ? "$" : ham_u->fcs_c, - u3r_mug(ame), - u3r_mug(pro)); - ham_u->liv = c3n; - - return u3m_bail(c3__fail); - } - else { - -#if 0 - u3l_log("test: %s %s", - cop_u->cos_c, - (!strcmp(".2", ham_u->fcs_c)) ? "$" : ham_u->fcs_c); -#endif - u3z(ame); - return pro; - } - } - return u3_none; - } -} - -/* _cj_hook_in(): execute hook from core, or fail. -*/ -static u3_noun -_cj_hook_in(u3_noun cor, - const c3_c* tam_c, - c3_o jet_o) -{ - u3_weak loc, col; - u3_noun roc, tem, got, pat, nam, huc; - - if ( c3n == u3du(cor) ) { - u3l_log("_cj_hook_in failure: c3n == u3du(cor)"); - return u3m_bail(c3__fail); - } - - loc = _cj_spot(cor, NULL); - if ( u3_none == loc ) { - u3l_log("_cj_hook_in failure: u3_none == loc"); - return u3m_bail(c3__fail); - } - - tem = u3i_string(tam_c); - while ( 1 ) { - u3x_trel(loc, &pat, &nam, &huc); - got = u3qdb_get(huc, tem); - if ( u3_nul != got ) { - c3_l axe_l; - u3_noun pro, fol; - u3j_core* cop_u; - - u3z(tem); - fol = u3k(u3t(got)); - u3z(got); - axe_l = _cj_axis(fol); - if ( 0 == axe_l ) { - u3t_off(glu_o); - pro = u3n_nock_on(cor, fol); - u3t_on(glu_o); - } - else { - c3_l jax_l, inx_l; - u3_noun hap, act; - - u3z(fol); - act = _cj_find_warm(loc); - jax_l = u3h(act); - hap = u3h(u3t(act)); - cop_u = &u3D.ray_u[jax_l]; - - // Tricky: the above case would work here too, but would - // disable jet_o and create some infinite recursions. - // - u3t_off(glu_o); - if ( (c3n == jet_o) || - (u3_none == (inx_l = u3kdb_get(u3k(hap), axe_l))) || - (u3_none == (pro = _cj_kick_z(cor, - cop_u, - &cop_u->arm_u[inx_l], - axe_l))) ) { - pro = u3n_nock_on(cor, u3k(u3x_at(axe_l, cor))); - } - u3t_on(glu_o); - u3z(act); - } - u3z(loc); - return pro; - } - else if ( c3n == u3h(pat) ) { - u3_noun dyn = u3t(pat), - axe = u3h(dyn), - pel = u3t(dyn); - // axe already known-valid - roc = u3k(u3r_at(axe, cor)); - u3z(cor); - cor = roc; - col = u3k(pel); - u3z(loc); - loc = col; - } - else { - u3_noun sat = u3t(pat); - if ( c3y == u3h(sat) ) { - u3l_log("_cj_hook_in failure: c3y == u3h(sat)"); - return u3m_bail(c3__fail); - } - else { - col = u3k(u3t(sat)); - u3z(loc); - loc = col; - roc = u3k(u3t(cor)); - u3z(cor); - cor = roc; - } - } - } -} - -/* u3j_soft(): execute soft hook. -*/ -u3_noun -u3j_soft(u3_noun cor, - const c3_c* tam_c) -{ - u3_noun pro; - u3t_on(glu_o); - pro = _cj_hook_in(cor, tam_c, c3n); - u3t_off(glu_o); - return pro; -} - -/* u3j_hook(): execute hook from core, or fail. -*/ -u3_noun -u3j_hook(u3_noun cor, - const c3_c* tam_c) -{ - u3_noun pro; - u3t_on(glu_o); - pro = _cj_hook_in(cor, tam_c, c3y); - u3t_off(glu_o); - return pro; -} - -/* _cj_prog(): stop tracing glu and find a nock program - */ -static u3p(u3n_prog) -_cj_prog(u3_weak loc, u3_noun fol) -{ - u3p(u3n_prog) pog_p; - u3t_off(glu_o); - pog_p = u3n_find((loc == u3_none ? u3_nul : loc), fol); - u3t_on(glu_o); - return pog_p; -} - -/* cj_hank_find(): find cached hook information, keyed by arbitrary - * prefix and term cords. RETAIN. - */ -static _cj_hank* -_cj_hank_find(u3_noun pre, u3_noun tam) -{ - u3_noun key = u3nc(u3k(pre), u3k(tam)); - u3_noun got = u3h_v1_git(u3R->jed.han_p, key); - - if ( u3_none != got ) { - u3z(key); - return u3to(_cj_hank, got); - } - else { - _cj_hank* new_u = u3a_walloc(c3_wiseof(_cj_hank)); - u3a_road* rod_u = u3R; - - while ( rod_u->par_p && u3_none == got ) { - rod_u = u3to(u3a_road, rod_u->par_p); - got = u3h_v1_git(rod_u->jed.han_p, key); - } - - if ( u3_none == got ) { - new_u->hax = u3_none; - } - else { - _cj_hank* old_u = u3to(_cj_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) - // - u3j_site_take(&(new_u->sit_u), &(old_u->sit_u)); - } - } - - u3h_v1_put(u3R->jed.han_p, key, u3of(_cj_hank, new_u)); - u3z(key); - return new_u; - } -} - -/* _cj_hank_fine(): check that cached hook information is valid - * for given core. *inn will point to the hooked - * core on return if valid. RETAIN. - */ -static c3_o -_cj_hank_fine(_cj_hank* han_u, u3_noun cor, u3_noun *inn) -{ - u3_noun hax = han_u->hax; - if ( u3_none == hax ) { - return c3n; - } - else { - *inn = u3r_at(hax, cor); - if ( u3_none == *inn ) { - return c3n; - } - else { - u3j_site* sit_u = &(han_u->sit_u); - u3_assert(u3_none != sit_u->loc); - return _cj_fine(*inn, sit_u->fin_p); - } - } -} - -/* _cj_hank_lose(): release memory maintained in a hook cache. -*/ -static void -_cj_hank_lose(_cj_hank* han_u) -{ - if ( u3_none != han_u->hax ) { - u3z(han_u->hax); - u3j_site_lose(&(han_u->sit_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) -{ - u3_weak loc, col; - u3_noun got, pat, nam, huc; - u3_noun hax = 1; - u3j_site* sit_u = &(han_u->sit_u); - - if ( c3n == u3du(cor) ) { - u3l_log("fail in _cj_hank_fill (c3n == u3du(cor))"); - return u3m_bail(c3__fail); - } - - sit_u->bas = u3_none; - if ( u3_none == (col = loc = _cj_spot(cor, NULL)) ) { - u3l_log("fail in _cj_hank_fill (_cj_spot(cor, NULL))"); - return u3m_bail(c3__fail); - } - - while ( 1 ) { - u3x_trel(loc, &pat, &nam, &huc); - got = u3qdb_get(huc, tam); - if ( u3_nul != got ) { - u3_noun fol = u3k(u3t(got)); - u3z(got); - sit_u->bat = u3k(u3h(cor)); - sit_u->loc = u3k(loc); - sit_u->fin_p = _cj_cast(cor, loc); - sit_u->fon_o = c3y; - if ( 0 == (sit_u->axe = _cj_axis(fol)) ) { - sit_u->jet_o = c3n; - sit_u->pog_p = _cj_prog(loc, fol); - } - else { - // loc already known-valid - han_u->sit_u.pog_p = _cj_prog(loc, u3r_at(sit_u->axe, cor)); - han_u->sit_u.jet_o = _cj_nail(loc, sit_u->axe, - &(sit_u->lab), &(sit_u->cop_u), &(sit_u->ham_u)); - } - u3z(fol); - u3z(col); - han_u->hax = hax; - return cor; - } - else if ( c3n == u3h(pat) ) { - u3_noun dyn = u3t(pat), - axe = u3h(dyn), - xah; - // axe already known-valid - cor = u3r_at(axe, cor); - loc = u3t(dyn); - xah = u3qc_peg(axe, hax); - u3z(hax); - hax = xah; - } - else { - u3_noun sat = u3t(pat); - if ( c3y == u3h(sat) ) { - u3l_log("fail in _cj_hank_fill (c3y == u3h(sat))"); - return u3m_bail(c3__fail); - } - else { - u3_noun xah; - cor = u3t(cor); - loc = u3t(sat); - xah = u3qc_peg(3, hax); - u3z(hax); - hax = xah; - } - } - } -} - -/* _cj_sink(): kick by nock. - */ -static u3_noun -_cj_sink(u3_noun cor, u3_noun axe) -{ - u3_noun fol = u3x_at(axe, cor); - u3z(axe); - return u3n_nock_on(cor, u3k(fol)); -} - -/* u3j_kick(): new kick. -** -** `axe` is RETAINED by the caller; `cor` is RETAINED iff there -** is no kick, TRANSFERRED if one. -*/ -u3_weak -u3j_kick(u3_noun cor, u3_noun axe) -{ - u3t_on(glu_o); - u3_weak loc = _cj_spot(cor, NULL); - if ( u3_none == loc ) { - u3t_off(glu_o); - return u3_none; - } - else { - u3_weak act = _cj_find_warm(loc); - u3z(loc); - if ( u3_none == act ) { - u3t_off(glu_o); - return u3_none; - } - else { - c3_l jax_l; - u3_noun hap, bal, jit, inx; - - u3x_qual(act, &jax_l, &hap, &bal, &jit); - - if ( u3_none == (inx = u3kdb_get(u3k(hap), u3k(axe))) ) { - u3t_off(glu_o); - { - c3_o pof_o = __(u3C.wag_w & u3o_debug_cpu); - c3_o trc_o = __(u3C.wag_w & u3o_trace); - - if ( _(pof_o) ) { - pof_o = u3t_come(bal); - } - if ( _(trc_o) ) { - trc_o = u3t_nock_trace_push(bal); - } - u3z(act); - if ( _(pof_o) || _(trc_o) ) { - u3_noun pro = _cj_sink(cor, u3k(axe)); - - if (_(pof_o)) { - u3t_flee(); - } - if ( _(trc_o) ) { - u3t_nock_trace_pop(); - } - return pro; - } - else { - return u3_none; - } - } - } - else { - u3j_core* cop_u = &u3D.ray_u[jax_l]; - c3_l inx_l = inx; - u3j_harm* ham_u = &cop_u->arm_u[inx_l]; - c3_o pof_o = __(u3C.wag_w & u3o_debug_cpu); - c3_o trc_o = __(u3C.wag_w & u3o_trace); - u3_noun pro; - - if ( _(pof_o) ) { - pof_o = u3t_come(bal); - } - if ( _(trc_o) ) { - trc_o = u3t_nock_trace_push(bal); - } - u3z(act); - u3t_off(glu_o); - pro = _cj_kick_z(cor, cop_u, ham_u, axe); - - if ( u3_none == pro ) { - if ( _(pof_o) || _(trc_o) ) { - pro = _cj_sink(cor, u3k(axe)); - - if (_(pof_o)) { - u3t_flee(); - } - if ( _(trc_o) ) { - u3t_nock_trace_pop(); - } - } - return pro; - } - else { - if ( _(pof_o) ) { - u3t_flee(); - } - if ( _(trc_o) ) { - u3t_nock_trace_pop(); - } - return pro; - } - } - } - } -} - -/* _cj_fink_take(): copy u3j_fink from junior road. -*/ -static u3j_fink* -_cj_fink_take(u3j_fink* jun_u) -{ - c3_w i_w, len_w = jun_u->len_w; - u3j_fink* fin_u = u3a_walloc(c3_wiseof(u3j_fink) + - (len_w * c3_wiseof(u3j_fist))); - - fin_u->len_w = len_w; - fin_u->sat = u3a_take(jun_u->sat); - for ( i_w = 0; i_w < len_w; ++i_w ) { - u3j_fist* fis_u = &(fin_u->fis_u[i_w]); - u3j_fist* sif_u = &(jun_u->fis_u[i_w]); - fis_u->bat = u3a_take(sif_u->bat); - fis_u->pax = u3a_take(sif_u->pax); - } - return fin_u; -} - -/* _cj_fink_free(): lose and free everything in a u3j_fink. -*/ -static void -_cj_fink_free(u3p(u3j_fink) fin_p) -{ - c3_w i_w; - u3j_fink* fin_u = u3to(u3j_fink, fin_p); - u3z(fin_u->sat); - for ( i_w = 0; i_w < fin_u->len_w; ++i_w ) { - u3j_fist* fis_u = &(fin_u->fis_u[i_w]); - u3z(fis_u->bat); - u3z(fis_u->pax); - } - u3a_wfree(fin_u); -} - -/* u3j_rite_take(): copy junior rite references. [dst_u] is uninitialized -*/ -void -u3j_rite_take(u3j_rite* dst_u, u3j_rite* src_u) -{ - if ( u3_none == src_u->clu ) { - dst_u->clu = u3_none; - dst_u->fin_p = 0; - dst_u->own_o = c3n; - } - else { - dst_u->clu = u3a_take(src_u->clu); - dst_u->own_o = src_u->own_o; - dst_u->fin_p = ( c3n == src_u->own_o ) - ? src_u->fin_p - : u3of(u3j_fink, _cj_fink_take(u3to(u3j_fink, src_u->fin_p))); - } -} - -/* u3j_rite_merge(): copy rite references from src_u to dst_u, -** losing old references -*/ -void -u3j_rite_merge(u3j_rite* dst_u, u3j_rite* src_u) -{ - if ( u3_none != src_u->clu ) { - if ( u3_none != dst_u->clu ) { - u3z(dst_u->clu); - } - - dst_u->clu = src_u->clu; - - if ( dst_u->fin_p != src_u->fin_p ) { - if ( c3y == dst_u->own_o ) { - _cj_fink_free(dst_u->fin_p); - } - - dst_u->fin_p = src_u->fin_p; - dst_u->own_o = src_u->own_o; - } - } -} - -/* u3j_site_take(): copy junior site references. [dst_u] is uninitialized -*/ -void -u3j_site_take(u3j_site* dst_u, u3j_site* src_u) -{ - dst_u->axe = u3a_take(src_u->axe); - dst_u->bat = u3_none; - dst_u->bas = u3_none; - dst_u->pog_p = 0; - - if ( u3_none == src_u->loc ) { - dst_u->loc = u3_none; - dst_u->lab = u3_none; - dst_u->jet_o = c3n; - dst_u->cop_u = NULL; - dst_u->ham_u = NULL; - dst_u->fin_p = 0; - dst_u->fon_o = c3n; - } - else { - dst_u->loc = u3a_take(src_u->loc); - dst_u->lab = u3a_take(src_u->lab); - dst_u->jet_o = src_u->jet_o; - dst_u->cop_u = src_u->cop_u; - dst_u->ham_u = src_u->ham_u; - - if ( c3y == src_u->fon_o ) { - dst_u->fin_p = u3of(u3j_fink, _cj_fink_take(u3to(u3j_fink, src_u->fin_p))); - dst_u->fon_o = c3y; - } - else { - dst_u->fin_p = src_u->fin_p; - dst_u->fon_o = c3n; - } - } -} - -/* u3j_site_merge(): copy site references from src_u to dst_u, -** losing old references -*/ -void -u3j_site_merge(u3j_site* dst_u, u3j_site* src_u) -{ - u3z(dst_u->axe); - dst_u->axe = src_u->axe; - - if ( u3_none != src_u->loc ) { - u3z(dst_u->loc); - u3z(dst_u->lab); - dst_u->loc = src_u->loc; - dst_u->lab = src_u->lab; - dst_u->cop_u = src_u->cop_u; - dst_u->ham_u = src_u->ham_u; - dst_u->jet_o = src_u->jet_o; - - if ( dst_u->fin_p != src_u->fin_p ) { - if ( c3y == dst_u->fon_o ) { - _cj_fink_free(dst_u->fin_p); - } - - dst_u->fin_p = src_u->fin_p; - dst_u->fon_o = src_u->fon_o; - } - } -} - -/* u3j_site_ream(): refresh u3j_site after restoring from checkpoint -*/ -void -u3j_site_ream(u3j_site* sit_u) -{ - if ( u3_none != sit_u->loc ) { - u3z(sit_u->lab); - sit_u->jet_o = _cj_nail(sit_u->loc, sit_u->axe, - &(sit_u->lab), &(sit_u->cop_u), &(sit_u->ham_u)); - } -} - -/* _cj_site_lock(): ensure site has a valid program pointer - */ -static void -_cj_site_lock(u3_noun loc, u3_noun cor, u3j_site* sit_u) -{ - if ( (u3_none != sit_u->bat) && - (c3y == u3r_sing(sit_u->bat, u3h(cor))) ) { - return; - } - sit_u->pog_p = _cj_prog(loc, u3x_at(sit_u->axe, cor)); - if ( u3_none != sit_u->bat ) { - u3z(sit_u->bat); - } - sit_u->bat = u3k(u3h(cor)); -} +#include "pkg/noun/v1/hashtable.h" -/* _cj_burn(): stop tracing glu and call a nock program - */ -static u3_noun -_cj_burn(u3p(u3n_prog) pog_p, u3_noun cor) -{ - u3_noun pro; - u3t_off(glu_o); - pro = u3n_burn(pog_p, cor); - u3t_on(glu_o); - return pro; -} - -/* _cj_site_kick_hot(): execute site's kick on located core -** (no validity checks). -*/ -static u3_weak -_cj_site_kick_hot(u3_noun loc, u3_noun cor, u3j_site* sit_u, c3_o lok_o) -{ - u3_weak pro = u3_none; - c3_o jet_o = sit_u->jet_o; - c3_o pof_o = __(u3C.wag_w & u3o_debug_cpu); - c3_o trc_o = __(u3C.wag_w & u3o_trace); - - if ( c3n == pof_o && c3n == trc_o ) { - if ( c3y == jet_o ) { - u3t_off(glu_o); - pro = _cj_kick_z(cor, sit_u->cop_u, sit_u->ham_u, sit_u->axe); - u3t_on(glu_o); - } - if ( u3_none == pro ) { - if ( c3y == lok_o ) { - _cj_site_lock(loc, cor, sit_u); - } - } - } - else { - if ( _(pof_o) ) { - pof_o = u3t_come(sit_u->lab); - } - if ( _(trc_o) ) { - trc_o = u3t_nock_trace_push(sit_u->lab); - } - - if ( c3y == jet_o ) { - u3t_off(glu_o); - pro = _cj_kick_z(cor, sit_u->cop_u, sit_u->ham_u, sit_u->axe); - u3t_on(glu_o); - } - if ( u3_none == pro ) { - if ( c3y == lok_o ) { - _cj_site_lock(loc, cor, sit_u); - } - pro = _cj_burn(sit_u->pog_p, cor); - } - - if ( c3y == pof_o ) { - u3t_flee(); - } - if ( c3y == trc_o ) { - u3t_nock_trace_pop(); - } - } - - return pro; -} - -/* _cj_site_kick(): execute site's kick on core. - */ -static u3_weak -_cj_site_kick(u3_noun cor, u3j_site* sit_u) -{ - u3_weak loc, pro; - - loc = pro = u3_none; - - if ( u3_none != sit_u->loc ) { - if ( c3y == _cj_fine(cor, sit_u->fin_p) ) { - loc = sit_u->loc; - pro = _cj_site_kick_hot(loc, cor, sit_u, c3y); - } - } - - if ( u3_none == loc ) { - loc = _cj_spot(cor, &(sit_u->bas)); - if ( u3_none != loc ) { - u3p(u3j_fink) fon_p = 0; - u3_weak lod = u3_none; - u3_weak lob = u3_none; - - if ( u3_none != sit_u->loc ) { - lod = sit_u->loc; - lob = sit_u->lab; - if ( c3y == sit_u->fon_o ) { - fon_p = sit_u->fin_p; - } - } - - sit_u->loc = loc; - sit_u->fin_p = _cj_cast(cor, loc); - sit_u->fon_o = c3y; - sit_u->jet_o = _cj_nail(loc, sit_u->axe, - &(sit_u->lab), &(sit_u->cop_u), &(sit_u->ham_u)); - pro = _cj_site_kick_hot(loc, cor, sit_u, c3y); - - if ( u3_none != lod ) { - u3z(lod); - u3z(lob); - if ( 0 != fon_p ) { - _cj_fink_free(fon_p); - } - } - } - } - - if ( u3_none == pro ) { - _cj_site_lock(loc, cor, sit_u); - } - - return pro; -} - -/* u3j_site_kick(): kick a core with a u3j_site cache. - */ -u3_weak -u3j_site_kick(u3_noun cor, u3j_site* sit_u) -{ - u3_weak pro; - u3t_on(glu_o); - pro = _cj_site_kick(cor, sit_u); - u3t_off(glu_o); - return pro; -} - -/* u3j_cook(): Execute hook from core, call site cached by arbitrary c string -*/ -u3_noun -u3j_cook(const c3_c* key_c, - u3_noun cor, - const c3_c* tam_c) -{ - u3_noun pro, key, tam, inn; - _cj_hank* han_u; - - u3t_on(glu_o); - key = u3i_string(key_c); - tam = u3i_string(tam_c); - han_u = _cj_hank_find(key, tam); - if ( c3n == _cj_hank_fine(han_u, cor, &inn) ) { - _cj_hank_lose(han_u); - inn = _cj_hank_fill(han_u, tam, cor); - } - pro = _cj_site_kick(u3k(inn), &(han_u->sit_u)); - if ( u3_none == pro ) { - pro = _cj_burn(han_u->sit_u.pog_p, inn); - } - u3z(cor); - - u3z(key); - u3z(tam); - u3t_off(glu_o); - return pro; -} - -/* u3j_kink(): kick either by jet or by nock. -*/ -u3_noun -u3j_kink(u3_noun cor, u3_noun axe) -{ - u3_weak pro = u3j_kick(cor, axe); - - if ( u3_none != pro ) { - return pro; - } - else { - return _cj_sink(cor, axe); - } -} - -/* u3j_gate_prep(): prepare a locally cached gate to call repeatedly. - * core is TRANSFERRED. - */ -void -u3j_gate_prep(u3j_site* sit_u, u3_noun cor) -{ - u3_noun loc; - u3t_on(glu_o); - if ( c3n == u3du(cor) || c3n == u3du(u3t(cor)) ) { - u3m_bail(c3__exit); - return; - } - sit_u->bas = u3_none; - sit_u->axe = 2; - sit_u->bat = cor; // a lie, this isn't really the battery! - sit_u->loc = loc = _cj_spot(cor, &(sit_u->bas)); - sit_u->pog_p = _cj_prog(loc, u3h(cor)); - if ( u3_none != loc ) { - u3_noun pax = _cj_loc_axe(loc), - pay = u3qc_cap(pax), - pam = u3qc_mas(pax); - if ( 3 != pay || 2 == pam || (3 != pam && 3 != u3qc_cap(pam)) ) { - u3l_log("u3j_gate_prep(): parent axis includes sample"); - u3m_p("axis", pax); - u3_weak act = _cj_find_warm(loc); - u3_assert( u3_none != act ); - sit_u->jet_o = c3n; - sit_u->lab = u3k(u3h(u3t(u3t(act)))); - u3z(act); - } - else { - sit_u->jet_o = _cj_nail(loc, 2, - &(sit_u->lab), &(sit_u->cop_u), &(sit_u->ham_u)); - } - u3z(pam); u3z(pax); - } - u3t_off(glu_o); -} - -/* u3j_gate_slam(): slam a site prepared by u3j_gate_find() with sample. - * sam is TRANSFERRED. - */ -u3_noun -u3j_gate_slam(u3j_site* sit_u, u3_noun sam) -{ - u3_weak pro; - u3_noun cor; - - u3t_on(glu_o); - pro = u3_none; - cor = u3nt(u3k(u3h(sit_u->bat)), - sam, - u3k(u3t(u3t(sit_u->bat)))); - if ( u3_none != sit_u->loc ) { - pro = _cj_site_kick_hot(sit_u->loc, cor, sit_u, c3n); - } - if ( u3_none == pro ) { - pro = _cj_burn(sit_u->pog_p, cor); - } - u3t_off(glu_o); - return pro; -} - -/* u3j_gate_lose(): clean up site prepared by u3j_gate_find(). - */ -void -u3j_gate_lose(u3j_site* sit_u) -{ - u3z(sit_u->bat); - u3z(sit_u->bas); - if ( u3_none != sit_u->loc ) { - u3z(sit_u->loc); - u3z(sit_u->lab); - } -} - -/* _cj_minx(): produce location of core from fsck'd clue. RETAIN. - */ -static u3_weak -_cj_minx(u3_noun cey, u3_noun cor) -{ - u3_noun nam, axe, huc; - u3x_trel(cey, &nam, &axe, &huc); - - if ( 0 == axe ) { - return u3nt(u3nt(c3y, c3y, u3k(u3t(cor))), u3k(nam), u3k(huc)); - } - else { - u3_weak par, pel; - u3_noun pat; - - par = u3r_at(axe, cor); - if ( u3_none == par || c3n == u3du(par) ) { - u3l_log("fund: %s is bogus", u3r_string(nam)); - return u3_none; - } - pel = _cj_spot(par, NULL); - if ( u3_none == pel ) { - u3l_log("fund: in %s, parent %x not found at %d", - u3r_string(nam), - u3r_mug(u3h(par)), - axe); - return u3_none; - } - pat = ( ( 3 == axe ) && (c3y == u3h(u3h(pel))) ) - ? u3nt(c3y, c3n, pel) - : u3nt(c3n, u3k(axe), pel); - return u3nt(pat, u3k(nam), u3k(huc)); - } -} - -static void -_cj_print_tas(u3_noun tas) -{ - c3_w met_w = u3r_met(3, tas); - c3_c* str_c = alloca(met_w + 1); - u3r_bytes(0, met_w, (c3_y*)str_c, tas); - str_c[met_w] = 0; - u3l_log("/%s", str_c); -} - -/* _cj_mine(): declare a core and produce location. RETAIN. -*/ -static u3_weak -_cj_mine(u3_noun cey, u3_noun cor, u3_noun bas) -{ - u3_weak loc = _cj_minx(cey, cor); - if ( u3_none != loc ) { - c3_l par_l, jax_l; - u3_noun pel = _cj_loc_pel(loc), - axe = _cj_loc_axe(loc), - bat = u3h(cor), - nam = u3h(u3t(loc)), - bar = _cj_find_cold(bat), - reg, hap, bal, act; - if ( u3_none == bar ) { - reg = u3_none; - } - else { - reg = u3k(u3t(bar)); - u3z(bar); - } - reg = _cj_gust(reg, u3k(axe), u3k(pel), u3k(loc)); - if ( 0 == axe ) { - par_l = 0; - bal = u3nc(u3k(nam), u3_nul); - } - else { - u3_weak pac = _cj_find_warm(pel); - u3_assert(u3_none != pac); - par_l = u3h(pac); - bal = u3nc(u3k(nam), u3k(u3h(u3t(u3t(pac))))); - u3z(pac); - } - jax_l = _cj_hot_mean(par_l, nam); -#if 0 - u3m_p("new jet", bal); - u3l_log(" bat %x, jax %d", u3r_mug(bat), jax_l); -#endif - - if ( !(u3C.wag_w & u3o_hashless) ) { - if ( jax_l ) { - c3_y dig_y[32]; - c3_w i_w; - u3_noun i = bal; - u3l_log("hot jet: "); - while ( i != u3_nul ) { - _cj_print_tas(u3h(i)); - i = u3t(i); - } - u3l_log("\r\n axe %d, jax %d,\r\n bash ", axe, jax_l); - u3r_bytes(0, 32, dig_y, bas); - for ( i_w = 32; i_w > 0; ) { - u3l_log("%02x", dig_y[--i_w]); - } - u3l_log(""); - } - } - - hap = _cj_warm_hump(jax_l, u3t(u3t(loc))); - act = u3nq(jax_l, hap, bal, _cj_jit(jax_l, bat)); - u3h_v1_put(u3R->jed.cod_p, bat, u3nc(u3k(bas), reg)); - u3h_v1_put(u3R->jed.war_p, loc, act); // see note in _cj_spot - u3z(pel); u3z(axe); - } - - return loc; -#if 0 - { - u3_noun bas = _cj_bash(bat), - hot = u3h_v1_get(u3D.hot_p, bas); - c3_o hav_o = c3n; - - if ( u3_none != hot ) { - u3_noun her = u3h(hot), - hol = _cj_reg_find(her, cor); - if ( hol != u3_none ) { - hav_o = c3y; - u3z(hol); - } - u3z(hot); - } - - if ( c3n == hav_o ) { - u3m_p("unregistered battery", bal); - u3l_log("hash: %x", bas); - } - u3z(bas); - } -#endif -} - -static void -_cj_audit(u3_noun loc, u3_noun cey, u3_noun cor) -{ - u3_noun pat, nam, huc, cax, can, cuc, pax; - - u3x_trel(loc, &pat, &nam, &huc); - u3x_trel(cey, &can, &cax, &cuc); - - pax = _cj_loc_axe(loc); - - if ( (c3n == u3r_sing(nam, can)) || - (c3n == u3r_sing(pax, cax)) || - (c3n == u3r_sing(huc, cuc)) ) { - u3_noun mix = _cj_minx(cey, cor); - u3m_p("bad audit", loc); - u3m_p("hint says", mix); - u3z(mix); - } - - u3z(pax); -} - -/* _cj_mile(): register core for jets, returning location. -*/ -static u3_weak -_cj_mile(u3_noun clu, u3_noun cor) -{ - u3_weak loc = u3_none; - if ( c3n == u3du(cor) ) { - u3z(clu); - u3z(cor); - } - else { - u3_weak cey = _cj_je_fsck(clu); - if ( u3_none != cey ) { - u3_weak bas = u3_none; - loc = _cj_spot(cor, &bas); - if ( u3_none == loc ) { - loc = _cj_mine(cey, cor, bas); - } - else { - _cj_audit(loc, cey, cor); - } - u3z(cey); - if ( u3_none != bas ) { - u3z(bas); - } - } - u3z(cor); - } - return loc; -} - -/* u3j_mine(): register core for jets. -*/ -void -u3j_mine(u3_noun clu, u3_noun cor) -{ - u3_weak loc; - u3t_on(glu_o); - loc = _cj_mile(clu, cor); - u3z(loc); - u3t_off(glu_o); -} - -/* u3j_rite_mine(): mine cor with clue, using u3j_rite for caching -*/ -void -u3j_rite_mine(u3j_rite* rit_u, u3_noun clu, u3_noun cor) -{ - c3_t non_t; - u3t_on(glu_o); - - non_t = (u3_none == rit_u->clu); - - if ( non_t || - c3n == u3r_sing(rit_u->clu, clu) || - c3n == _cj_fine(cor, rit_u->fin_p) ) { - u3_weak loc = _cj_mile(u3k(clu), u3k(cor)); - if ( u3_none != loc ) { - u3p(u3j_fink) fon_p = rit_u->fin_p; - u3_noun old = rit_u->clu; - c3_o own_o = rit_u->own_o; - rit_u->own_o = c3y; - rit_u->clu = u3k(clu); - rit_u->fin_p = _cj_cast(cor, loc); - u3z(loc); - - if ( !non_t && (c3y == own_o) ) { - u3z(old); - _cj_fink_free(fon_p); - } - } - } - u3z(clu); - u3z(cor); - u3t_off(glu_o); -} - -/* _cj_take_hank_cb(): u3h_v1_take_with cb for taking hanks -*/ -static u3p(_cj_hank) -_cj_take_hank_cb(u3p(_cj_hank) nah_p) -{ - _cj_hank* nah_u = u3to(_cj_hank, nah_p); - _cj_hank* han_u = u3a_walloc(c3_wiseof(_cj_hank)); - - if ( u3_none == nah_u->hax ) { - han_u->hax = u3_none; - // han_u->sit_u left uninitialized, will be ignored - } - else { - han_u->hax = u3a_take(nah_u->hax); - u3j_site_take(&(han_u->sit_u), &(nah_u->sit_u)); - } - - return u3of(_cj_hank, han_u); -} - -/* u3j_take(): copy junior jet state. -*/ -u3a_jets -u3j_take(u3a_jets jed_u) -{ - jed_u.war_p = u3h_v1_take(jed_u.war_p); - jed_u.cod_p = u3h_v1_take(jed_u.cod_p); - jed_u.han_p = u3h_v1_take_with(jed_u.han_p, _cj_take_hank_cb); - jed_u.bas_p = u3h_v1_take(jed_u.bas_p); - return jed_u; -} - -/* _cj_merge_hank_cb(): u3h_v1_uni_with cb for integrating taken hanks -** NB "transfers" or frees hanks in jed_u.han_p -*/ -static void -_cj_merge_hank_cb(u3_noun kev, void* wit) -{ - u3p(u3h_v1_root) han_p = *(u3p(u3h_v1_root)*)wit; - _cj_hank* nah_u; - u3_noun key; - u3p(_cj_hank) nah_p; - u3x_cell(kev, &key, &nah_p); - - nah_u = u3to(_cj_hank, nah_p); - - if ( u3_none == nah_u->hax ) { - u3a_wfree(nah_u); - } - else { - _cj_hank* han_u; - u3_weak got = u3h_v1_git(u3R->jed.han_p, key); - - if ( u3_none == got ) { - han_u = nah_u; - } - else { - han_u = u3to(_cj_hank, got); - - if ( u3_none != han_u->hax ) { - u3z(han_u->hax); - } - han_u->hax = nah_u->hax; - - u3j_site_merge(&(han_u->sit_u), &(nah_u->sit_u)); - u3a_wfree(nah_u); - } - - u3h_v1_put(han_p, key, u3of(_cj_hank, han_u)); - } -} - -/* u3j_reap(): promote jet state. -*/ -void -u3j_reap(u3a_jets jed_u) -{ - u3h_v1_uni(u3R->jed.war_p, jed_u.war_p); - u3h_v1_free(jed_u.war_p); - - u3h_v1_uni(u3R->jed.cod_p, jed_u.cod_p); - u3h_v1_free(jed_u.cod_p); - - u3h_v1_walk_with(jed_u.han_p, _cj_merge_hank_cb, &u3R->jed.han_p); - u3h_v1_free(jed_u.han_p); - - u3h_v1_uni(u3R->jed.bas_p, jed_u.bas_p); - u3h_v1_free(jed_u.bas_p); -} - -/* _cj_ream(): ream list of battery [bash registry] pairs. RETAIN. - */ -static void -_cj_ream(u3_noun all) -{ - c3_l par_l, jax_l; - u3_noun i, j, k, rul, loc, bal, act, lop, kev, rut, hap, - pat, reg, pol, rem, rec, bat, pel, nam, huc; - u3_weak pac; - - for ( i = all, lop = u3_nul; i != u3_nul; i = u3t(i) ) { - kev = u3h(i); - bat = u3h(kev); - reg = u3t(u3t(kev)); - rut = u3h(reg); - - // register roots - rul = u3qdb_tap(rut); - for ( j = rul; j != u3_nul; j = u3t(j) ) { - loc = u3t(u3h(j)); - u3x_trel(loc, &pat, &nam, &huc); - bal = u3nc(u3k(nam), u3_nul); - jax_l = _cj_hot_mean(0, nam); - hap = _cj_warm_hump(jax_l, huc); - act = u3nq(jax_l, hap, bal, _cj_jit(jax_l, bat)); -#if 0 - u3m_p("old jet", bal); - u3l_log(" bat %x, jax %d", u3r_mug(bat), jax_l); -#endif - u3h_v1_put(u3R->jed.war_p, loc, act); - } - u3z(rul); - - // put ancestors in lop (list [battery=^ parent=location this=location]) - for ( j = u3t(reg); j != u3_nul; j = u3t(j) ) { - pol = lop; - lop = u3qdb_tap(u3t(u3h(j))); - for ( k = lop; u3_nul != k; k = u3t(k) ) { - pol = u3nc(u3nc(u3k(bat), u3k(u3h(k))), pol); - } - u3z(lop); - lop = pol; - } - } - - // ordering is random so we need to push onto rem when parent - // isn't yet present in the warm state - while ( u3_nul != lop ) { - rem = u3_nul; - for ( i = lop; u3_nul != i; i = u3t(i) ) { - rec = u3h(i); - u3x_trel(rec, &bat, &pel, &loc); - pac = _cj_find_warm(pel); - if ( u3_none == pac ) { - rem = u3nc(u3k(rec), rem); - } - else { - u3x_trel(loc, &pat, &nam, &huc); - par_l = u3h(pac); - jax_l = _cj_hot_mean(par_l, nam); - bal = u3nc(u3k(nam), u3k(u3h(u3t(u3t(pac))))); - hap = _cj_warm_hump(jax_l, huc), - u3z(pac); - act = u3nq(jax_l, hap, bal, _cj_jit(jax_l, bat)); -#if 0 - u3m_p("old jet", bal); - u3l_log(" bat %x, jax %d", u3r_mug(bat), jax_l); -#endif - u3h_v1_put(u3R->jed.war_p, loc, act); - } - } - u3z(lop); - lop = rem; - } -} - -/* _cj_warm_tap(): tap war_p to rel -*/ -static void -_cj_warm_tap(u3_noun kev, void* wit) -{ - u3_noun* rel = wit; - *rel = u3nc(u3k(kev), *rel); -} - -/* _cj_ream_hank(): clear hot state out of hook sites. -*/ -static void -_cj_ream_hank(u3_noun kev) -{ - u3j_site_ream(&(u3to(_cj_hank, u3t(kev))->sit_u)); -} - -/* u3j_ream(): rebuild warm state -*/ -void -u3j_ream(void) -{ - u3_noun rel = u3_nul; - u3_assert(u3R == &(u3H->rod_u)); - u3h_v1_free(u3R->jed.war_p); - u3R->jed.war_p = u3h_v1_new(); - u3h_v1_walk_with(u3R->jed.cod_p, _cj_warm_tap, &rel); - _cj_ream(rel); - u3z(rel); - - u3h_v1_walk(u3R->jed.han_p, _cj_ream_hank); -} - -/* u3j_stay(): extract cold state -*/ -u3_noun -u3j_stay(void) -{ - u3_noun rel = u3_nul; - u3_assert(u3R == &(u3H->rod_u)); - u3h_v1_walk_with(u3R->jed.cod_p, _cj_warm_tap, &rel); - return rel; -} - -/* u3j_load(): inject cold state -*/ -void -u3j_load(u3_noun rel) -{ - u3_noun ler = rel; - u3_noun lor; - - while ( u3_nul != ler ) { - u3x_cell(ler, &lor, &ler); - u3h_v1_put(u3R->jed.cod_p, u3h(lor), u3k(u3t(lor))); - } - - u3z(rel); -} - -/* _cj_fink_mark(): mark a u3j_fink for gc. -*/ -static c3_w -_cj_fink_mark(u3j_fink* fin_u) -{ - c3_w i_w, tot_w = u3a_mark_noun(fin_u->sat); - for ( i_w = 0; i_w < fin_u->len_w; ++i_w ) { - u3j_fist* fis_u = &(fin_u->fis_u[i_w]); - tot_w += u3a_mark_noun(fis_u->bat); - tot_w += u3a_mark_noun(fis_u->pax); - } - tot_w += u3a_mark_ptr(fin_u); - return tot_w; -} - -/* u3j_site_lose(): lose references of u3j_site (but do not free). - */ -void -u3j_site_lose(u3j_site* sit_u) -{ - u3z(sit_u->axe); - if ( u3_none != sit_u->bat ) { - u3z(sit_u->bat); - } - if ( u3_none != sit_u->bas ) { - u3z(sit_u->bas); - } - if ( u3_none != sit_u->loc ) { - u3z(sit_u->loc); - u3z(sit_u->lab); - if ( c3y == sit_u->fon_o ) { - _cj_fink_free(sit_u->fin_p); - } - } -} +/** Data structures. +**/ -/* u3j_rite_lose(): lose references of u3j_rite (but do not free). +/* _cj_hank: cached hook information. +** NB: copy of _cj_hank from pkg/noun/jets.c */ -void -u3j_rite_lose(u3j_rite* rit_u) -{ - if ( (c3y == rit_u->own_o) && u3_none != rit_u->clu ) { - u3z(rit_u->clu); - _cj_fink_free(rit_u->fin_p); - } -} - -/* u3j_rite_mark(): mark u3j_rite for gc. -*/ -c3_w -u3j_rite_mark(u3j_rite* rit_u) -{ - c3_w tot_w = 0; - if ( (c3y == rit_u->own_o) && u3_none != rit_u->clu ) { - tot_w += u3a_mark_noun(rit_u->clu); - tot_w += _cj_fink_mark(u3to(u3j_fink, rit_u->fin_p)); - } - return tot_w; -} - -/* u3j_site_mark(): mark u3j_site for gc. -*/ -c3_w -u3j_site_mark(u3j_site* sit_u) -{ - c3_w tot_w = u3a_mark_noun(sit_u->axe); - if ( u3_none != sit_u->bat ) { - tot_w += u3a_mark_noun(sit_u->bat); - } - if ( u3_none != sit_u->bas ) { - tot_w += u3a_mark_noun(sit_u->bas); - } - if ( u3_none != sit_u->loc ) { - tot_w += u3a_mark_noun(sit_u->loc); - tot_w += u3a_mark_noun(sit_u->lab); - if ( c3y == sit_u->fon_o ) { - tot_w += _cj_fink_mark(u3to(u3j_fink, sit_u->fin_p)); - } - } - return tot_w; -} - -/* _cj_mark_hank(): mark hank cache for gc. -*/ -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)); - *tot_w += u3a_mark_ptr(han_u); - if ( u3_none != han_u->hax ) { - *tot_w += u3a_mark_noun(han_u->hax); - *tot_w += u3j_site_mark(&(han_u->sit_u)); - } -} - -/* u3j_mark(): mark jet state for gc. -*/ -c3_w -u3j_mark(FILE* fil_u) -{ - c3_w tot_w = 0; - - tot_w += u3a_maid(fil_u, " warm jet state", u3h_v1_mark(u3R->jed.war_p)); - tot_w += u3a_maid(fil_u, " cold jet state", u3h_v1_mark(u3R->jed.cod_p)); - tot_w += u3a_maid(fil_u, " hank cache", u3h_v1_mark(u3R->jed.han_p)); - tot_w += u3a_maid(fil_u, " battery hash cache", u3h_v1_mark(u3R->jed.bas_p)); - - { - c3_w han_w = 0; - u3h_v1_walk_with(u3R->jed.han_p, _cj_mark_hank, &han_w); - tot_w += u3a_maid(fil_u, " call site cache", han_w); - } - - if ( u3R == &(u3H->rod_u) ) { - tot_w += u3a_maid(fil_u, " hot jet state", u3h_v1_mark(u3R->jed.hot_p)); - } +typedef struct { + u3_weak hax; // axis of hooked inner core + u3j_site sit_u; // call-site data +} _cj_hank; - return u3a_maid(fil_u, "total jet stuff", tot_w); -} +/** Functions. +**/ /* _cj_free_hank(): free an entry from the hank cache. +** NB: copy of _cj_free_hank() from pkg/noun/jets.c */ static void _cj_free_hank(u3_noun kev) @@ -2350,26 +36,10 @@ _cj_free_hank(u3_noun kev) u3a_wfree(han_u); } -/* u3j_free(): free jet state. -*/ -void -u3j_free(void) -{ - u3h_v1_walk(u3R->jed.han_p, _cj_free_hank); - u3h_v1_free(u3R->jed.war_p); - u3h_v1_free(u3R->jed.cod_p); - u3h_v1_free(u3R->jed.han_p); - u3h_v1_free(u3R->jed.bas_p); - if ( u3R == &(u3H->rod_u) ) { - u3h_v1_free(u3R->jed.hot_p); - } -} - -/* u3j_reclaim(): clear ad-hoc persistent caches to reclaim memory. -** XX need to version +/* u3j_v1_reclaim(): clear ad-hoc persistent caches to reclaim memory. */ void -u3j_reclaim(void) +u3j_v1_reclaim(void) { // re-establish the warm jet state // @@ -2383,19 +53,19 @@ u3j_reclaim(void) // u3h_v1_walk(u3R->jed.han_p, _cj_free_hank); u3h_v1_free(u3R->jed.han_p); - u3R->jed.han_p = u3h_v1_new(); + u3R->jed.han_p = u3h_new(); } -/* u3j_rewrite_compact(): rewrite jet state for compaction. +/* u3j_v1_rewrite_compact(): rewrite jet state for compaction. * - * NB: u3R->jed.han_p *must* be cleared (currently via u3j_reclaim above) + * NB: u3R->jed.han_p *must* be cleared (currently via u3j_v1_reclaim above) * since it contains hanks which are not nouns but have loom pointers. - * Alternately, rewrite the entries with u3h_v1_walk, using u3j_mark as a + * Alternately, rewrite the entries with u3h_v1_walk, using u3j_v1_mark as a * template for how to walk. There's an untested attempt at this in git * history at e8a307a. */ void -u3j_rewrite_compact() +u3j_v1_rewrite_compact() { u3h_v1_rewrite(u3R->jed.war_p); u3h_v1_rewrite(u3R->jed.cod_p); diff --git a/pkg/noun/v1/jets.h b/pkg/noun/v1/jets.h index 57a7875f20..7e045ce67d 100644 --- a/pkg/noun/v1/jets.h +++ b/pkg/noun/v1/jets.h @@ -3,7 +3,7 @@ #ifndef U3_JETS_V1_H #define U3_JETS_V1_H -#include "allocate.h" +#include "pkg/noun/allocate.h" #include "c3.h" #include "types.h" @@ -12,4 +12,9 @@ void u3j_v1_reclaim(void); + /* u3j_v1_rewrite_compact(): rewrite jet state for compaction. + */ + void + u3j_v1_rewrite_compact(); + #endif /* ifndef U3_JETS_V1_H */ diff --git a/pkg/noun/v1/manage.c b/pkg/noun/v1/manage.c index 285c70d43d..e478876de2 100644 --- a/pkg/noun/v1/manage.c +++ b/pkg/noun/v1/manage.c @@ -1,17 +1,18 @@ /// @file -#include "v1/manage.h" +#include "pkg/noun/v1/manage.h" #include #include #include #include -#include "v1/allocate.h" +#include "pkg/noun/v1/allocate.h" #include "events.h" -#include "v1/hashtable.h" +#include "pkg/noun/v1/hashtable.h" #include "imprison.h" -#include "jets.h" +#include "pkg/noun/jets.h" +#include "pkg/noun/v1/jets.h" #include "jets/k.h" #include "log.h" #include "nock.h" @@ -21,2327 +22,16 @@ #include "retrieve.h" #include "trace.h" #include "urcrypt/urcrypt.h" -#include "vortex.h" +#include "pkg/noun/vortex.h" #include "xtract.h" -// XX stack-overflow recovery should be gated by -a -// -#undef NO_OVERFLOW - - /* (u3_noun)setjmp(u3R->esc.buf): setjmp within road. - */ -#if 0 - c3_o - u3m_v1_trap(void); -#else -# define u3m_v1_trap() (u3_noun)(_setjmp(u3R->esc.buf)) -#endif - - /* u3m_v1_signal(): treat a nock-level exception as a signal interrupt. - */ - void - u3m_v1_signal(u3_noun sig_l); - - /* u3m_v1_dump(): dump the current road to stderr. - */ - void - u3m_v1_dump(void); - - /* u3m_v1_fall(): return to parent road. - */ - void - u3m_v1_fall(void); - - /* u3m_v1_leap(): in u3R, create a new road within the existing one. - */ - void - u3m_v1_leap(c3_w pad_w); - - /* u3m_v1_golf(): record cap length for u3m_v1_flog(). - */ - c3_w - u3m_v1_golf(void); - - /* u3m_v1_flog(): pop the cap. - ** - ** A common sequence for inner allocation is: - ** - ** c3_w gof_w = u3m_v1_golf(); - ** u3m_v1_leap(); - ** // allocate some inner stuff... - ** u3m_v1_fall(); - ** // inner stuff is still valid, but on cap - ** u3m_v1_flog(gof_w); - ** - ** u3m_v1_flog(0) simply clears the cap. - */ - void - u3m_v1_flog(c3_w gof_w); - - /* u3m_v1_soft_top(): top-level safety wrapper. - */ - u3_noun - u3m_v1_soft_top(c3_w mil_w, // timer ms - c3_w pad_w, // base memory pad - u3_funk fun_f, - u3_noun arg); - - -// u3m_v1_signal uses restricted functionality signals for compatibility reasons: -// some platforms may not provide true POSIX asynchronous signals and their -// compat layer will then implement this restricted functionality subset. -// u3m_v1_signal never needs to interrupt I/O operations, its signal handlers -// do not manipulate signals, do not modify shared state, and always either -// return or longjmp. -// -static rsignal_jmpbuf u3_Signal; - -#include "sigsegv.h" - -#ifndef SIGSTKSZ -# define SIGSTKSZ 16384 -#endif -#ifndef NO_OVERFLOW -static uint8_t Sigstk[SIGSTKSZ]; -#endif - -#if 0 -/* _cm_punt(): crudely print trace. -*/ -static void -_cm_punt(u3_noun tax) -{ - u3_noun xat; - - for ( xat = tax; xat; xat = u3t(xat) ) { - u3m_v1_p("&", u3h(xat)); - } -} -#endif - -/* _cm_emergency(): write emergency text to stderr, never failing. -*/ -static void -_cm_emergency(c3_c* cap_c, c3_l sig_l) -{ - write(2, "\r\n", 2); - write(2, cap_c, strlen(cap_c)); - - if ( sig_l ) { - write(2, ": ", 2); - write(2, &sig_l, 4); - } - - write(2, "\r\n", 2); -} - -static void _cm_overflow(void *arg1, void *arg2, void *arg3) -{ - (void)(arg1); - (void)(arg2); - (void)(arg3); - u3m_v1_signal(c3__over); -} - -/* _cm_signal_handle(): handle a signal in general. -*/ -static void -_cm_signal_handle(c3_l sig_l) -{ - if ( c3__over == sig_l ) { -#ifndef NO_OVERFLOW - sigsegv_leave_handler(_cm_overflow, NULL, NULL, NULL); -#endif - } - else { - u3m_v1_signal(sig_l); - } -} - -#ifndef NO_OVERFLOW -static void -_cm_signal_handle_over(int emergency, stackoverflow_context_t scp) -{ - _cm_signal_handle(c3__over); -} -#endif - -static void -_cm_signal_handle_term(int x) -{ - // Ignore if we are using base memory from work memory, very rare. - // - if ( (0 != u3H->rod_u.kid_p) && (&(u3H->rod_u) == u3R) ) { - _cm_emergency("ignored", c3__term); - } - else { - _cm_signal_handle(c3__term); - } -} - -static void -_cm_signal_handle_intr(int x) -{ - // Interrupt: stop work. Ignore if not working, or (rarely) using base. - // - if ( &(u3H->rod_u) == u3R ) { - _cm_emergency("ignored", c3__intr); - } - else { - _cm_signal_handle(c3__intr); - } -} - -static void -_cm_signal_handle_alrm(int x) -{ - _cm_signal_handle(c3__alrm); -} - -/* _cm_signal_reset(): reset top road after signal longjmp. -*/ -static void -_cm_signal_reset(void) -{ - u3R = &u3H->rod_u; - u3R->cap_p = u3R->mat_p; - u3R->ear_p = 0; - u3R->kid_p = 0; -} - -#if 0 -/* _cm_stack_recover(): recover stack trace, with lacunae. -*/ -static u3_noun -_cm_stack_recover(u3a_road* rod_u) -{ - c3_w len_w; - - len_w = 0; - { - u3_noun tax = rod_u->bug.tax; - - while ( tax ) { - len_w++; - tax = u3t(tax); - } - - if ( len_w < 4096 ) { - return u3a_take(rod_u->bug.tax); - } - else { - u3_noun beg, fin; - c3_w i_w; - - tax = rod_u->bug.tax; - beg = u3_nul; - for ( i_w = 0; i_w < 2048; i_w++ ) { - beg = u3nc(u3a_take(u3h(tax)), beg); - tax = u3t(tax); - } - beg = u3kb_flop(beg); - - for ( i_w = 0; i_w < (len_w - 4096); i_w++ ) { - tax = u3t(tax); - } - fin = u3nc(u3nc(c3__lose, c3__over), u3a_take(tax)); - - return u3kb_weld(beg, fin); - } - } -} -#endif - -/* _cm_stack_unwind(): unwind to the top level, preserving all frames. -*/ -static u3_noun -_cm_stack_unwind(void) -{ - u3_noun tax; - - while ( u3R != &(u3H->rod_u) ) { - u3_noun yat = u3m_v1_love(u3R->bug.tax); - - u3R->bug.tax = u3kb_weld(yat, u3R->bug.tax); - } - tax = u3R->bug.tax; - - u3R->bug.tax = 0; - return tax; -} - -/* _cm_signal_recover(): recover from a deep signal, after longjmp. Free arg. -*/ -static u3_noun -_cm_signal_recover(c3_l sig_l, u3_noun arg) -{ - u3_noun tax; - - // Unlikely to be set, but it can be made to happen. - // - tax = u3H->rod_u.bug.tax; - u3H->rod_u.bug.tax = 0; - - if ( &(u3H->rod_u) == u3R ) { - // A top-level crash - rather odd. We should GC. - // - _cm_emergency("recover: top", sig_l); - u3C.wag_w |= u3o_check_corrupt; - - // Reset the top road - the problem could be a fat cap. - // - _cm_signal_reset(); - - if ( (c3__meme == sig_l) && (u3a_open(u3R) <= 256) ) { - // Out of memory at the top level. Error becomes c3__full, - // and we release the emergency buffer. To continue work, - // we need to readjust the image, eg, migrate to 64 bit. - // - u3z(u3R->bug.mer); - u3R->bug.mer = 0; - sig_l = c3__full; - } - return u3nt(3, sig_l, tax); - } - else { - u3_noun pro; - - // A signal was generated while we were within Nock. - // - _cm_emergency("recover: dig", sig_l); - -#if 0 - // Descend to the innermost trace, collecting stack. - // - { - u3a_road* rod_u; - - u3R = &(u3H->rod_u); - rod_u = u3R; - - while ( rod_u->kid_p ) { -#if 0 - u3l_log("collecting %d frames", - u3kb_lent((u3to(u3_road, rod_u->kid_p)->bug.tax)); -#endif - tax = u3kb_weld(_cm_stack_recover(u3to(u3_road, rod_u->kid_p)), tax); - rod_u = u3to(u3_road, rod_u->kid_p); - } - } -#else - tax = _cm_stack_unwind(); -#endif - pro = u3nt(3, sig_l, tax); - _cm_signal_reset(); - - u3z(arg); - return pro; - } -} - -/* _cm_signal_deep(): start deep processing; set timer for [mil_w] or 0. -*/ -static void -_cm_signal_deep(c3_w mil_w) -{ - // disable outer system signal handling - // - if ( 0 != u3C.sign_hold_f ) { - u3C.sign_hold_f(); - } - -#ifndef NO_OVERFLOW - stackoverflow_install_handler(_cm_signal_handle_over, Sigstk, SIGSTKSZ); -#endif - rsignal_install_handler(SIGINT, _cm_signal_handle_intr); - rsignal_install_handler(SIGTERM, _cm_signal_handle_term); - - // Provide a little emergency memory, for use in case things - // go utterly haywire. - // - if ( 0 == u3H->rod_u.bug.mer ) { - u3H->rod_u.bug.mer = u3i_string( - "emergency buffer with sufficient space to cons the trace and bail" - ); - } - - if ( mil_w ) { - struct itimerval itm_u; - - timerclear(&itm_u.it_interval); - itm_u.it_value.tv_sec = (mil_w / 1000); - itm_u.it_value.tv_usec = 1000 * (mil_w % 1000); - - if ( rsignal_setitimer(ITIMER_VIRTUAL, &itm_u, 0) ) { - u3l_log("loom: set timer failed %s", strerror(errno)); - } - else { - rsignal_install_handler(SIGVTALRM, _cm_signal_handle_alrm); - } - } - - u3t_boot(); -} - -/* _cm_signal_done(): -*/ -static void -_cm_signal_done() -{ - rsignal_deinstall_handler(SIGINT); - rsignal_deinstall_handler(SIGTERM); - rsignal_deinstall_handler(SIGVTALRM); - -#ifndef NO_OVERFLOW - stackoverflow_deinstall_handler(); -#endif - { - struct itimerval itm_u; - - timerclear(&itm_u.it_interval); - timerclear(&itm_u.it_value); - - if ( rsignal_setitimer(ITIMER_VIRTUAL, &itm_u, 0) ) { - u3l_log("loom: clear timer failed %s", strerror(errno)); - } - } - - // restore outer system signal handling - // - if ( 0 != u3C.sign_move_f ) { - u3C.sign_move_f(); - } - - u3t_boff(); -} - -/* u3m_v1_signal(): treat a nock-level exception as a signal interrupt. -*/ -void -u3m_v1_signal(u3_noun sig_l) -{ - rsignal_longjmp(u3_Signal, sig_l); -} - -/* u3m_v1_file(): load file, as atom, or bail. -*/ -u3_noun -u3m_v1_file(c3_c* pas_c) -{ - struct stat buf_b; - c3_i fid_i = c3_open(pas_c, O_RDONLY, 0644); - c3_w fln_w, red_w; - c3_y* pad_y; - - if ( (fid_i < 0) || (fstat(fid_i, &buf_b) < 0) ) { - u3l_log("%s: %s", pas_c, strerror(errno)); - return u3m_v1_bail(c3__fail); - } - fln_w = buf_b.st_size; - pad_y = c3_malloc(buf_b.st_size); - - red_w = read(fid_i, pad_y, fln_w); - close(fid_i); - - if ( fln_w != red_w ) { - c3_free(pad_y); - return u3m_v1_bail(c3__fail); - } - else { - u3_noun pad = u3i_bytes(fln_w, (c3_y *)pad_y); - c3_free(pad_y); - - return pad; - } -} - -/* u3m_v1_mark(): mark all nouns in the road. -*/ -c3_w -u3m_v1_mark(FILE* fil_u) -{ - c3_w tot_w = 0; - tot_w += u3v_mark(fil_u); - tot_w += u3j_mark(fil_u); - tot_w += u3n_mark(fil_u); - tot_w += u3a_mark_road(fil_u); - return tot_w; -} - -/* _pave_parts(): build internal tables. -*/ -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_v1_new_cache(50000); - u3R->jed.war_p = u3h_v1_new(); - u3R->jed.cod_p = u3h_v1_new(); - u3R->jed.han_p = u3h_v1_new(); - u3R->jed.bas_p = u3h_v1_new(); - u3R->byc.har_p = u3h_v1_new(); -} - -/* _pave_road(): writes road boundaries to loom mem (stored at mat_w) -*/ -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); - u3_road* rod_u = (void*) mat_w; - - // enable in case of corruption - // - // memset(mem_w, 0, 4 * len_w); - memset(rod_u, 0, sizeof(c3_w) * siz_w); - - // the top and bottom of the heap are initially the same - // - rod_u->rut_p = u3of(c3_w, rut_w); - rod_u->hat_p = u3of(c3_w, rut_w); - - - rod_u->mat_p = u3of(c3_w, mat_w); // stack bottom - rod_u->cap_p = u3of(c3_w, cap_w); // stack top - - _rod_vaal(rod_u); - return rod_u; -} - -/* _pave_north(): calculate boundaries and initialize north road. - - mem_w - the "beginning" of your loom (its lowest address). Corresponds to rut - in a north road. - siz_w - the size in bytes of your road record (or home record in the case of - paving home). - len_w - size of your loom in words -*/ -static u3_road* -_pave_north(c3_w* mem_w, c3_w siz_w, c3_w len_w, c3_o kid_o) -{ - // in a north road, the heap is low and the stack is high - // - // the heap starts at the base memory pointer [mem_w]; - // the stack starts at the end of the memory segment, - // minus space for the road structure [siz_w] - // - // 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* cap_w = mat_w; - - if ( c3y == kid_o ) { - u3e_ward(u3of(c3_w, rut_w) - 1, u3of(c3_w, cap_w)); - } - - return _pave_road(rut_w, mat_w, cap_w, siz_w); -} - -/* _pave_south(): calculate boundaries and initialize south road. - - mem_w - the "beginning" of your loom (its lowest address). Corresponds to mat - in a south road. - siz_w - the size in bytes of your road record (or home record in the case of - paving home). - len_w - size of your loom in words -*/ -static u3_road* -_pave_south(c3_w* mem_w, c3_w siz_w, c3_w len_w) -{ - // in a south road, the heap is high and the stack is low - // - // the heap starts at the end of the memory segment; - // the stack starts at the base memory pointer [mem_w], - // and ends after the space for the road structure [siz_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* cap_w = mat_w + siz_w; - - u3e_ward(u3of(c3_w, cap_w) - 1, u3of(c3_w, rut_w)); - - return _pave_road(rut_w, mat_w, cap_w, siz_w); -} - -/* _pave_home(): initialize pristine home road. -*/ -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 siz_w = c3_wiseof(u3v_home); - c3_w len_w = u3C.wor_i - u3C.walign_w; - - u3H = (void *)_pave_north(mem_w, siz_w, len_w, c3n); - u3H->ver_w = U3V_VERLAT; - u3R = &u3H->rod_u; - - _pave_parts(); -} - -STATIC_ASSERT( ((c3_wiseof(u3v_home) * 4) == sizeof(u3v_home)), - "home road alignment" ); - -/* _find_home(): in restored image, point to home road. -*/ -static void -_find_home(void) -{ - c3_w ver_w = *(u3_Loom + u3C.wor_i - 1); - u3a_config_loom(ver_w); - - // NB: the home road is always north - // - c3_w* mem_w = u3_Loom + u3C.walign_w; - 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); - - u3H = (void *)mat_w; - u3R = &u3H->rod_u; - - // this looks risky, but there are no legitimate scenarios - // where it's wrong - // - u3R->cap_p = u3R->mat_p = u3a_outa(u3H); - - // check for obvious corruption - // - { - c3_w nor_w, sou_w; - u3_post low_p, hig_p; - u3m_v1_water(&low_p, &hig_p); - - nor_w = (low_p + ((1 << u3a_page) - 1)) >> u3a_page; - sou_w = u3P.pag_w - (hig_p >> u3a_page); - - if ( (nor_w > u3P.nor_u.pgs_w) || (sou_w != u3P.sou_u.pgs_w) ) { - fprintf(stderr, "loom: corrupt size north (%u, %u) south (%u, %u)\r\n", - nor_w, u3P.nor_u.pgs_w, sou_w, u3P.sou_u.pgs_w); - u3_assert(!"loom: corrupt size"); - } - - // the north segment is in-order on disk; it being oversized - // doesn't necessarily indicate corruption. - // - if ( nor_w < u3P.nor_u.pgs_w ) { - fprintf(stderr, "loom: strange size north (%u, %u)\r\n", - nor_w, u3P.nor_u.pgs_w); - } - } - - /* As a further guard against any sneaky loom corruption */ - u3a_loom_sane(); - - if (U3V_VERLAT > ver_w) { - // u3m_v1_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); -} - -/* u3m_v1_pave(): instantiate or activate image. -*/ -void -u3m_v1_pave(c3_o nuu_o) -{ - if ( c3y == nuu_o ) { - _pave_home(); - } - else { - _find_home(); - } -} - -#if 0 -/* u3m_v1_clear(): clear all allocated data in road. -*/ -void -u3m_v1_clear(void) -{ - u3h_free(u3R->cax.har_p); - u3j_free(); - u3n_free(); -} - -void -u3m_v1_dump(void) -{ - c3_w hat_w; - c3_w fre_w = 0; - c3_w i_w; - - hat_w = _(u3a_is_north(u3R)) ? u3R->hat_w - u3R->rut_w - : u3R->rut_w - u3R->hat_w; - - for ( i_w = 0; i_w < u3_cc_fbox_no; i_w++ ) { - u3a_fbox* fre_u = u3R->all.fre_u[i_w]; - - while ( fre_u ) { - fre_w += fre_u->box_u.siz_w; - fre_u = fre_u->nex_u; - } - } - u3l_log("dump: hat_w %x, fre_w %x, allocated %x", - hat_w, fre_w, (hat_w - fre_w)); - - if ( 0 != (hat_w - fre_w) ) { - c3_w* box_w = _(u3a_is_north(u3R)) ? u3R->rut_w : u3R->hat_w; - c3_w mem_w = 0; - - while ( box_w < (_(u3a_is_north(u3R)) ? u3R->hat_w : u3R->rut_w) ) { - u3a_box* box_u = (void *)box_w; - - if ( 0 != box_u->use_w ) { -#ifdef U3_MEMORY_DEBUG - // u3l_log("live %d words, code %x", box_u->siz_w, box_u->cod_w); -#endif - mem_w += box_u->siz_w; - } - box_w += box_u->siz_w; - } - - u3l_log("second count: %x", mem_w); - } -} -#endif - -/* u3m_v1_bail(): bail out. Does not return. -** -** Bail motes: -** -** %evil :: erroneous cryptography -** %exit :: semantic failure -** %oops :: assertion failure -** %intr :: interrupt -** %fail :: computability failure -** %over :: stack overflow (a kind of %fail) -** %meme :: out of memory -** -** These are equivalents of the full exception noun, the error ball: -** -** $% [%0 success] -** [%1 paths] -** [%2 trace] -** [%3 code trace] -** == -** -** XX several of these abort() calls should be gated by -a -*/ -c3_i -u3m_v1_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 ) { - case c3__evil: - case c3__exit: break; - - default: { - if ( _(u3ud(how)) ) { - c3_c str_c[5]; - - str_c[0] = ((how >> 0) & 0xff); - str_c[1] = ((how >> 8) & 0xff); - str_c[2] = ((how >> 16) & 0xff); - str_c[3] = ((how >> 24) & 0xff); - str_c[4] = 0; - fprintf(stderr, "\r\nbail: %s\r\n", str_c); - } - else if ( 1 != u3h(how) ) { - u3_assert(_(u3ud(u3h(how)))); - fprintf(stderr, "\r\nbail: %d\r\n", u3h(how)); - } - } - } - - // intercept fatal errors - // - switch ( how ) { - case c3__foul: - case c3__oops: { - // XX set exit code - // - fprintf(stderr, "bailing out\r\n"); - abort(); - } - } - - if ( &(u3H->rod_u) == u3R ) { - // For top-level errors, which shouldn't happen often, we have no - // choice but to use the signal process; and we require the flat - // form of how. - // - // XX JB: these seem unrecoverable, at least wrt memory management, - // so they've been disabled above for now - // - u3_assert(_(u3a_is_cat(how))); - u3m_v1_signal(how); - } - - // release the emergency buffer, ensuring space for cells - // - u3z(u3R->bug.mer); - u3R->bug.mer = 0; - - /* Reconstruct a correct error ball. - */ - if ( _(u3ud(how)) ) { - switch ( how ) { - case c3__exit: { - how = u3nc(2, u3R->bug.tax); - } break; - - default: { - how = u3nt(3, how, u3R->bug.tax); - } break; - } - } - - /* Longjmp, with an underscore. - */ - _longjmp(u3R->esc.buf, how); -} - -int c3_cooked() { return u3m_v1_bail(c3__oops); } - -/* u3m_v1_error(): bail out with %exit, ct_pushing error. -*/ -c3_i -u3m_v1_error(c3_c* str_c) -{ - u3t_mean(u3i_string(str_c)); - return u3m_v1_bail(c3__exit); -} - -/* u3m_v1_leap(): in u3R, create a new road within the existing one. -*/ -void -u3m_v1_leap(c3_w pad_w) -{ - c3_w len_w; /* the length of the new road (avail - (pad + wiseof(u3a_road))) */ - u3_road* rod_u; - - _rod_vaal(u3R); - - /* Measure the pad - we'll need it. - */ - { -#if 0 - if ( pad_w < u3R->all.fre_w ) { - pad_w = 0; - } - else { - pad_w -= u3R->all.fre_w; - } -#endif - if ( (pad_w + c3_wiseof(u3a_road)) >= u3a_open(u3R) ) { - /* not enough storage to leap */ - u3m_v1_bail(c3__meme); - } - pad_w += c3_wiseof(u3a_road); - len_w = u3a_open(u3R) - pad_w; - c3_align(len_w, u3C.walign_w, C3_ALGHI); - } - - /* Allocate a region on the cap. - */ - { - u3p(c3_w) bot_p; /* S: bot_p = new mat. N: bot_p = new rut */ - - if ( c3y == u3a_is_north(u3R) ) { - bot_p = u3R->hat_p + pad_w; - - rod_u = _pave_south(u3a_into(bot_p), c3_wiseof(u3a_road), len_w); -#if 0 - fprintf(stderr, "NPAR.hat_p: 0x%x %p, SKID.hat_p: 0x%x %p\r\n", - u3R->hat_p, u3a_into(u3R->hat_p), - rod_u->hat_p, u3a_into(rod_u->hat_p)); -#endif - } - else { - bot_p = u3R->cap_p; - - rod_u = _pave_north(u3a_into(bot_p), c3_wiseof(u3a_road), len_w, c3y); -#if 0 - fprintf(stderr, "SPAR.hat_p: 0x%x %p, NKID.hat_p: 0x%x %p\r\n", - u3R->hat_p, u3a_into(u3R->hat_p), - rod_u->hat_p, u3a_into(rod_u->hat_p)); - -#endif - } - } - - /* Attach the new road to its parents. - */ - { - u3_assert(0 == u3R->kid_p); - rod_u->par_p = u3of(u3_road, u3R); - u3R->kid_p = u3of(u3_road, rod_u); - } - - /* Set up the new road. - */ - { - u3R = rod_u; - _pave_parts(); - } -#ifdef U3_MEMORY_DEBUG - rod_u->all.fre_w = 0; -#endif - - _rod_vaal(u3R); -} - -void -_print_diff(c3_c* cap_c, c3_w a, c3_w b) -{ - c3_w diff = apar_p); - -#if 0 - /* If you're printing a lot of these you need to change - * u3a_print_memory from fprintf to u3l_log - */ - fprintf(stderr, "fall: from %s %p, to %s %p (cap 0x%x, was 0x%x)\r\n", - _(u3a_is_north(u3R)) ? "north" : "south", - u3R, - _(u3a_is_north(u3to(u3_road, u3R->par_p))) ? "north" : "south", - u3to(u3_road, u3R->par_p), - u3R->hat_p, - u3R->rut_p); - _print_diff("unused free", u3R->hat_p, u3R->cap_p); - _print_diff("freeing", u3R->rut_p, u3R->hat_p); - _print_diff("stack", u3R->cap_p, u3R->mat_p); - static c3_w wat_w = 500000000; - if (u3to(u3_road, u3R->par_p) == &u3H->rod_u) { - wat_w = 500000000; - } - else { - wat_w = c3_min(wat_w, - u3R->hat_p < u3R->cap_p ? - u3R->cap_p - u3R->hat_p : - u3R->hat_p - u3R->cap_p); - } - u3a_print_memory(stderr, "low water mark", wat_w); - -#endif - - u3to(u3_road, u3R->par_p)->pro.nox_d += u3R->pro.nox_d; - u3to(u3_road, u3R->par_p)->pro.cel_d += u3R->pro.cel_d; - - /* The new cap is the old hat - it's as simple as that. - */ - u3to(u3_road, u3R->par_p)->cap_p = u3R->hat_p; - - /* And, we're back home. - */ - u3R = u3to(u3_road, u3R->par_p); - u3R->kid_p = 0; -} - -/* u3m_v1_hate(): new, integrated leap mechanism (enter). -*/ -void -u3m_v1_hate(c3_w pad_w) -{ - u3_assert(0 == u3R->ear_p); - - u3R->ear_p = u3R->cap_p; - u3m_v1_leap(pad_w); - - u3R->bug.mer = u3i_string( - "emergency buffer with sufficient space to cons the trace and bail" - ); -} - -/* u3m_v1_love(): return product from leap. -*/ -u3_noun -u3m_v1_love(u3_noun pro) -{ - // save cache pointers from current road - // - u3p(u3h_root) byc_p = u3R->byc.har_p; - u3a_jets jed_u = u3R->jed; - - // fallback to parent road (child heap on parent's stack) - // - u3m_v1_fall(); - - // copy product and caches off our stack - // - pro = u3a_take(pro); - jed_u = u3j_take(jed_u); - byc_p = u3n_take(byc_p); - - // pop the stack - // - u3R->cap_p = u3R->ear_p; - u3R->ear_p = 0; - - // integrate junior caches - // - u3j_reap(jed_u); - u3n_reap(byc_p); - - return pro; -} - -/* u3m_v1_golf(): record cap_p length for u3m_v1_flog(). -*/ -c3_w -u3m_v1_golf(void) -{ - if ( c3y == u3a_is_north(u3R) ) { - return u3R->mat_p - u3R->cap_p; - } - else { - return u3R->cap_p - u3R->mat_p; - } -} - -/* u3m_v1_flog(): reset cap_p. -*/ -void -u3m_v1_flog(c3_w gof_w) -{ - // Enable memsets in case of memory corruption. - // - if ( c3y == u3a_is_north(u3R) ) { - u3_post bot_p = (u3R->mat_p - gof_w); - // c3_w len_w = (bot_w - u3R->cap_w); - - // memset(u3R->cap_w, 0, 4 * len_w); - u3R->cap_p = bot_p; - } - else { - u3_post bot_p = u3R->mat_p + gof_w; - // c3_w len_w = (u3R->cap_w - bot_w); - - // memset(bot_w, 0, 4 * len_w); // - u3R->cap_p = bot_p; - } -} - -/* u3m_v1_water(): produce watermarks. -*/ -void -u3m_v1_water(u3_post* low_p, u3_post* hig_p) -{ - // allow the segfault handler to fire before the road is set - // - // while not explicitly possible in the codebase, - // compiler optimizations can reorder stores - // - if ( !u3R ) { - *low_p = 0; - *hig_p = u3C.wor_i - 1; - } - // in a north road, hat points to the end of the heap + 1 word, - // while cap points to the top of the stack - // - else if ( c3y == u3a_is_north(u3R) ) { - *low_p = u3R->hat_p - 1; - *hig_p = u3R->cap_p; - } - // in a south road, hat points to the end of the heap, - // while cap points to the top of the stack + 1 word - // - else { - *low_p = u3R->cap_p - 1; - *hig_p = u3R->hat_p; - } -} - -/* u3m_v1_soft_top(): top-level safety wrapper. -*/ -u3_noun -u3m_v1_soft_top(c3_w mil_w, // timer ms - c3_w pad_w, // base memory pad - u3_funk fun_f, - u3_noun arg) -{ - u3_noun why, pro; - c3_l sig_l; - - /* Enter internal signal regime. - */ - _cm_signal_deep(mil_w); - - if ( 0 != (sig_l = rsignal_setjmp(u3_Signal)) ) { - // reinitialize trace state - // - u3t_init(); - - // return to blank state - // - _cm_signal_done(); - - // recover memory state from the top down - // - return _cm_signal_recover(sig_l, arg); - } - - /* Record the cap, and leap. - */ - u3m_v1_hate(pad_w); - - /* Trap for ordinary nock exceptions. - */ - if ( 0 == (why = (u3_noun)_setjmp(u3R->esc.buf)) ) { - pro = fun_f(arg); - - /* Make sure the inner routine did not create garbage. - */ - if ( u3C.wag_w & u3o_debug_ram ) { -#ifdef U3_CPU_DEBUG - if ( u3R->all.max_w > 1000000 ) { - u3a_print_memory(stderr, "execute: top", u3R->all.max_w); - } -#endif - u3m_v1_grab(pro, u3_none); - } - - /* Revert to external signal regime. - */ - _cm_signal_done(); - - /* Produce success, on the old road. - */ - pro = u3nc(0, u3m_v1_love(pro)); - } - else { - /* Overload the error result. - */ - pro = u3m_v1_love(why); - } - - /* Revert to external signal regime. - */ - _cm_signal_done(); - - /* Free the argument. - */ - u3z(arg); - - /* Return the product. - */ - return pro; -} - -/* u3m_v1_soft_sure(): top-level call assumed correct. -*/ -u3_noun -u3m_v1_soft_sure(u3_funk fun_f, u3_noun arg) -{ - u3_noun pro, pru = u3m_v1_soft_top(0, (1 << 18), fun_f, arg); - - u3_assert(_(u3du(pru))); - pro = u3k(u3t(pru)); - u3z(pru); - - return pro; -} - -/* u3m_v1_soft_slam: top-level call. -*/ -u3_noun _cm_slam(u3_noun arg) { return u3n_slam_on(u3h(arg), u3t(arg)); } -u3_noun -u3m_v1_soft_slam(u3_noun gat, u3_noun sam) -{ - return u3m_v1_soft_sure(_cm_slam, u3nc(gat, sam)); -} - -/* u3m_v1_soft_nock: top-level nock. -*/ -u3_noun _cm_nock(u3_noun arg) { return u3n_nock_on(u3h(arg), u3t(arg)); } -u3_noun -u3m_v1_soft_nock(u3_noun bus, u3_noun fol) -{ - return u3m_v1_soft_sure(_cm_nock, u3nc(bus, fol)); -} - -/* u3m_v1_soft_run(): descend into virtualization context. -*/ -u3_noun -u3m_v1_soft_run(u3_noun gul, - u3_funq fun_f, - u3_noun aga, - u3_noun agb) -{ - u3_noun why = 0, pro; - - /* Record the cap, and leap. - */ - u3m_v1_hate(1 << 18); - - /* Configure the new road. - */ - { - u3R->ski.gul = u3nc(gul, u3to(u3_road, u3R->par_p)->ski.gul); - u3R->pro.don = u3to(u3_road, u3R->par_p)->pro.don; - u3R->pro.trace = u3to(u3_road, u3R->par_p)->pro.trace; - u3R->bug.tax = 0; - } - u3t_on(coy_o); - - /* Trap for exceptions. - */ - if ( 0 == (why = (u3_noun)_setjmp(u3R->esc.buf)) ) { - u3t_off(coy_o); - pro = fun_f(aga, agb); - -#ifdef U3_CPU_DEBUG - if ( u3R->all.max_w > 1000000 ) { - u3a_print_memory(stderr, "execute: run", u3R->all.max_w); - } -#endif - - /* Today you can't run -g without memory debug, but you should be - * able to. - */ -#ifdef U3_MEMORY_DEBUG - if ( u3C.wag_w & u3o_debug_ram ) { - u3m_v1_grab(pro, u3_none); - } -#endif - - /* Produce success, on the old road. - */ - pro = u3nc(0, u3m_v1_love(pro)); - } - else { - u3t_init(); - - /* Produce - or fall again. - */ - { - u3_assert(_(u3du(why))); - switch ( u3h(why) ) { - default: u3_assert(0); return 0; - - case 0: { // unusual: bail with success. - pro = u3m_v1_love(why); - } break; - - case 1: { // blocking request - pro = u3m_v1_love(why); - } break; - - case 2: { // true exit - pro = u3m_v1_love(why); - } break; - - case 3: { // failure; rebail w/trace - u3_noun yod = u3m_v1_love(u3t(why)); - - u3m_v1_bail - (u3nt(3, - u3a_take(u3h(yod)), - u3kb_weld(u3t(yod), u3k(u3R->bug.tax)))); - } break; - - case 4: { // meta-bail - u3m_v1_bail(u3m_v1_love(u3t(why))); - } break; - } - } - } - - /* Release the arguments. - */ - { - u3z(gul); - u3z(aga); - u3z(agb); - } - - /* Return the product. - */ - return pro; -} - -/* u3m_v1_soft_esc(): namespace lookup. Produces direct result. -*/ -u3_noun -u3m_v1_soft_esc(u3_noun ref, u3_noun sam) -{ - u3_noun why, gul, pro; - - /* Assert preconditions. - */ - { - u3_assert(0 != u3R->ski.gul); - gul = u3h(u3R->ski.gul); - } - - /* Record the cap, and leap. - */ - u3m_v1_hate(1 << 18); - - /* Configure the new road. - */ - { - u3R->ski.gul = u3t(u3to(u3_road, u3R->par_p)->ski.gul); - u3R->pro.don = u3to(u3_road, u3R->par_p)->pro.don; - u3R->pro.trace = u3to(u3_road, u3R->par_p)->pro.trace; - u3R->bug.tax = 0; - } - - /* Trap for exceptions. - */ - if ( 0 == (why = (u3_noun)_setjmp(u3R->esc.buf)) ) { - pro = u3n_slam_on(gul, u3nc(ref, sam)); - - /* Fall back to the old road, leaving temporary memory intact. - */ - pro = u3m_v1_love(pro); - } - else { - u3t_init(); - - /* Push the error back up to the calling context - not the run we - ** are in, but the caller of the run, matching pure nock semantics. - */ - u3m_v1_bail(u3nc(4, u3m_v1_love(why))); - } - - /* Release the sample. Note that we used it above, but in a junior - ** road, so its refcount is intact. - */ - u3z(ref); - u3z(sam); - - /* Return the product. - */ - return pro; -} - -/* u3m_v1_grab(): garbage-collect the world, plus extra roots. -*/ -void -u3m_v1_grab(u3_noun som, ...) // terminate with u3_none -{ - // u3h_free(u3R->cax.har_p); - // u3R->cax.har_p = u3h_new(); - - u3m_v1_mark(0); - { - va_list vap; - u3_noun tur; - - va_start(vap, som); - - if ( som != u3_none ) { - u3a_mark_noun(som); - - while ( u3_none != (tur = va_arg(vap, u3_noun)) ) { - u3a_mark_noun(tur); - } - } - va_end(vap); - } - u3a_sweep(); -} - -/* u3m_v1_soft(): top-level wrapper. -** -** Produces [0 product] or [%error (list tank)], top last. -*/ -u3_noun -u3m_v1_soft(c3_w mil_w, - u3_funk fun_f, - u3_noun arg) -{ - u3_noun why; - - why = u3m_v1_soft_top(mil_w, (1 << 20), fun_f, arg); // 4M pad - - if ( 0 == u3h(why) ) { - return why; - } - else { - u3_noun tax, cod, pro; - - switch ( u3h(why) ) { - case 2: { - cod = c3__exit; - tax = u3t(why); - } break; - - case 3: { - cod = u3h(u3t(why)); - tax = u3t(u3t(why)); - } break; - - // don't use .^ at the top level! - // - default: { - u3m_v1_p("invalid mot", u3h(why)); - u3_assert(0); - } - } - - // don't call +mook if we have no kernel - // - // This is required to soft the boot sequence. - // - if ( 0 == u3A->roc ) { - while ( u3_nul != tax ) { - u3_noun dat, mot, val; - u3x_cell(tax, &dat, &tax); - - if ( c3y == u3r_cell(dat, &mot, &val) ) { - if ( c3__spot == mot ) { - u3m_v1_p("tax", val); - } - else if ( (c3__mean == mot) - && (c3y == u3a_is_atom(val)) ) - { - u3m_v1_p("men", val); - } - else { - u3m_v1_p("mot", mot); - } - } - } - - pro = u3nc(u3k(cod), u3_nul); - } - // %evil leaves no trace - // - else if ( c3__evil == cod ) { - pro = u3nc(u3k(cod), u3_nul); - } - else { - u3_noun mok = u3dc("mook", 2, u3k(tax)); - pro = u3nc(u3k(cod), u3k(u3t(mok))); - u3z(mok); - } - - u3z(why); - return pro; - } -} - -/* _cm_is_tas(): yes iff som (RETAIN) is @tas. -*/ -static c3_o -_cm_is_tas(u3_atom som, c3_w len_w) -{ - c3_w i_w; - - for ( i_w = 0; i_w < len_w; i_w++ ) { - c3_c c_c = u3r_byte(i_w, som); - - if ( islower(c_c) || - (isdigit(c_c) && (0 != i_w) && ((len_w - 1) != i_w)) - || '-' == c_c ) - { - continue; - } - return c3n; - } - return c3y; -} - -/* _cm_is_ta(): yes iff som (RETAIN) is @ta. -*/ -static c3_o -_cm_is_ta(u3_noun som, c3_w len_w) -{ - c3_w i_w; - - for ( i_w = 0; i_w < len_w; i_w++ ) { - c3_c c_c = u3r_byte(i_w, som); - - if ( (c_c < 32) || (c_c > 127) ) { - return c3n; - } - } - return c3y; -} - -/* _cm_hex(): hex byte. -*/ -c3_y _cm_hex(c3_y c_y) -{ - if ( c_y < 10 ) - return '0' + c_y; - else return 'a' + (c_y - 10); -} - -/* _cm_in_pretty: measure/cut prettyprint. -*/ -static c3_w -_cm_in_pretty(u3_noun som, c3_o sel_o, c3_c* str_c) -{ - if ( _(u3du(som)) ) { - c3_w sel_w, one_w, two_w; - - sel_w = 0; - if ( _(sel_o) ) { - if ( str_c ) { *(str_c++) = '['; } - sel_w += 1; - } - - one_w = _cm_in_pretty(u3h(som), c3y, str_c); - if ( str_c ) { - str_c += one_w; - *(str_c++) = ' '; - } - two_w = _cm_in_pretty(u3t(som), c3n, str_c); - if ( str_c ) { str_c += two_w; } - - if ( _(sel_o) ) { - if ( str_c ) { *(str_c++) = ']'; } - sel_w += 1; - } - return one_w + two_w + 1 + sel_w; - } - else { - if ( som < 65536 ) { - c3_c buf_c[6]; - c3_w len_w; - - snprintf(buf_c, 6, "%d", som); - len_w = strlen(buf_c); - - if ( str_c ) { strcpy(str_c, buf_c); str_c += len_w; } - return len_w; - } - else { - c3_w len_w = u3r_met(3, som); - - if ( _(_cm_is_tas(som, len_w)) ) { - c3_w len_w = u3r_met(3, som); - - if ( str_c ) { - *(str_c++) = '%'; - u3r_bytes(0, len_w, (c3_y *)str_c, som); - str_c += len_w; - } - return len_w + 1; - } - else if ( _(_cm_is_ta(som, len_w)) ) { - if ( str_c ) { - *(str_c++) = '\''; - u3r_bytes(0, len_w, (c3_y *)str_c, som); - str_c += len_w; - *(str_c++) = '\''; - } - return len_w + 2; - } - else { - c3_w len_w = u3r_met(3, som); - c3_c *buf_c = c3_malloc(2 + (2 * len_w) + 1); - c3_w i_w = 0; - c3_w a_w = 0; - - buf_c[a_w++] = '0'; - buf_c[a_w++] = 'x'; - - for ( i_w = 0; i_w < len_w; i_w++ ) { - c3_y c_y = u3r_byte(len_w - (i_w + 1), som); - - if ( (i_w == 0) && (c_y <= 0xf) ) { - buf_c[a_w++] = _cm_hex(c_y); - } else { - buf_c[a_w++] = _cm_hex(c_y >> 4); - buf_c[a_w++] = _cm_hex(c_y & 0xf); - } - } - buf_c[a_w] = 0; - len_w = a_w; - - if ( str_c ) { strcpy(str_c, buf_c); str_c += len_w; } - - c3_free(buf_c); - return len_w; - } - } - } -} - -/* u3m_v1_pretty(): dumb prettyprint to string. -*/ -c3_c* -u3m_v1_pretty(u3_noun som) -{ - c3_w len_w = _cm_in_pretty(som, c3y, 0); - c3_c* pre_c = c3_malloc(len_w + 1); - - _cm_in_pretty(som, c3y, pre_c); - pre_c[len_w] = 0; - return pre_c; -} - -/* _cm_in_pretty_path: measure/cut prettyprint. - * - * Modeled after _cm_in_pretty(), the backend to u3m_v1_p(), but with the - * assumption that we're always displaying a path. - */ -static c3_w -_cm_in_pretty_path(u3_noun som, c3_c* str_c) -{ - if ( _(u3du(som)) ) { - c3_w sel_w, one_w, two_w; - if ( str_c ) { - *(str_c++) = '/'; - } - sel_w = 1; - - one_w = _cm_in_pretty_path(u3h(som), str_c); - if ( str_c ) { - str_c += one_w; - } - - two_w = _cm_in_pretty_path(u3t(som), str_c); - if ( str_c ) { - str_c += two_w; - } - - return sel_w + one_w + two_w; - } - else { - c3_w len_w = u3r_met(3, som); - if ( str_c && len_w ) { - u3r_bytes(0, len_w, (c3_y *)str_c, som); - str_c += len_w; - } - return len_w; - } -} - -/* u3m_v1_pretty_path(): prettyprint a path to string. -*/ -c3_c* -u3m_v1_pretty_path(u3_noun som) -{ - c3_w len_w = _cm_in_pretty_path(som, NULL); - c3_c* pre_c = c3_malloc(len_w + 1); - - _cm_in_pretty_path(som, pre_c); - pre_c[len_w] = 0; - return pre_c; -} - -/* u3m_v1_p(): dumb print with caption. -*/ -void -u3m_v1_p(const c3_c* cap_c, u3_noun som) -{ - c3_c* pre_c = u3m_v1_pretty(som); - - u3l_log("%s: %s", cap_c, pre_c); - c3_free(pre_c); -} - -/* u3m_v1_tape(): dump a tape to stdout. -*/ -void -u3m_v1_tape(u3_noun tep) -{ - u3_noun tap = tep; - - while ( u3_nul != tap ) { - c3_c car_c; - - if ( u3h(tap) >= 127 ) { - car_c = '?'; - } else car_c = u3h(tap); - - putc(car_c, stdout); - tap = u3t(tap); - } - u3z(tep); -} - -/* u3m_v1_wall(): dump a wall to stdout. -*/ -void -u3m_v1_wall(u3_noun wol) -{ - u3_noun wal = wol; - - while ( u3_nul != wal ) { - u3m_v1_tape(u3k(u3h(wal))); - - putc(13, stdout); - putc(10, stdout); - - wal = u3t(wal); - } - u3z(wol); -} - -/* _cm_limits(): set up global modes and limits. -*/ -static void -_cm_limits(void) -{ - struct rlimit rlm; - - // Moar stack. - // - { - u3_assert( 0 == getrlimit(RLIMIT_STACK, &rlm) ); - - rlm.rlim_cur = c3_min(rlm.rlim_max, (65536 << 10)); - - if ( 0 != setrlimit(RLIMIT_STACK, &rlm) ) { - u3l_log("boot: stack size: %s", strerror(errno)); - exit(1); - } - } - - // Moar filez. - // - { - getrlimit(RLIMIT_NOFILE, &rlm); - - #ifdef U3_OS_osx - rlm.rlim_cur = c3_min(OPEN_MAX, rlm.rlim_max); - #else - rlm.rlim_cur = rlm.rlim_max; - #endif - - // no exit, not a critical limit - // - if ( 0 != setrlimit(RLIMIT_NOFILE, &rlm) ) { - u3l_log("boot: open file limit: %s", strerror(errno)); - } - } - - // Moar core. - // -# ifndef ASAN_ENABLED - { - getrlimit(RLIMIT_CORE, &rlm); - rlm.rlim_cur = RLIM_INFINITY; - - // no exit, not a critical limit - // - if ( 0 != setrlimit(RLIMIT_CORE, &rlm) ) { - u3l_log("boot: core limit: %s", strerror(errno)); - } - } -# endif -} - -/* u3m_v1_backup(): copy snapshot to .urb/bhk (if it doesn't exist yet). -*/ -c3_o -u3m_v1_backup(c3_o ovw_o) -{ - return u3e_backup(ovw_o); -} - -/* u3m_v1_fault(): handle a memory event with libsigsegv protocol. -*/ -c3_i -u3m_v1_fault(void* adr_v, c3_i ser_i) -{ - c3_w* adr_w = (c3_w*)adr_v; - u3_post low_p, hig_p; - - // let the stack overflow handler run. - // - if ( 0 == ser_i ) { - return 0; - } - // this could be avoided by registering the loom bounds in libsigsegv - // - else if ( (adr_w < u3_Loom) || (adr_w >= (u3_Loom + u3C.wor_i)) ) { - fprintf(stderr, "loom: external fault: %p (%p : %p)\r\n\r\n", - adr_w, u3_Loom, u3_Loom + u3C.wor_i); - u3_assert(0); - return 0; - } - - u3m_v1_water(&low_p, &hig_p); - - switch ( u3e_fault(low_p, hig_p, u3a_outa(adr_w)) ) { - // page tracking invariants violated, fatal - // - case u3e_flaw_sham: { - u3_assert(0); - return 0; - } - - // virtual memory failure (protections) - // - // XX s/b recoverable, need to u3m_v1_signal() a new mote - // - case u3e_flaw_base: { - u3_assert(0); - return 0; - } - - // loom limits exceeded, recoverable - // - case u3e_flaw_meme: { - u3m_v1_signal(c3__meme); // doesn't return - return 1; - } - - case u3e_flaw_good: return 1; - } - - u3_assert(!"unpossible"); -} - -/* u3m_v1_foul(): dirty all pages and disable tracking. -*/ -void -u3m_v1_foul(void) -{ - if ( c3n == u3e_yolo() ) { - return; - } - - u3e_foul(); -} - -/* u3m_v1_save(): update the checkpoint. -*/ -void -u3m_v1_save(void) -{ - u3_post low_p, hig_p; - u3m_v1_water(&low_p, &hig_p); - - u3_assert(u3R == &u3H->rod_u); - -#if 1 // XX redundant - { - c3_w low_w = u3a_heap(u3R); // old u3m_v1_water() - c3_w hig_w = u3a_temp(u3R) + c3_wiseof(u3v_home); - - c3_w nox_w = (low_w + ((1 << u3a_page) - 1)) >> u3a_page; - c3_w sox_w = (hig_w + ((1 << u3a_page) - 1)) >> u3a_page; - - c3_w nor_w = (low_p + ((1 << u3a_page) - 1)) >> u3a_page; - c3_w sop_w = hig_p >> u3a_page; - c3_w sor_w = u3P.pag_w - sop_w; - - if ( (nox_w < nor_w) || (sox_w < sor_w) ) { - fprintf(stderr, "loom: save strange nox %u nor %u sox %u sor %u\r\n", - nox_w, nor_w, sox_w, sor_w); - } - else if ( (nox_w > nor_w) || (sox_w > sor_w) ) { - fprintf(stderr, "loom: save wrong nox %u nor %u sox %u sor %u\r\n", - nox_w, nor_w, sox_w, sor_w); - u3_assert(!"busted"); - } - } -#endif - - return u3e_save(low_p, hig_p); -} - -/* u3m_v1_toss(): discard ephemeral memory. -*/ -void -u3m_v1_toss(void) -{ - u3_post low_p, hig_p; - u3m_v1_water(&low_p, &hig_p); - - if ( ((low_p + u3C.tos_w) < u3C.wor_i) - && (hig_p > u3C.tos_w) ) - { - low_p += u3C.tos_w; - hig_p -= u3C.tos_w; - - if ( low_p < hig_p ) { - u3e_toss(low_p, hig_p); - } - } -} - -/* u3m_v1_ward(): tend the guardpage. -*/ -void -u3m_v1_ward(void) -{ - u3_post low_p, hig_p; - u3m_v1_water(&low_p, &hig_p); - -#if 1 // XX redundant - { - c3_w low_w, hig_w; - - if ( c3y == u3a_is_north(u3R) ) { - low_w = u3R->hat_p; - hig_w = u3R->cap_p; - } - else { - low_w = u3R->cap_p; - hig_w = u3R->hat_p; - } - - if ( (low_w > (u3P.gar_w << u3a_page)) - || (hig_w < (u3P.gar_w << u3a_page)) ) - { - u3_assert( ((low_p >> u3a_page) >= u3P.gar_w) - || ((hig_p >> u3a_page) <= u3P.gar_w) ); - } - } -#endif - - return u3e_ward(low_p, hig_p); -} - -/* _cm_signals(): set up interrupts, etc. -*/ -static void -_cm_signals(void) -{ - if ( 0 != sigsegv_install_handler(u3m_v1_fault) ) { - u3l_log("boot: sigsegv install failed"); - exit(1); - } - -# if defined(U3_OS_PROF) - // Block SIGPROF, so that if/when we reactivate it on the - // main thread for profiling, we won't get hits in parallel - // on other threads. - if ( u3C.wag_w & u3o_debug_cpu ) { - sigset_t set; - - sigemptyset(&set); - sigaddset(&set, SIGPROF); - - if ( 0 != pthread_sigmask(SIG_BLOCK, &set, NULL) ) { - u3l_log("boot: thread mask SIGPROF: %s", strerror(errno)); - exit(1); - } - } -# endif -} - -/* _cm_malloc_ssl(): openssl-shaped malloc -*/ -static void* -_cm_malloc_ssl(size_t len_i -#if OPENSSL_VERSION_NUMBER >= 0x10100000L - , const char* file, int line -#endif - ) -{ - return u3a_malloc(len_i); -} - -/* _cm_realloc_ssl(): openssl-shaped realloc. -*/ -static void* -_cm_realloc_ssl(void* lag_v, size_t len_i -#if OPENSSL_VERSION_NUMBER >= 0x10100000L - , const char* file, int line -#endif - ) -{ - return u3a_realloc(lag_v, len_i); -} - -/* _cm_free_ssl(): openssl-shaped free. -*/ -static void -_cm_free_ssl(void* tox_v -#if OPENSSL_VERSION_NUMBER >= 0x10100000L - , const char* file, int line -#endif - ) -{ - return u3a_free(tox_v); -} - -extern void u3je_secp_init(void); - -/* _cm_crypto(): initialize openssl and crypto jets. -*/ -static void -_cm_crypto() -{ - /* Initialize OpenSSL with loom allocation functions. */ - if ( 0 == CRYPTO_set_mem_functions(&_cm_malloc_ssl, - &_cm_realloc_ssl, - &_cm_free_ssl) ) { - u3l_log("%s", "openssl initialization failed"); - abort(); - } - - u3je_secp_init(); -} - -/* _cm_realloc2(): gmp-shaped realloc. -*/ -static void* -_cm_realloc2(void* lag_v, size_t old_i, size_t new_i) -{ - return u3a_realloc(lag_v, new_i); -} - -/* _cm_free2(): gmp-shaped free. -*/ -static void -_cm_free2(void* tox_v, size_t siz_i) -{ - return u3a_free(tox_v); -} - -/* u3m_v1_init(): start the environment. -*/ -void -u3m_v1_init(size_t len_i) -{ - _cm_limits(); - _cm_signals(); - _cm_crypto(); - - // make sure GMP uses our malloc. - // - mp_set_memory_functions(u3a_malloc, _cm_realloc2, _cm_free2); - - // make sure that [len_i] is a fully-addressible non-zero power of two. - // - if ( !len_i - || (len_i & (len_i - 1)) - || (len_i < (1 << (u3a_page + 2))) - || (len_i > u3a_bytes) ) - { - u3l_log("loom: bad size: %zu", len_i); - exit(1); - } - - // map at fixed address. - // - { - void* map_v = mmap((void *)u3_Loom, - len_i, - (PROT_READ | PROT_WRITE), - (MAP_ANON | MAP_FIXED | MAP_PRIVATE), - -1, 0); - - if ( -1 == (c3_ps)map_v ) { - map_v = mmap((void *)0, - len_i, - (PROT_READ | PROT_WRITE), - (MAP_ANON | MAP_PRIVATE), - -1, 0); - - u3l_log("boot: mapping %zuMB failed", len_i >> 20); - u3l_log("see urbit.org/using/install/#about-swap-space" - " for adding swap space"); - if ( -1 != (c3_ps)map_v ) { - u3l_log("if porting to a new platform, try U3_OS_LoomBase %p", - map_v); - } - exit(1); - } - - u3C.wor_i = len_i >> 2; - u3l_log("loom: mapped %zuMB", len_i >> 20); - } -} - -extern void u3je_secp_stop(void); - -/* u3m_v1_stop(): graceful shutdown cleanup. -*/ -void -u3m_v1_stop() -{ - u3e_stop(); - u3je_secp_stop(); -} - -/* u3m_v1_boot(): start the u3 system. return next event, starting from 1. -*/ -c3_d -u3m_v1_boot(c3_c* dir_c, size_t len_i) -{ - c3_o nuu_o; - - u3C.dir_c = dir_c; - - /* Activate the loom. - */ - u3m_v1_init(len_i); - - /* Activate the storage system. - */ - nuu_o = u3e_live(c3n, dir_c); - - /* Activate tracing. - */ - u3C.slog_f = 0; - u3C.sign_hold_f = 0; - u3C.sign_move_f = 0; - u3t_init(); - - /* Construct or activate the allocator. - */ - u3m_v1_pave(nuu_o); - - /* Initialize the jet system. - */ - { - c3_w len_w = u3j_boot(nuu_o); - u3l_log("boot: installed %d jets", len_w); - } - - /* Reactivate jets on old kernel. - */ - if ( c3n == nuu_o ) { - u3j_ream(); - u3n_ream(); - return u3A->eve_d; - } - else { - /* Basic initialization. - */ - memset(u3A, 0, sizeof(*u3A)); - return 0; - } -} - -/* u3m_v1_boot_lite(): start without checkpointing. -*/ -c3_d -u3m_v1_boot_lite(size_t len_i) -{ - /* Activate the loom. - */ - u3m_v1_init(len_i); - - /* Activate tracing. - */ - u3C.slog_f = 0; - u3C.sign_hold_f = 0; - u3C.sign_move_f = 0; - u3t_init(); - - /* Construct or activate the allocator. - */ - u3m_v1_pave(c3y); - - /* Place the guard page. - */ - u3e_init(); - - /* Initialize the jet system. - */ - u3j_boot(c3y); - - /* Basic initialization. - */ - memset(u3A, 0, sizeof(*u3A)); - return 0; -} - /* u3m_v1_reclaim: clear persistent caches to reclaim memory */ void u3m_v1_reclaim(void) { - u3v_reclaim(); // XX can we delete this? need to check rewrite_compact that roots are properly handled - u3j_reclaim(); // XX need to version - u3n_reclaim(); // XX need to version - u3a_reclaim(); // XX can we delete this? need to check rewrite_compact that roots are properly handled -} - -/* _cm_pack_rewrite(): trace through arena, rewriting pointers. - * XX need to version; dynamic scope insanity! -*/ -static void -_cm_pack_rewrite(void) -{ - // XX fix u3a_rewrite* to support south roads - // - u3_assert( &(u3H->rod_u) == u3R ); - - // NB: these implementations must be kept in sync with u3m_v1_reclaim(); - // anything not reclaimed must be rewritable - // - u3v_rewrite_compact(); - u3j_rewrite_compact(); - u3n_rewrite_compact(); - u3a_rewrite_compact(); -} - - -static void -_migrate_v1_reclaim() -{ - fprintf(stderr, "loom: migration reclaim\r\n"); - u3m_v1_reclaim(); -} - -static void -_migrate_v1_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_v1_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(); // XX need to version - u3C.migration_state = MIG_NONE; -} - -static void -_migrate_v1_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_v1_migrate: perform loom migration if necessary. - ver_w - target version -*/ -void -u3m_v1_migrate(void) -{ - fprintf(stderr, "loom: pointer compression migration running...\r\n"); - - /* packing first simplifies migration logic and minimizes required buffer space */ - // XX determine if we need to version this for the v2 migration - // u3m_v1_pack(); - - /* perform the migration in a pattern similar to |pack */ - _migrate_v1_reclaim(); - _migrate_v1_seek(&u3H->rod_u); - _migrate_v1_rewrite(); - _migrate_v1_move(&u3H->rod_u); - - /* finally update the version and commit to disk */ - // u3H->ver_w = ver_w; maybe do this outside of this function + u3v_reclaim(); + u3j_v1_reclaim(); + u3n_v1_reclaim(); + u3a_v1_reclaim(); } diff --git a/pkg/noun/v1/manage.h b/pkg/noun/v1/manage.h index fb2719acb2..07f85409cc 100644 --- a/pkg/noun/v1/manage.h +++ b/pkg/noun/v1/manage.h @@ -9,185 +9,9 @@ /** System management. **/ - /* u3m_v1_boot(): start the u3 system. return next event, starting from 1. - */ - c3_d - u3m_v1_boot(c3_c* dir_c, size_t len_i); - - /* u3m_v1_boot_lite(): start without checkpointing. - */ - c3_d - u3m_v1_boot_lite(size_t len_i); - - /* u3m_v1_stop(): graceful shutdown cleanup. */ - void - u3m_v1_stop(void); - - /* u3m_v1_bail(): bail out. Does not return. - ** - ** Bail motes: - ** - ** %exit :: semantic failure - ** %evil :: bad crypto - ** %intr :: interrupt - ** %fail :: execution failure - ** %foul :: assert failure - ** %need :: network block - ** %meme :: out of memory - ** %time :: timed out - ** %oops :: assertion failure - */ - c3_i - u3m_v1_bail(c3_m how_m) __attribute__((noreturn)); - - /* u3m_v1_fault(): handle a memory event with libsigsegv protocol. - */ - c3_i - u3m_v1_fault(void* adr_v, c3_i ser_i); - - /* u3m_v1_foul(): dirty all pages and disable tracking. - */ - void - u3m_v1_foul(void); - - /* u3m_v1_backup(): copy snapshot to .urb/bhk (if it doesn't exist yet). - */ - c3_o - u3m_v1_backup(c3_o); - - /* u3m_v1_save(): update the checkpoint. - */ - void - u3m_v1_save(void); - - /* u3m_v1_toss(): discard ephemeral memory. - */ - void - u3m_v1_toss(void); - - /* u3m_v1_ward(): tend the guardpage. - */ - void - u3m_v1_ward(void); - - /* u3m_v1_init(): start the environment. - */ - void - u3m_v1_init(size_t len_i); - - /* u3m_v1_pave(): instantiate or activate image. - */ - void - u3m_v1_pave(c3_o nuu_o); - - /* u3m_v1_signal(): treat a nock-level exception as a signal interrupt. - */ - void - u3m_v1_signal(u3_noun sig_l); - - /* u3m_v1_file(): load file, as atom, or bail. - */ - u3_noun - u3m_v1_file(c3_c* pas_c); - - /* u3m_v1_error(): bail out with %exit, ct_pushing error. - */ - c3_i - u3m_v1_error(c3_c* str_c); - - /* u3m_v1_hate(): new, integrated leap mechanism (enter). - */ - void - u3m_v1_hate(c3_w pad_w); - - /* u3m_v1_love(): return product from leap. - */ - u3_noun - u3m_v1_love(u3_noun pro); - - /* u3m_v1_soft(): system soft wrapper. unifies unix and nock errors. - ** - ** Produces [%$ result] or [%error (list tank)]. - */ - u3_noun - u3m_v1_soft(c3_w mil_w, u3_funk fun_f, u3_noun arg); - - /* u3m_v1_soft_slam: top-level call. - */ - u3_noun - u3m_v1_soft_slam(u3_noun gat, u3_noun sam); - - /* u3m_v1_soft_nock: top-level nock. - */ - u3_noun - u3m_v1_soft_nock(u3_noun bus, u3_noun fol); - - /* u3m_v1_soft_sure(): top-level call assumed correct. - */ - u3_noun - u3m_v1_soft_sure(u3_funk fun_f, u3_noun arg); - - /* u3m_v1_soft_run(): descend into virtualization context. - */ - u3_noun - u3m_v1_soft_run(u3_noun gul, - u3_funq fun_f, - u3_noun aga, - u3_noun agb); - - /* u3m_v1_soft_esc(): namespace lookup to (unit ,*). - */ - u3_noun - u3m_v1_soft_esc(u3_noun ref, u3_noun sam); - - /* u3m_v1_mark(): mark all nouns in the road. - */ - c3_w - u3m_v1_mark(FILE* fil_u); - - /* u3m_v1_grab(): garbage-collect the world, plus extra roots. - */ - void - u3m_v1_grab(u3_noun som, ...); // terminate with u3_none - - /* u3m_v1_water(): produce high and low watermarks. Asserts u3R == u3H. - */ - void - u3m_v1_water(u3_post* low_p, u3_post* hig_p); - - /* u3m_v1_pretty(): dumb prettyprint to string. RETAIN. - */ - c3_c* - u3m_v1_pretty(u3_noun som); - - /* u3m_v1_pretty_path(): prettyprint a path to string. RETAIN. - */ - c3_c* - u3m_v1_pretty_path(u3_noun som); - - /* u3m_v1_p(): dumb print with caption. RETAIN. - */ - void - u3m_v1_p(const c3_c* cap_c, u3_noun som); - - /* u3m_v1_tape(): dump a tape to stdout. - */ - void - u3m_v1_tape(u3_noun tep); - - /* u3m_v1_wall(): dump a wall to stdout. - */ - void - u3m_v1_wall(u3_noun wol); - /* u3m_v1_reclaim: clear persistent caches to reclaim memory */ void u3m_v1_reclaim(void); - /* u3m_v1_pack: compact (defragment) memory, returns u3a_open delta. - */ - c3_w - u3m_v1_pack(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..ffd390d969 --- /dev/null +++ b/pkg/noun/v1/nock.c @@ -0,0 +1,61 @@ +/// @file + +#include "pkg/noun/nock.h" +#include "pkg/noun/v1/nock.h" + +#include "pkg/noun/v1/hashtable.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_free() -- the value is a post to a u3n_v1_prog. + // Note that the hank cache *must* also be freed (in u3j_reclaim()) + // + u3n_v1_free(); + u3R->byc.har_p = u3h_new(); +} + +/* _cn_prog_free(): free memory retained by program pog_u +** NB: copy of _cn_prog_free in pkg/noun/nock.c +*/ +static void +_cn_prog_free(u3n_prog* pog_u) +{ + c3_w dex_w; + for (dex_w = 0; dex_w < pog_u->lit_u.len_w; ++dex_w) { + u3z(pog_u->lit_u.non[dex_w]); + } + for (dex_w = 0; dex_w < pog_u->mem_u.len_w; ++dex_w) { + u3z(pog_u->mem_u.sot_u[dex_w].key); + } + for (dex_w = 0; dex_w < pog_u->cal_u.len_w; ++dex_w) { + u3j_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_rite_lose(&(pog_u->reg_u.rit_u[dex_w])); + } + u3a_free(pog_u); +} + + +/* _n_feb(): u3h_walk helper for u3n_free + */ +static void +_n_feb(u3_noun kev) +{ + _cn_prog_free(u3to(u3n_prog, u3t(kev))); +} + +/* u3n_v1_free(): free bytecode cache + */ +void +u3n_v1_free() +{ + u3p(u3h_root) har_p = u3R->byc.har_p; + u3h_v1_walk(har_p, _n_feb); + u3h_v1_free(har_p); +} diff --git a/pkg/noun/v1/nock.h b/pkg/noun/v1/nock.h new file mode 100644 index 0000000000..c64dd2f487 --- /dev/null +++ b/pkg/noun/v1/nock.h @@ -0,0 +1,25 @@ +/// @file + +#ifndef U3_NOCK_V1_H +#define U3_NOCK_V1_H + +#include "pkg/noun/jets.h" + + /** 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); + + /* u3n_v1_rewrite_compact(): rewrite bytecode cache for compaction. + */ + void + u3n_v1_rewrite_compact(); + +#endif /* ifndef U3_NOCK_V1_H */ \ No newline at end of file diff --git a/pkg/noun/v2/allocate.c b/pkg/noun/v2/allocate.c index 9277259e52..d30629487a 100644 --- a/pkg/noun/v2/allocate.c +++ b/pkg/noun/v2/allocate.c @@ -1,5 +1,6 @@ /// @file +#include "pkg/noun/allocate.h" #include "pkg/noun/v2/allocate.h" #include "pkg/noun/v2/hashtable.h" @@ -49,10 +50,8 @@ u3a_v2_rewritten_noun(u3_noun som) } /* u3a_v2_rewrite_compact(): rewrite pointers in ad-hoc persistent road structures. - * XX need to version */ void -// u3a_v2_v1_rewrite_compact(u3a_v2_v1_road *rod_u) u3a_v2_rewrite_compact(void) { u3a_v2_rewrite_noun(u3R->ski.gul); @@ -61,7 +60,7 @@ u3a_v2_rewrite_compact(void) u3a_v2_rewrite_noun(u3R->pro.don); u3a_v2_rewrite_noun(u3R->pro.day); u3a_v2_rewrite_noun(u3R->pro.trace); - u3h_rewrite(u3R->cax.har_p); + u3h_v2_rewrite(u3R->cax.har_p); u3R->ski.gul = u3a_v2_rewritten_noun(u3R->ski.gul); u3R->bug.tax = u3a_v2_rewritten_noun(u3R->bug.tax); diff --git a/pkg/noun/v2/allocate.h b/pkg/noun/v2/allocate.h index 0d4f7279e2..f0cb2997c8 100644 --- a/pkg/noun/v2/allocate.h +++ b/pkg/noun/v2/allocate.h @@ -7,7 +7,7 @@ #include "pkg/noun/v2/manage.h" #include "options.h" - /** Constants. XX TODO + /** Constants. **/ /** inline functions. diff --git a/pkg/noun/v2/hashtable.c b/pkg/noun/v2/hashtable.c index 3cfbf11d1a..47dadc5311 100644 --- a/pkg/noun/v2/hashtable.c +++ b/pkg/noun/v2/hashtable.c @@ -1,8 +1,11 @@ /// @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" #include "imprison.h" #include "retrieve.h" @@ -98,7 +101,6 @@ _ch_walk_buck(u3h_buck* hab_u, void (*fun_f)(u3_noun, void*), void* wit) } /* _ch_walk_node(): walk node for gc. -** NB: copy of _ch_walk_node in pkg/noun/hashtable.c */ static void _ch_walk_node(u3h_node* han_u, c3_w lef_w, void (*fun_f)(u3_noun, void*), void* wit) @@ -117,7 +119,7 @@ _ch_walk_node(u3h_node* han_u, c3_w lef_w, void (*fun_f)(u3_noun, void*), void* fun_f(kev, wit); } else { - void* hav_v = u3h_slot_to_node(sot_w); + void* hav_v = u3h_v2_slot_to_node(sot_w); if ( 0 == lef_w ) { _ch_walk_buck(hav_v, fun_f, wit); @@ -209,8 +211,8 @@ _ch_rewrite_node(u3h_node* han_u, c3_w lef_w) u3a_v2_rewrite_noun(kev); } else { - void* hav_v = u3h_v2_slot_to_node(sot_w); - u3h_node* nod_u = u3to(u3h_node,u3a_v2_rewritten(u3of(u3h_node,hav_v))); + void* hav_v = u3h_v1_slot_to_node(sot_w); + u3h_node* nod_u = u3to(u3h_node, u3a_v1_rewritten(u3of(u3h_node,hav_v))); if (u3C.migration_state == MIG_REWRITE_COMPRESSED) u3C.vits_w = 1; @@ -249,6 +251,7 @@ u3h_v2_rewrite(u3p(u3h_root) har_p) u3a_v2_rewrite_noun(kev); } else if ( _(u3h_slot_is_node(sot_w)) ) { + // XX check for correctness u3h_node* han_u = u3h_v2_slot_to_node(sot_w); u3h_node* nod_u = u3to(u3h_node, u3a_rewritten(u3of(u3h_node,han_u))); diff --git a/pkg/noun/v2/hashtable.h b/pkg/noun/v2/hashtable.h index e68f1638d5..c1a734b76c 100644 --- a/pkg/noun/v2/hashtable.h +++ b/pkg/noun/v2/hashtable.h @@ -13,16 +13,8 @@ *** *** Coordinate with u3_noun definition! **/ - /* u3h_v2_slot_is_null(): yes iff slot is empty - ** u3h_v2_slot_is_noun(): yes iff slot contains a key/value cell - ** u3h_v2_slot_is_node(): yes iff slot contains a subtable/bucket - ** u3h_v2_slot_is_warm(): yes iff fresh bit is set - ** u3h_v2_slot_to_node(): slot to node pointer + /* u3h_v2_slot_to_node(): slot to node pointer ** u3h_v2_node_to_slot(): node pointer to slot - ** u3h_v2_slot_to_noun(): slot to cell - ** u3h_v2_noun_to_slot(): cell to slot - ** u3h_v2_noun_be_warm(): warm mutant - ** u3h_v2_noun_be_cold(): cold mutant */ # define u3h_v2_slot_to_node(sot) (u3a_into(((sot) & 0x3fffffff) << u3C.vits_w)) # define u3h_v2_node_to_slot(ptr) ((u3a_outa((ptr)) >> u3C.vits_w) | 0x40000000) @@ -39,7 +31,7 @@ /* u3h_v2_rewrite(): rewrite hashtable for compaction. */ void - u3h_v2_rewrite(u3p(u3h_v2_root) har_p); + u3h_v2_rewrite(u3p(u3h_root) har_p); /* u3h_v2_walk_with(): traverse hashtable with key, value fn and data * argument; RETAINS. diff --git a/pkg/noun/v2/jets.c b/pkg/noun/v2/jets.c index d3dcd21f4f..840a8cbfe2 100644 --- a/pkg/noun/v2/jets.c +++ b/pkg/noun/v2/jets.c @@ -1,9 +1,12 @@ /// @file +#include "pkg/noun/vortex.h" + #include "pkg/noun/jets.h" +#include "pkg/noun/v1/jets.h" #include "pkg/noun/v2/jets.h" -#include "v2/hashtable.h" +#include "pkg/noun/v2/hashtable.h" /** Data structures. **/ @@ -16,6 +19,9 @@ typedef struct { u3j_site sit_u; // call-site data } _cj_hank; +/** Functions. +**/ + /* _cj_free_hank(): free an entry from the hank cache. ** NB: copy of _cj_free_hank() from pkg/noun/jets.c */ @@ -30,9 +36,7 @@ _cj_free_hank(u3_noun kev) u3a_wfree(han_u); } - /* u3j_v2_reclaim(): clear ad-hoc persistent caches to reclaim memory. -** XX need to version */ void u3j_v2_reclaim(void) @@ -47,16 +51,16 @@ u3j_v2_reclaim(void) // clear the jet hank cache // - u3h_v1_walk(u3R->jed.han_p, _cj_free_hank); - u3h_v1_free(u3R->jed.han_p); - u3R->jed.han_p = u3h_v1_new(); + u3h_v2_walk(u3R->jed.han_p, _cj_free_hank); + u3h_v2_free(u3R->jed.han_p); + u3R->jed.han_p = u3h_new(); } /* u3j_v2_rewrite_compact(): rewrite jet state for compaction. * * NB: u3R->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_v1_walk, using u3j_v2_mark as a + * 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. */ @@ -69,12 +73,12 @@ u3j_v2_rewrite_compact() u3h_v2_rewrite(u3R->jed.bas_p); if ( u3R == &(u3H->rod_u) ) { - u3h_v1_rewrite(u3R->jed.hot_p); - u3R->jed.hot_p = u3a_v2_rewritten(u3R->jed.hot_p); + u3h_v2_rewrite(u3R->jed.hot_p); + u3R->jed.hot_p = u3a_rewritten(u3R->jed.hot_p); } - u3R->jed.war_p = u3a_v2_rewritten(u3R->jed.war_p); - u3R->jed.cod_p = u3a_v2_rewritten(u3R->jed.cod_p); - u3R->jed.han_p = u3a_v2_rewritten(u3R->jed.han_p); - u3R->jed.bas_p = u3a_v2_rewritten(u3R->jed.bas_p); + u3R->jed.war_p = u3a_rewritten(u3R->jed.war_p); + u3R->jed.cod_p = u3a_rewritten(u3R->jed.cod_p); + u3R->jed.han_p = u3a_rewritten(u3R->jed.han_p); + u3R->jed.bas_p = u3a_rewritten(u3R->jed.bas_p); } diff --git a/pkg/noun/v2/jets.h b/pkg/noun/v2/jets.h index b071e9c7e0..5688a6de29 100644 --- a/pkg/noun/v2/jets.h +++ b/pkg/noun/v2/jets.h @@ -3,7 +3,7 @@ #ifndef U3_JETS_V2_H #define U3_JETS_V2_H -#include "allocate.h" +#include "pkg/noun/allocate.h" #include "c3.h" #include "types.h" diff --git a/pkg/noun/v2/manage.c b/pkg/noun/v2/manage.c index f0d7e9048d..79a694c851 100644 --- a/pkg/noun/v2/manage.c +++ b/pkg/noun/v2/manage.c @@ -59,7 +59,7 @@ static void _migrate_reclaim() { fprintf(stderr, "loom: migration reclaim\r\n"); - u3m_reclaim(); + u3m_v2_reclaim(); } static void