From fcedfddf00b3f994e4f4e40332ac7fc192c63244 Mon Sep 17 00:00:00 2001 From: polwex Date: Sun, 5 Oct 2025 21:56:51 +0700 Subject: claude is gud --- vere/pkg/noun/jets.c | 2445 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2445 insertions(+) create mode 100644 vere/pkg/noun/jets.c (limited to 'vere/pkg/noun/jets.c') diff --git a/vere/pkg/noun/jets.c b/vere/pkg/noun/jets.c new file mode 100644 index 0000000..3598364 --- /dev/null +++ b/vere/pkg/noun/jets.c @@ -0,0 +1,2445 @@ +/// @file + +#include "jets.h" + +#include "allocate.h" +#include "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.h" +#include "vortex.h" +#include "xtract.h" + + +/** 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_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_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 || + (((c3_w)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_git(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_put(u3R->jed.hot_p, key, toh); + u3z(key); + } + } + + 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_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_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_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_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_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_free(u3R->jed.hot_p); + } + u3R->jed.hot_p = u3h_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; +} + +static inline c3_w +_cj_of_hank(u3j_hank *han_u) +{ + u3_post han_p = u3of(u3j_hank, han_u); + return han_p >> u3a_vits; +} + +static inline u3j_hank* +_cj_to_hank(c3_w han_w) +{ + u3_post han_p = han_w << u3a_vits; + return u3to(u3j_hank, han_p); +} + +/* cj_hank_find(): find cached hook information, keyed by arbitrary + * prefix and term cords. RETAIN. + */ +static u3j_hank* +_cj_hank_find(u3_noun pre, u3_noun tam) +{ + u3_noun key = u3nc(u3k(pre), u3k(tam)); + u3_noun got = u3h_git(u3R->jed.han_p, key); + + if ( u3_none != got ) { + u3z(key); + return _cj_to_hank(got); + } + else { + u3j_hank* new_u = u3a_walloc(c3_wiseof(u3j_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_git(rod_u->jed.han_p, key); + } + + if ( u3_none == got ) { + new_u->hax = u3_none; + } + else { + u3j_hank* old_u = _cj_to_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_put(u3R->jed.han_p, key, _cj_of_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(u3j_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(u3j_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(u3j_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); // XX these may be u3_none + 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)); +} + +/* _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; + u3j_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_put(u3R->jed.cod_p, bat, u3nc(u3k(bas), reg)); + u3h_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_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_take_with cb for taking hanks +*/ +static c3_w +_cj_take_hank_cb(c3_w nah_w) +{ + u3j_hank* nah_u = _cj_to_hank(nah_w); + u3j_hank* han_u = u3a_walloc(c3_wiseof(u3j_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 _cj_of_hank(han_u); +} + +/* u3j_take(): copy junior jet state. +*/ +u3a_jets +u3j_take(u3a_jets jed_u) +{ + jed_u.war_p = u3h_take(jed_u.war_p); + jed_u.cod_p = u3h_take(jed_u.cod_p); + jed_u.han_p = u3h_take_with(jed_u.han_p, _cj_take_hank_cb); + jed_u.bas_p = u3h_take(jed_u.bas_p); + return jed_u; +} + +/* _cj_merge_hank_cb(): u3h_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_root) han_p = *(u3p(u3h_root)*)wit; + u3j_hank* nah_u; + u3_noun key; + c3_w nah_w; + u3x_cell(kev, &key, &nah_w); + + nah_u = _cj_to_hank(nah_w); + + if ( u3_none == nah_u->hax ) { + u3a_wfree(nah_u); + } + else { + u3j_hank* han_u; + u3_weak got = u3h_git(u3R->jed.han_p, key); + + if ( u3_none == got ) { + han_u = nah_u; + } + else { + han_u = _cj_to_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_put(han_p, key, _cj_of_hank(han_u)); + } +} + +/* u3j_reap(): promote jet state. +*/ +void +u3j_reap(u3a_jets jed_u) +{ + u3h_uni(u3R->jed.war_p, jed_u.war_p); + u3h_free(jed_u.war_p); + + u3h_uni(u3R->jed.cod_p, jed_u.cod_p); + u3h_free(jed_u.cod_p); + + u3h_walk_with(jed_u.han_p, _cj_merge_hank_cb, &u3R->jed.han_p); + u3h_free(jed_u.han_p); + + u3h_uni(u3R->jed.bas_p, jed_u.bas_p); + u3h_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_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_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(&(_cj_to_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_free(u3R->jed.war_p); + u3R->jed.war_p = u3h_new(); + u3h_walk_with(u3R->jed.cod_p, _cj_warm_tap, &rel); + _cj_ream(rel); + u3z(rel); + + u3h_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_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_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); + } + } +} + +/* u3j_rite_lose(): lose references of u3j_rite (but do not free). + */ +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; + u3j_hank* han_u = _cj_to_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. +*/ +u3m_quac* +u3j_mark() +{ + u3m_quac** qua_u = c3_malloc(sizeof(*qua_u) * 7); + + qua_u[0] = c3_calloc(sizeof(*qua_u[0])); + qua_u[0]->nam_c = strdup("warm jet state"); + qua_u[0]->siz_w = u3h_mark(u3R->jed.war_p) * 4; + + qua_u[1] = c3_calloc(sizeof(*qua_u[1])); + qua_u[1]->nam_c = strdup("cold jet state"); + qua_u[1]->siz_w = u3h_mark(u3R->jed.cod_p) * 4; + + qua_u[2] = c3_calloc(sizeof(*qua_u[2])); + qua_u[2]->nam_c = strdup("hank cache"); + qua_u[2]->siz_w = u3h_mark(u3R->jed.han_p) * 4; + + qua_u[3] = c3_calloc(sizeof(*qua_u[3])); + qua_u[3]->nam_c = strdup("battery hash cache"); + qua_u[3]->siz_w = u3h_mark(u3R->jed.bas_p) * 4; + + qua_u[4] = c3_calloc(sizeof(*qua_u[4])); + qua_u[4]->nam_c = strdup("call site cache"); + u3h_walk_with(u3R->jed.han_p, _cj_mark_hank, &qua_u[4]->siz_w); + qua_u[4]->siz_w *= 4; + + c3_w sum_w = 0; + for ( c3_w i_w = 0; i_w < 5; i_w++ ) { + sum_w += qua_u[i_w]->siz_w; + } + + u3m_quac* tot_u = c3_calloc(sizeof(*tot_u)); + tot_u->nam_c = strdup("total jet stuff"); + + if ( u3R == &(u3H->rod_u) ) { + qua_u[5] = c3_calloc(sizeof(*qua_u[5])); + qua_u[5]->nam_c = strdup("hot jet state"); + qua_u[5]->siz_w = u3h_mark(u3R->jed.hot_p) * 4; + + sum_w += qua_u[5]->siz_w; + + qua_u[6] = NULL; + + tot_u->siz_w = sum_w; + tot_u->qua_u = qua_u; + + return tot_u; + } else { + qua_u[5] = NULL; + + tot_u->siz_w = sum_w; + tot_u->qua_u = qua_u; + + return tot_u; + } +} + +/* u3j_free_hank(): free an entry from the hank cache. +*/ +void +u3j_free_hank(u3_noun kev) +{ + u3j_hank* han_u = _cj_to_hank(u3t(kev)); + if ( u3_none != han_u->hax ) { + u3z(han_u->hax); + u3j_site_lose(&(han_u->sit_u)); + } + u3a_wfree(han_u); +} + +/* u3j_free(): free jet state. +*/ +void +u3j_free(void) +{ + u3h_walk(u3R->jed.han_p, u3j_free_hank); + u3h_free(u3R->jed.war_p); + u3h_free(u3R->jed.cod_p); + u3h_free(u3R->jed.han_p); + u3h_free(u3R->jed.bas_p); + if ( u3R == &(u3H->rod_u) ) { + u3h_free(u3R->jed.hot_p); + } +} + +/* u3j_reclaim(): clear ad-hoc persistent caches to reclaim memory. +*/ +void +u3j_reclaim(void) +{ + // re-establish the warm jet state + // + // XX might this reduce fragmentation? + // + // if ( &(u3H->rod_u) == u3R ) { + // u3j_ream(); + // } + // clear the jet hank cache + // + u3h_walk(u3R->jed.han_p, u3j_free_hank); + u3h_free(u3R->jed.han_p); + u3R->jed.han_p = u3h_new(); +} + +/* u3j_rewrite_compact(): rewrite jet state for compaction. + * + * NB: u3R->jed.han_p *must* be cleared (currently via u3j_reclaim above) + * since it contains hanks which are not nouns but have loom pointers. + * Alternately, rewrite the entries with u3h_walk, using u3j_mark as a + * template for how to walk. There's an untested attempt at this in git + * history at e8a307a. +*/ +void +u3j_rewrite_compact(void) +{ + u3h_relocate(&(u3R->jed.war_p)); + u3h_relocate(&(u3R->jed.cod_p)); + u3h_relocate(&(u3R->jed.han_p)); + u3h_relocate(&(u3R->jed.bas_p)); + + if ( u3R == &(u3H->rod_u) ) { + u3h_relocate(&(u3R->jed.hot_p)); + } +} -- cgit v1.2.3