Merge pull request #3612 from urbit/jb/slab

u3: replaces atom slab-allocation api for efficiency
This commit is contained in:
Joe Bryan 2020-09-30 17:49:40 -07:00 committed by GitHub
commit 6bc52c0591
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 623 additions and 538 deletions

View File

@ -52,11 +52,11 @@ _jam_bench(void)
gettimeofday(&b4, 0);
{
c3_w* wor_w, bit_w;
u3i_slab sab_u;
for ( i_w = 0; i_w < max_w; i_w++ ) {
wor_w = u3s_jam_fib(wit, &bit_w);
u3a_wfree(wor_w);
u3s_jam_fib(&sab_u, wit);
u3i_slab_free(&sab_u);
}
}

View File

@ -414,6 +414,11 @@
void
u3a_wfree(void* lag_v);
/* u3a_wtrim(): trim storage.
*/
void
u3a_wtrim(void* tox_v, c3_w old_w, c3_w len_w);
/* u3a_wealloc(): word realloc.
*/
void*
@ -643,33 +648,6 @@
void
u3a_deadbeef(void);
/* Atoms from proto-atoms.
*/
/* u3a_slab(): create a length-bounded proto-atom.
*/
c3_w*
u3a_slab(c3_w len_w);
/* u3a_slaq(): u3a_slab() with a defined blocksize.
*/
c3_w*
u3a_slaq(c3_g met_g, c3_w len_w);
/* u3a_malt(): measure and finish a proto-atom.
*/
u3_noun
u3a_malt(c3_w* sal_w);
/* u3a_moot(): finish a pre-measured proto-atom; dangerous.
*/
u3_noun
u3a_moot(c3_w* sal_w);
/* u3a_mint(): finish a measured proto-atom.
*/
u3_noun
u3a_mint(c3_w* sal_w, c3_w len_w);
/* u3a_walk_fore(): preorder traversal, visits ever limb of a noun.
**
** cells are visited *before* their heads and tails

View File

@ -2,17 +2,91 @@
**
** This file is in the public domain.
*/
/** Structures.
**/
/* u3i_slab: atom builder.
*/
typedef struct _u3i_slab {
struct { // internals
u3a_atom* _vat_u; // heap atom (nullable)
c3_w _sat_w; // static storage
} _; //
union { //
c3_y* buf_y; // bytes
c3_w* buf_w; // words
}; //
c3_w len_w; // word length
} u3i_slab;
/* staged atom-building api
*/
/* u3i_slab_init(): configure bloq-length slab, zero-initialize.
*/
void
u3i_slab_init(u3i_slab* sab_u, c3_g met_g, c3_d len_d);
/* u3i_slab_bare(): configure bloq-length slab, uninitialized.
*/
void
u3i_slab_bare(u3i_slab* sab_u, c3_g met_g, c3_d len_d);
/* u3i_slab_from(): configure bloq-length slab, initialize with [a].
*/
void
u3i_slab_from(u3i_slab* sab_u, u3_atom a, c3_g met_g, c3_d len_d);
/* u3i_slab_grow(): resize slab, zero-initializing new space.
*/
void
u3i_slab_grow(u3i_slab* sab_u, c3_g met_g, c3_d len_d);
/* u3i_slab_free(): dispose memory backing slab.
*/
void
u3i_slab_free(u3i_slab* sab_u);
/* u3i_slab_mint(): produce atom from slab, trimming.
*/
u3_atom
u3i_slab_mint(u3i_slab* sab_u);
/* u3i_slab_moot(): produce atom from slab, no trimming.
*/
u3_atom
u3i_slab_moot(u3i_slab* sab_u);
/* u3i_slab_mint_bytes(): produce atom from byte-slab, trimming.
** XX assumes little-endian, implement swap to support big-endian
*/
# define u3i_slab_mint_bytes u3i_slab_mint
/* u3i_slab_moot_bytes(): produce atom from byte-slab, no trimming.
** XX assumes little-endian, implement swap to support big-endian
*/
# define u3i_slab_moot_bytes u3i_slab_moot
/* General constructors.
*/
/* u3i_word(): construct u3_atom from c3_w.
*/
u3_atom
u3i_word(c3_w dat_w);
/* u3i_chub(): construct u3_atom from c3_d.
*/
u3_atom
u3i_chub(c3_d dat_d);
/* u3i_bytes(): Copy [a] bytes from [b] to an LSB first atom.
*/
u3_noun
u3_atom
u3i_bytes(c3_w a_w,
const c3_y* b_y);
/* u3i_words(): Copy [a] words from [b] into an atom.
*/
u3_noun
u3_atom
u3i_words(c3_w a_w,
const c3_w* b_w);
@ -24,12 +98,12 @@
/* u3i_mp(): Copy the GMP integer [a] into an atom, and clear it.
*/
u3_noun
u3_atom
u3i_mp(mpz_t a_mp);
/* u3i_vint(): increment [a].
*/
u3_noun
u3_atom
u3i_vint(u3_noun a);
/* u3i_cell(): Produce the cell `[a b]`.

View File

@ -15,8 +15,8 @@
** returns atom-suitable words, and *bit_w will have
** the length (in bits). return should be freed with u3a_wfree().
*/
c3_w*
u3s_jam_fib(u3_noun a, c3_w* bit_w);
c3_w
u3s_jam_fib(u3i_slab* sab_u, u3_noun a);
/* u3s_jam_xeno(): jam with off-loom buffer (re-)allocation.
*/

View File

@ -14,9 +14,9 @@
return u3m_bail(c3__fail);
}
else {
c3_g a_g = a;
c3_w tot_w = 0;
c3_w* sal_w;
c3_g a_g = a;
c3_w tot_w = 0;
u3i_slab sab_u;
/* Measure and validate the slab required.
*/
@ -41,12 +41,12 @@
tot_w += pi_cab;
cab = u3t(cab);
}
if ( 0 == tot_w ) {
return 0;
}
if ( 0 == (sal_w = u3a_slaq(a_g, tot_w)) ) {
return u3m_bail(c3__fail);
}
u3i_slab_init(&sab_u, a_g, tot_w);
}
/* Chop the list atoms in.
@ -60,12 +60,13 @@
u3_atom pi_cab = u3h(i_cab);
u3_atom qi_cab = u3t(i_cab);
u3r_chop(a_g, 0, pi_cab, pos_w, sal_w, qi_cab);
u3r_chop(a_g, 0, pi_cab, pos_w, sab_u.buf_w, qi_cab);
pos_w += pi_cab;
cab = u3t(cab);
}
}
return u3a_malt(sal_w);
return u3i_slab_mint(&sab_u);
}
}
u3_noun

View File

@ -22,18 +22,14 @@
if ( 0 == all_w ) {
return 0;
} else {
c3_w* sal_w = u3a_slaq(a_g, all_w);
}
else {
u3i_slab sab_u;
u3i_slab_from(&sab_u, b, a_g, all_w);
if ( 0 == sal_w ) {
return u3m_bail(c3__fail);
}
else {
u3r_chop(a_g, 0, lew_w, 0, sal_w, b);
u3r_chop(a_g, 0, ler_w, lew_w, sal_w, c);
}
// return u3a_moot(sal_w);
return u3a_malt(sal_w);
u3r_chop(a_g, 0, ler_w, lew_w, sab_u.buf_w, c);
return u3i_slab_mint(&sab_u);
}
}
}

View File

@ -15,24 +15,18 @@
if ( (lna_w == 0) && (lnb_w == 0) ) {
return 0;
} else {
c3_w len_w = c3_max(lna_w, lnb_w);
c3_w* sal_w = u3a_slab(len_w);
}
else {
c3_w len_w = c3_max(lna_w, lnb_w);
c3_w i_w;
u3i_slab sab_u;
u3i_slab_from(&sab_u, a, 5, len_w);
if ( 0 == sal_w ) {
return u3m_bail(c3__fail);
for ( i_w = 0; i_w < lnb_w; i_w++ ) {
sab_u.buf_w[i_w] |= u3r_word(i_w, b);
}
else {
c3_w i_w;
u3r_chop(5, 0, lna_w, 0, sal_w, a);
for ( i_w = 0; i_w < lnb_w; i_w++ ) {
sal_w[i_w] |= u3r_word(i_w, b);
}
// return u3a_moot(sal_w);
return u3a_malt(sal_w);
}
return u3i_slab_mint(&sab_u);
}
}
u3_noun

View File

@ -38,14 +38,12 @@
return u3k(d);
}
else {
c3_w* sal_w = u3a_slaq(a_g, c_w);
u3i_slab sab_u;
u3i_slab_init(&sab_u, a_g, c_w);
if ( 0 == sal_w ) {
return u3m_bail(c3__fail);
}
u3r_chop(a_g, b_w, c_w, 0, sal_w, d);
u3r_chop(a_g, b_w, c_w, 0, sab_u.buf_w, d);
return u3a_malt(sal_w);
return u3i_slab_mint(&sab_u);
}
}
}

View File

@ -15,23 +15,18 @@
if ( (lna_w == 0) && (lnb_w == 0) ) {
return 0;
} else {
c3_w len_w = c3_max(lna_w, lnb_w);
c3_w* sal_w = u3a_slab(len_w);
}
else {
c3_w len_w = c3_max(lna_w, lnb_w);
c3_w i_w;
u3i_slab sab_u;
u3i_slab_from(&sab_u, a, 5, len_w);
if ( 0 == sal_w ) {
return u3m_bail(c3__fail);
for ( i_w = 0; i_w < len_w; i_w++ ) {
sab_u.buf_w[i_w] &= u3r_word(i_w, b);
}
else {
c3_w i_w;
u3r_chop(5, 0, lna_w, 0, sal_w, a);
for ( i_w = 0; i_w < len_w; i_w++ ) {
sal_w[i_w] &= (i_w >= lnb_w) ? 0 : u3r_word(i_w, b);
}
return u3a_malt(sal_w);
}
return u3i_slab_mint(&sab_u);
}
}
u3_noun

View File

@ -29,14 +29,12 @@
return u3k(c);
}
else {
c3_w* sal_w = u3a_slaq(a_g, b_w);
u3i_slab sab_u;
u3i_slab_init(&sab_u, a_g, b_w);
if ( 0 == sal_w ) {
return u3m_bail(c3__fail);
}
u3r_chop(a_g, 0, b_w, 0, sal_w, c);
u3r_chop(a_g, 0, b_w, 0, sab_u.buf_w, c);
return u3a_malt(sal_w);
return u3i_slab_mint(&sab_u);
}
}
}

View File

@ -29,15 +29,12 @@
return u3m_bail(c3__exit);
}
else {
c3_w* sal_w = u3a_slaq(a_g, (b_w + len_w));
u3i_slab sab_u;
u3i_slab_init(&sab_u, a_g, (b_w + len_w));
if ( 0 == sal_w ) {
return u3m_bail(c3__fail);
}
u3r_chop(a_g, 0, len_w, b_w, sal_w, c);
u3r_chop(a_g, 0, len_w, b_w, sab_u.buf_w, c);
// return u3a_moot(sal_w);
return u3a_malt(sal_w);
return u3i_slab_mint(&sab_u);
}
}
}

View File

@ -15,23 +15,20 @@
if ( (lna_w == 0) && (lnb_w == 0) ) {
return 0;
} else {
c3_w len_w = c3_max(lna_w, lnb_w);
c3_w* sal_w = u3a_slab(len_w);
}
else {
c3_w len_w = c3_max(lna_w, lnb_w);
c3_w i_w;
u3i_slab sab_u;
u3i_slab_from(&sab_u, a, 5, len_w);
if ( 0 == sal_w ) {
return u3m_bail(c3__fail);
// XX use u3r_chop for XOR?
//
for ( i_w = 0; i_w < lnb_w; i_w++ ) {
sab_u.buf_w[i_w] ^= u3r_word(i_w, b);
}
else {
c3_w i_w;
u3r_chop(5, 0, lna_w, 0, sal_w, a);
for ( i_w = 0; i_w < lnb_w; i_w++ ) {
sal_w[i_w] ^= u3r_word(i_w, b);
}
return u3a_malt(sal_w);
}
return u3i_slab_mint(&sab_u);
}
}
u3_noun

View File

@ -14,9 +14,9 @@
return u3m_bail(c3__exit);
}
else {
c3_g a_g = a;
c3_w tot_w = 0;
c3_w* sal_w;
c3_g a_g = a;
c3_w tot_w = 0;
u3i_slab sab_u;
/* Measure and validate the slab required.
*/
@ -42,31 +42,31 @@
tot_w += len_w;
cab = u3t(cab);
}
if ( 0 == tot_w ) {
return 0;
}
if ( 0 == (sal_w = u3a_slaq(a_g, tot_w)) ) {
return u3m_bail(c3__fail);
}
u3i_slab_init(&sab_u, a_g, tot_w);
}
/* Chop the list atoms in.
*/
{
u3_noun cab = b;
c3_w pos_w = 0;
c3_w pos_w = 0;
while ( 0 != cab ) {
u3_noun h_cab = u3h(cab);
c3_w len_w = u3r_met(a_g, h_cab);
u3r_chop(a_g, 0, len_w, pos_w, sal_w, h_cab);
u3r_chop(a_g, 0, len_w, pos_w, sab_u.buf_w, h_cab);
pos_w += len_w;
cab = u3t(cab);
}
}
// return u3a_moot(sal_w);
return u3a_malt(sal_w);
return u3i_slab_mint(&sab_u);
}
}
u3_noun

View File

@ -14,9 +14,9 @@
return u3m_bail(c3__exit);
}
else {
c3_g a_g = a;
c3_w tot_w = 0;
c3_w* sal_w;
c3_g a_g = a;
c3_w tot_w = 0;
u3i_slab sab_u;
/* Measure and validate the slab required.
*/
@ -42,30 +42,30 @@
tot_w++;
cab = u3t(cab);
}
if ( 0 == tot_w ) {
return 0;
}
if ( 0 == (sal_w = u3a_slaq(a_g, tot_w)) ) {
return u3m_bail(c3__fail);
}
u3i_slab_init(&sab_u, a_g, tot_w);
}
/* Chop the list atoms in.
*/
{
u3_noun cab = b;
c3_w pos_w = 0;
c3_w pos_w = 0;
while ( 0 != cab ) {
u3_noun h_cab = u3h(cab);
u3r_chop(a_g, 0, 1, pos_w, sal_w, h_cab);
u3r_chop(a_g, 0, 1, pos_w, sab_u.buf_w, h_cab);
pos_w++;
cab = u3t(cab);
}
}
// return u3a_moot(sal_w);
return u3a_malt(sal_w);
return u3i_slab_mint(&sab_u);
}
}
u3_noun

View File

@ -28,19 +28,8 @@ u3qc_repn(u3_atom bits, u3_noun blox)
c3_w num_blox_w = u3qb_lent(blox);
c3_w bit_widt_w = num_blox_w * bits;
c3_w wor_widt_w = DIVCEIL(bit_widt_w, 32);
//
// Allocate a proto-atom. This is u3a_slab without initialization.
//
c3_w* buf_w;
{
c3_w* nov_w = u3a_walloc(wor_widt_w + c3_wiseof(u3a_atom));
u3a_atom* pug_u = (void *)nov_w;
pug_u->mug_w = 0;
pug_u->len_w = wor_widt_w;
buf_w = pug_u->buf_w;
}
u3i_slab sab_u;
u3i_slab_bare(&sab_u, 5, wor_widt_w);
//
// Fill the atom buffer with bits from each block.
@ -53,7 +42,7 @@ u3qc_repn(u3_atom bits, u3_noun blox)
// cur_w next buffer word to flush into.
//
{
c3_w acc_w=0, use_w=0, *cur_w=buf_w;
c3_w acc_w=0, use_w=0, *cur_w=sab_u.buf_w;
# define FLUSH() *cur_w++=acc_w; acc_w=use_w=0
# define SLICE(sz,off,val) TAKEBITS(sz, val) << off
@ -98,7 +87,7 @@ u3qc_repn(u3_atom bits, u3_noun blox)
}
}
return u3a_malt(buf_w);
return u3i_slab_mint(&sab_u);
}
u3_noun

View File

@ -42,23 +42,19 @@ u3_noun u3qc_rip(u3_atom bloq, u3_atom b) {
c3_w tub_w = ((dif_w == 0) ? san_w : (san_w - dif_w));
for ( c3_w i_w = 0; i_w < met_w; i_w++ ) {
c3_w pat_w = (met_w - (i_w + 1));
c3_w wut_w = (pat_w << san_g);
c3_w sap_w = ((0 == i_w) ? tub_w : san_w);
c3_w* sal_w = u3a_slab(sap_w);
if ( 0 == sal_w ) {
return u3m_bail(c3__fail);
}
c3_w j_w;
u3_atom rip;
c3_w pat_w = (met_w - (i_w + 1));
c3_w wut_w = (pat_w << san_g);
c3_w sap_w = ((0 == i_w) ? tub_w : san_w);
c3_w j_w;
u3_atom rip;
u3i_slab sab_u;
u3i_slab_bare(&sab_u, 5, sap_w);
for ( j_w = 0; j_w < sap_w; j_w++ ) {
sal_w[j_w] = u3r_word(wut_w + j_w, b);
sab_u.buf_w[j_w] = u3r_word(wut_w + j_w, b);
}
rip = u3a_malt(sal_w);
rip = u3i_slab_mint(&sab_u);
acc = u3nc(rip, acc);
len_w -= san_w;
}

View File

@ -26,15 +26,12 @@
return 0;
}
else {
c3_w* sal_w = u3a_slaq(a_g, (len_w - b_w));
u3i_slab sab_u;
u3i_slab_init(&sab_u, a_g, (len_w - b_w));
if ( 0 == sal_w ) {
return u3m_bail(c3__fail);
}
u3r_chop(a_g, b_w, (len_w - b_w), 0, sal_w, c);
u3r_chop(a_g, b_w, (len_w - b_w), 0, sab_u.buf_w, c);
// return u3a_moot(sal_w);
return u3a_malt(sal_w);
return u3i_slab_mint(&sab_u);
}
}
}

View File

@ -37,16 +37,9 @@ u3qe_jam(u3_atom a)
}
#endif
c3_w bit_w, *sal_w;
c3_w* wor_w = u3s_jam_fib(a, &bit_w);
c3_w len_w = bit_w >> 5;
if ( (len_w << 5) != bit_w ) {
++len_w;
}
sal_w = u3a_slab(len_w);
memcpy(sal_w, wor_w, len_w*sizeof(c3_w));
u3a_wfree(wor_w);
return u3a_moot(sal_w);
u3i_slab sab_u;
u3s_jam_fib(&sab_u, a);
return u3i_slab_mint(&sab_u);
}
u3_noun

View File

@ -632,6 +632,28 @@ u3a_wfree(void* tox_v)
_box_free(u3a_botox(tox_v));
}
/* u3a_wtrim(): trim storage.
*/
void
u3a_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) )
{
c3_w* box_w = (void *)u3a_botox(nov_w);
c3_w* end_w = (nov_w + len_w + 1);
c3_w asz_w = (end_w - box_w);
c3_w bsz_w = box_w[0] - asz_w;
_box_attach(_box_make(end_w, bsz_w, 0));
box_w[0] = asz_w;
box_w[asz_w - 1] = asz_w;
}
}
/* u3a_calloc(): allocate and zero-initialize array
*/
void*
@ -2457,77 +2479,6 @@ u3a_rewrite_noun(u3_noun som)
cel->tel = u3a_rewritten_noun(cel->tel);
}
/* u3a_slab(): create a length-bounded proto-atom.
*/
c3_w*
u3a_slab(c3_w len_w)
{
c3_w* nov_w = u3a_walloc(len_w + c3_wiseof(u3a_atom));
u3a_atom* pug_u = (void *)nov_w;
pug_u->mug_w = 0;
pug_u->len_w = len_w;
/* Clear teh slab.
*/
{
c3_w i_w;
for ( i_w=0; i_w < len_w; i_w++ ) {
pug_u->buf_w[i_w] = 0;
}
}
return pug_u->buf_w;
}
/* u3a_slaq(): u3a_slab() with a defined blocksize.
*/
c3_w*
u3a_slaq(c3_g met_g, c3_w len_w)
{
return u3a_slab(((len_w << met_g) + 31) >> 5);
}
/* u3a_malt(): measure and finish a proto-atom.
*/
u3_noun
u3a_malt(c3_w* sal_w)
{
c3_w* nov_w = (sal_w - c3_wiseof(u3a_atom));
u3a_atom* nov_u = (void *)nov_w;
c3_w len_w;
for ( len_w = nov_u->len_w; len_w; len_w-- ) {
if ( 0 != nov_u->buf_w[len_w - 1] ) {
break;
}
}
return u3a_mint(sal_w, len_w);
}
/* u3a_moot(): finish a pre-measured proto-atom; dangerous.
*/
u3_noun
u3a_moot(c3_w* sal_w)
{
c3_w* nov_w = (sal_w - c3_wiseof(u3a_atom));
u3a_atom* nov_u = (void*)nov_w;
c3_w len_w = nov_u->len_w;
c3_w las_w = nov_u->buf_w[len_w - 1];
c3_assert(0 != len_w);
c3_assert(0 != las_w);
if ( 1 == len_w ) {
if ( _(u3a_is_cat(las_w)) ) {
u3a_wfree(nov_w);
return las_w;
}
}
return u3a_to_pug(u3a_outa(nov_w));
}
#if 0
/* _ca_detect(): in u3a_detect().
*/
@ -2574,53 +2525,6 @@ u3a_detect(u3_noun fum, u3_noun som)
}
#endif
/* u3a_mint(): finish a measured proto-atom.
*/
u3_noun
u3a_mint(c3_w* sal_w, c3_w len_w)
{
c3_w* nov_w = (sal_w - c3_wiseof(u3a_atom));
u3a_atom* nov_u = (void*)nov_w;
/* See if we can free the slab entirely.
*/
if ( len_w == 0 ) {
u3a_wfree(nov_w);
return 0;
}
else if ( len_w == 1 ) {
c3_w low_w = nov_u->buf_w[0];
if ( _(u3a_is_cat(low_w)) ) {
u3a_wfree(nov_w);
return low_w;
}
}
/* See if we can strip off a block on the end.
*/
{
c3_w old_w = nov_u->len_w;
c3_w dif_w = (old_w - len_w);
if ( dif_w >= u3a_minimum ) {
c3_w* box_w = (void *)u3a_botox(nov_w);
c3_w* end_w = (nov_w + c3_wiseof(u3a_atom) + len_w + 1);
c3_w asz_w = (end_w - box_w);
c3_w bsz_w = box_w[0] - asz_w;
_box_attach(_box_make(end_w, bsz_w, 0));
box_w[0] = asz_w;
box_w[asz_w - 1] = asz_w;
}
nov_u->len_w = len_w;
}
return u3a_to_pug(u3a_outa(nov_w));
}
#ifdef U3_MEMORY_DEBUG
/* u3a_lush(): leak push.
*/

View File

@ -3,126 +3,382 @@
*/
#include "all.h"
/* u3i_bytes(): Copy [a] bytes from [b] to an LSB first atom.
/* _ci_slab_size(): calculate slab bloq-size, checking for overflow.
*/
u3_noun
u3i_bytes(c3_w a_w,
const c3_y* b_y)
static c3_w
_ci_slab_size(c3_g met_g, c3_d len_d)
{
u3_noun pro;
c3_d bit_d = len_d << met_g;
c3_d wor_d = (bit_d + 0x1f) >> 5;
c3_w wor_w = (c3_w)wor_d;
// Strip trailing zeroes.
//
while ( a_w && !b_y[a_w - 1] ) {
a_w--;
if ( (wor_w != wor_d)
|| (len_d != (bit_d >> met_g)) )
{
return (c3_w)u3m_bail(c3__fail);
}
// Check for cat.
return wor_w;
}
/* _ci_slab_init(): initialize slab with heap allocation.
** NB: callers must ensure [len_w] >0
*/
static void
_ci_slab_init(u3i_slab* sab_u, c3_w len_w)
{
c3_w* nov_w = u3a_walloc(len_w + c3_wiseof(u3a_atom));
u3a_atom* vat_u = (void *)nov_w;
vat_u->mug_w = 0;
vat_u->len_w = len_w;
#ifdef U3_MEMORY_DEBUG
c3_assert( len_w );
#endif
sab_u->_._vat_u = vat_u;
sab_u->buf_w = vat_u->buf_w;
sab_u->len_w = len_w;
}
/* _ci_slab_grow(): update slab with heap reallocation.
*/
static void
_ci_slab_grow(u3i_slab* sab_u, c3_w len_w)
{
c3_w* old_w = (void*)sab_u->_._vat_u;
// XX implement a more efficient u3a_wealloc()
//
if ( a_w <= 4 ) {
if ( !a_w ) {
return 0;
}
else if ( a_w == 1 ) {
return b_y[0];
}
else if ( a_w == 2 ) {
return (b_y[0] | (b_y[1] << 8));
}
else if ( a_w == 3 ) {
return (b_y[0] | (b_y[1] << 8) | (b_y[2] << 16));
}
else if ( (b_y[3] <= 0x7f) ) {
return (b_y[0] | (b_y[1] << 8) | (b_y[2] << 16) | (b_y[3] << 24));
c3_w* nov_w = u3a_wealloc(old_w, len_w + c3_wiseof(u3a_atom));
u3a_atom* vat_u = (void *)nov_w;
vat_u->len_w = len_w;
sab_u->_._vat_u = vat_u;
sab_u->buf_w = vat_u->buf_w;
sab_u->len_w = len_w;
}
/* _ci_atom_mint(): finalize a heap-allocated atom at specified length.
*/
static u3_atom
_ci_atom_mint(u3a_atom* vat_u, c3_w len_w)
{
c3_w* nov_w = (void*)vat_u;
if ( 0 == len_w ) {
u3a_wfree(nov_w);
return (u3_atom)0;
}
else if ( 1 == len_w ) {
c3_w dat_w = *vat_u->buf_w;
if ( c3y == u3a_is_cat(dat_w) ) {
u3a_wfree(nov_w);
return (u3_atom)dat_w;
}
}
// Allocate, fill, return.
// try to strip a block off the end
//
{
c3_w old_w = vat_u->len_w;
if ( old_w > len_w ) {
c3_y wiz_y = c3_wiseof(u3a_atom);
u3a_wtrim(nov_w, old_w + wiz_y, len_w + wiz_y);
}
}
vat_u->len_w = len_w;
return u3a_to_pug(u3a_outa(nov_w));
}
/* u3i_slab_init(): configure bloq-length slab, zero-initialize.
*/
void
u3i_slab_init(u3i_slab* sab_u, c3_g met_g, c3_d len_d)
{
u3i_slab_bare(sab_u, met_g, len_d);
u3t_on(mal_o);
memset(sab_u->buf_y, 0, (size_t)sab_u->len_w * 4);
u3t_off(mal_o);
}
/* u3i_slab_bare(): configure bloq-length slab, uninitialized.
*/
void
u3i_slab_bare(u3i_slab* sab_u, c3_g met_g, c3_d len_d)
{
u3t_on(mal_o);
{
c3_w len_w = (a_w + 3) >> 2;
c3_w* nov_w = u3a_walloc((len_w + c3_wiseof(u3a_atom)));
u3a_atom* nov_u = (void*)nov_w;
c3_w wor_w = _ci_slab_size(met_g, len_d);
nov_u->mug_w = 0;
nov_u->len_w = len_w;
// Clear the words.
// if we only need one word, use the static storage in [sab_u]
//
{
c3_w i_w;
for ( i_w=0; i_w < len_w; i_w++ ) {
nov_u->buf_w[i_w] = 0;
}
if ( (0 == wor_w) || (1 == wor_w) ) {
sab_u->_._vat_u = 0;
sab_u->buf_w = &sab_u->_._sat_w;
sab_u->len_w = 1;
}
// Fill the bytes.
// allocate an indirect atom
//
{
c3_w i_w;
for ( i_w=0; i_w < a_w; i_w++ ) {
nov_u->buf_w[i_w >> 2] |= (b_y[i_w] << ((i_w & 3) * 8));
}
else {
_ci_slab_init(sab_u, wor_w);
}
pro = u3a_to_pug(u3a_outa(nov_w));
}
u3t_off(mal_o);
}
/* u3i_slab_from(): configure bloq-length slab, initialize with [a].
*/
void
u3i_slab_from(u3i_slab* sab_u, u3_atom a, c3_g met_g, c3_d len_d)
{
u3i_slab_bare(sab_u, met_g, len_d);
// copies [a], zero-initializes any additional space
//
u3r_words(0, sab_u->len_w, sab_u->buf_w, a);
}
/* u3i_slab_grow(): resize slab, zero-initializing new space.
*/
void
u3i_slab_grow(u3i_slab* sab_u, c3_g met_g, c3_d len_d)
{
c3_w old_w = sab_u->len_w;
u3t_on(mal_o);
{
c3_w wor_w = _ci_slab_size(met_g, len_d);
// XX actually shrink?
//
if ( wor_w <= old_w ) {
sab_u->len_w = wor_w;
}
else {
// upgrade from static storage
//
if ( 1 == old_w ) {
c3_w dat_w = *sab_u->buf_w;
_ci_slab_init(sab_u, wor_w);
sab_u->buf_w[0] = dat_w;
}
// reallocate
//
else {
_ci_slab_grow(sab_u, wor_w);
}
{
c3_y* buf_y = (void*)(sab_u->buf_w + old_w);
size_t dif_i = wor_w - old_w;
memset(buf_y, 0, dif_i * 4);
}
}
}
u3t_off(mal_o);
}
/* u3i_slab_free(): dispose memory backing slab.
*/
void
u3i_slab_free(u3i_slab* sab_u)
{
c3_w len_w = sab_u->len_w;
u3a_atom* vat_u = sab_u->_._vat_u;
u3t_on(mal_o);
if ( 1 == len_w ) {
c3_assert( !vat_u );
}
else {
c3_w* tav_w = (sab_u->buf_w - c3_wiseof(u3a_atom));
c3_assert( tav_w == (c3_w*)vat_u );
u3a_wfree(vat_u);
}
u3t_off(mal_o);
}
/* u3i_slab_mint(): produce atom from slab, trimming.
*/
u3_atom
u3i_slab_mint(u3i_slab* sab_u)
{
c3_w len_w = sab_u->len_w;
u3a_atom* vat_u = sab_u->_._vat_u;
u3_atom pro;
u3t_on(mal_o);
if ( 1 == len_w ) {
c3_w dat_w = *sab_u->buf_w;
c3_assert( !vat_u );
u3t_off(mal_o);
pro = u3i_word(dat_w);
u3t_on(mal_o);
}
else {
u3a_atom* vat_u = sab_u->_._vat_u;
c3_w* tav_w = (sab_u->buf_w - c3_wiseof(u3a_atom));
c3_assert( tav_w == (c3_w*)vat_u );
// trim trailing zeros
//
while ( len_w && !(sab_u->buf_w[len_w - 1]) ) {
len_w--;
}
pro = _ci_atom_mint(vat_u, len_w);
}
u3t_off(mal_o);
return pro;
}
/* u3i_slab_moot(): produce atom from slab, no trimming.
*/
u3_atom
u3i_slab_moot(u3i_slab* sab_u)
{
c3_w len_w = sab_u->len_w;
u3a_atom* vat_u = sab_u->_._vat_u;
u3_atom pro;
u3t_on(mal_o);
if ( 1 == len_w) {
c3_w dat_w = *sab_u->buf_w;
c3_assert( !sab_u->_._vat_u );
u3t_off(mal_o);
pro = u3i_word(dat_w);
u3t_on(mal_o);
}
else {
u3a_atom* vat_u = sab_u->_._vat_u;
c3_w* tav_w = (sab_u->buf_w - c3_wiseof(u3a_atom));
c3_assert( tav_w == (c3_w*)vat_u );
pro = _ci_atom_mint(vat_u, len_w);
}
u3t_off(mal_o);
return pro;
}
/* u3i_word(): construct u3_atom from c3_w.
*/
u3_atom
u3i_word(c3_w dat_w)
{
u3_atom pro;
u3t_on(mal_o);
if ( c3y == u3a_is_cat(dat_w) ) {
pro = (u3_atom)dat_w;
}
else {
c3_w* nov_w = u3a_walloc(1 + c3_wiseof(u3a_atom));
u3a_atom* vat_u = (void *)nov_w;
vat_u->mug_w = 0;
vat_u->len_w = 1;
vat_u->buf_w[0] = dat_w;
pro = u3a_to_pug(u3a_outa(nov_w));
}
u3t_off(mal_o);
return pro;
}
/* u3i_chub(): construct u3_atom from c3_d.
*/
u3_atom
u3i_chub(c3_d dat_d)
{
c3_w dat_w[2] = {
dat_d & 0xffffffffULL,
dat_d >> 32
};
return u3i_words(2, dat_w);
}
/* u3i_bytes(): Copy [a] bytes from [b] to an LSB first atom.
*/
u3_atom
u3i_bytes(c3_w a_w,
const c3_y* b_y)
{
// strip trailing zeroes.
//
while ( a_w && !b_y[a_w - 1] ) {
a_w--;
}
if ( !a_w ) {
return (u3_atom)0;
}
else {
u3i_slab sab_u;
u3i_slab_bare(&sab_u, 3, a_w);
u3t_on(mal_o);
{
// zero-initialize last word
//
sab_u.buf_w[sab_u.len_w - 1] = 0;
memcpy(sab_u.buf_y, b_y, a_w);
}
u3t_off(mal_o);
return u3i_slab_moot_bytes(&sab_u);
}
}
/* u3i_words(): Copy [a] words from [b] into an atom.
*/
u3_noun
u3_atom
u3i_words(c3_w a_w,
const c3_w* b_w)
{
u3_noun pro;
// Strip trailing zeroes.
// strip trailing zeroes.
//
while ( a_w && !b_w[a_w - 1] ) {
a_w--;
}
// Check for cat.
//
if ( !a_w ) {
return 0;
return (u3_atom)0;
}
else if ( (a_w == 1) && !(b_w[0] >> 31) ) {
return b_w[0];
else {
u3i_slab sab_u;
u3i_slab_bare(&sab_u, 5, a_w);
u3t_on(mal_o);
memcpy(sab_u.buf_w, b_w, (size_t)4 * a_w);
u3t_off(mal_o);
return u3i_slab_moot(&sab_u);
}
// Allocate, fill, return.
//
u3t_on(mal_o);
{
c3_w* nov_w = u3a_walloc(a_w + c3_wiseof(u3a_atom));
u3a_atom* nov_u = (void*)nov_w;
nov_u->mug_w = 0;
nov_u->len_w = a_w;
// Fill the words.
//
{
c3_w i_w;
for ( i_w=0; i_w < a_w; i_w++ ) {
nov_u->buf_w[i_w] = b_w[i_w];
}
}
pro = u3a_to_pug(u3a_outa(nov_w));
}
u3t_off(mal_o);
return pro;
}
/* u3i_chubs(): Copy [a] chubs from [b] into an atom.
@ -131,100 +387,69 @@ u3_atom
u3i_chubs(c3_w a_w,
const c3_d* b_d)
{
u3_noun pro;
// Strip trailing zeroes.
// strip trailing zeroes.
//
while ( a_w && !b_d[a_w - 1] ) {
a_w--;
}
// Check for cat.
//
if ( !a_w ) {
return 0;
return (u3_atom)0;
}
else if ( (1 == a_w) && !(b_d[0] >> 31) ) {
return (c3_w)b_d[0];
else if ( 1 == a_w ) {
return u3i_chub(b_d[0]);
}
else {
u3i_slab sab_u;
u3i_slab_bare(&sab_u, 6, a_w);
// Allocate, fill, return.
//
u3t_on(mal_o);
{
c3_w len_w = 2 * a_w;
if ( !(b_d[a_w - 1] >> 32) ) {
len_w--;
}
c3_w* nov_w = u3a_walloc(len_w + c3_wiseof(u3a_atom));
u3a_atom* nov_u = (void*)nov_w;
nov_u->mug_w = 0;
nov_u->len_w = len_w;
// Fill the words.
//
u3t_on(mal_o);
{
c3_w i_w, x_w, max_w = a_w - 1;
c3_d i_d;
c3_w* buf_w = sab_u.buf_w;
c3_w i_w;
c3_d i_d;
for ( i_w = 0; i_w < max_w; i_w++ ) {
for ( i_w = 0; i_w < a_w; i_w++ ) {
i_d = b_d[i_w];
x_w = 2 * i_w;
nov_u->buf_w[x_w] = i_d & 0xffffffffULL;
x_w++;
nov_u->buf_w[x_w] = i_d >> 32;
}
{
i_d = b_d[i_w];
x_w = 2 * i_w;
nov_u->buf_w[x_w] = i_d & 0xffffffffULL;
x_w++;
}
if ( x_w < len_w ) {
nov_u->buf_w[x_w] = i_d >> 32;
*buf_w++ = i_d & 0xffffffffULL;
*buf_w++ = i_d >> 32;
}
}
u3t_off(mal_o);
pro = u3a_to_pug(u3a_outa(nov_w));
return u3i_slab_mint(&sab_u);
}
u3t_off(mal_o);
return pro;
}
/* u3i_mp(): Copy the GMP integer [a] into an atom, and clear it.
*/
u3_noun
u3_atom
u3i_mp(mpz_t a_mp)
{
c3_w pyg_w = mpz_size(a_mp) * ((sizeof(mp_limb_t)) / 4);
c3_w* buz_w = u3a_slab(4 * pyg_w);
size_t siz_i = mpz_sizeinbase(a_mp, 2);
u3i_slab sab_u;
u3i_slab_init(&sab_u, 0, siz_i);
mpz_export(buz_w, 0, -1, sizeof(c3_w), 0, 0, a_mp);
mpz_export(sab_u.buf_w, 0, -1, sizeof(c3_w), 0, 0, a_mp);
mpz_clear(a_mp);
return u3a_malt(buz_w);
// per the mpz_export() docs:
//
// > If op is non-zero then the most significant word produced
// > will be non-zero.
//
return u3i_slab_moot(&sab_u);
}
/* u3i_vint(): increment [a].
*/
u3_noun
u3_atom
u3i_vint(u3_noun a)
{
c3_assert(u3_none != a);
if ( _(u3a_is_cat(a)) ) {
c3_w vin_w = (a + 1);
if ( a == 0x7fffffff ) {
return u3i_words(1, &vin_w);
}
else return vin_w;
return ( a == 0x7fffffff ) ? u3i_word(a + 1) : (a + 1);
}
else if ( _(u3a_is_cell(a)) ) {
return u3m_bail(c3__exit);

View File

@ -121,18 +121,14 @@ _cj_bash(u3_noun bat)
rod_u = u3to(u3_road, rod_u->par_p);
}
else {
c3_w bit_w, met_w;
c3_w* wor_w;
c3_y* fat_y;
c3_y dig_y[32];
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];
wor_w = u3s_jam_fib(bat, &bit_w);
met_w = bit_w >> 3;
if ( bit_w != met_w << 3 ) {
++met_w;
}
// assume little-endian
fat_y = (c3_y*) wor_w;
#if defined(U3_OS_osx)
CC_SHA256_CTX ctx_h;
@ -146,9 +142,10 @@ _cj_bash(u3_noun bat)
SHA256_Update(&ctx_h, fat_y, met_w);
SHA256_Final(dig_y, &ctx_h);
#endif
pro = u3i_bytes(32, dig_y);
u3h_put(u3R->jed.bas_p, bat, u3k(pro));
u3a_wfree(wor_w);
u3i_slab_free(&sab_u);
break;
}
}

View File

@ -8,21 +8,14 @@
#include "all.h"
#include "ur/ur.h"
/* _cs_met0_w(): safe bitwidth for any c3_w
*/
static inline c3_w
_cs_met0_w(c3_w wid_w) {
return ( wid_w >> 31 ) ? 32 : u3r_met(0, wid_w);
}
/* _cs_jam_buf: struct for tracking the fibonacci-allocated jam of a noun
*/
struct _cs_jam_fib {
u3i_slab* sab_u;
u3p(u3h_root) har_p;
c3_w a_w;
c3_w b_w;
c3_w bit_w;
c3_w* buf_w;
};
/* _cs_jam_fib_grow(): reallocate buffer with fibonacci growth
@ -39,12 +32,8 @@ _cs_jam_fib_grow(struct _cs_jam_fib* fib_u, c3_w mor_w)
}
if ( wan_w > fib_u->a_w ) {
c3_w old_w, new_w, c_w = 0;
old_w = fib_u->a_w >> 5;
if ( (old_w << 5) != fib_u->a_w ) {
++old_w;
}
c3_w old_w = fib_u->sab_u->len_w;
c3_w c_w = 0;
// fibonacci growth
//
@ -54,13 +43,7 @@ _cs_jam_fib_grow(struct _cs_jam_fib* fib_u, c3_w mor_w)
fib_u->a_w = c_w;
}
new_w = c_w >> 5;
if ( (new_w << 5) != c_w ) {
++new_w;
}
fib_u->buf_w = u3a_wealloc(fib_u->buf_w, new_w);
memset(fib_u->buf_w + old_w, 0, (new_w - old_w) * sizeof(c3_w));
u3i_slab_grow(fib_u->sab_u, 0, c_w);
}
}
@ -71,8 +54,12 @@ _cs_jam_fib_chop(struct _cs_jam_fib* fib_u, c3_w met_w, u3_noun a)
{
c3_w bit_w = fib_u->bit_w;
_cs_jam_fib_grow(fib_u, met_w);
u3r_chop(0, 0, met_w, bit_w, fib_u->buf_w, a);
fib_u->bit_w += met_w;
{
c3_w* buf_w = fib_u->sab_u->buf_w;
u3r_chop(0, 0, met_w, bit_w, buf_w, a);
}
}
/* _cs_jam_fib_mat(): length-prefixed encode (mat) [a] into [fib_u]
@ -85,7 +72,7 @@ _cs_jam_fib_mat(struct _cs_jam_fib* fib_u, u3_noun a)
}
else {
c3_w a_w = u3r_met(0, a);
c3_w b_w = _cs_met0_w(a_w);
c3_w b_w = c3_bits_word(a_w);
_cs_jam_fib_chop(fib_u, b_w+1, 1 << b_w);
_cs_jam_fib_chop(fib_u, b_w-1, a_w & ((1 << (b_w-1)) - 1));
@ -156,28 +143,21 @@ _cs_jam_fib_cell_cb(u3_noun a, void* ptr_v)
** returns atom-suitable words, and *bit_w will have
** the length (in bits). return should be freed with u3a_wfree().
*/
c3_w*
u3s_jam_fib(u3_noun a, c3_w* bit_w)
c3_w
u3s_jam_fib(u3i_slab* sab_u, u3_noun a)
{
struct _cs_jam_fib fib_u;
fib_u.har_p = u3h_new();
fib_u.sab_u = sab_u;
// fib(12) is small enough to be reasonably fast to allocate.
//
fib_u.a_w = 144;
// fib(11) is needed to get fib(13).
//
fib_u.b_w = 89;
//
fib_u.a_w = ur_fib12;
fib_u.b_w = ur_fib11;
fib_u.bit_w = 0;
{
c3_w len_w = fib_u.a_w >> 5;
if ( (len_w << 5) != fib_u.a_w ) {
++len_w;
}
fib_u.buf_w = u3a_walloc(len_w);
memset(fib_u.buf_w, 0, len_w * sizeof(c3_w));
}
u3i_slab_init(sab_u, 0, fib_u.a_w);
// as this is a hot path, we unsafely elide overflow checks
//
@ -186,9 +166,9 @@ u3s_jam_fib(u3_noun a, c3_w* bit_w)
u3a_walk_fore_unsafe(a, &fib_u, _cs_jam_fib_atom_cb,
_cs_jam_fib_cell_cb);
*bit_w = fib_u.bit_w;
u3h_free(fib_u.har_p);
return fib_u.buf_w;
return fib_u.bit_w;
}
typedef struct _jam_xeno_s {
@ -602,27 +582,18 @@ _cs_cue_xeno_next(u3a_pile* pil_u,
if ( 31 >= len_d ) {
*out = (u3_noun)ur_bsr32_any(red_u, len_d);
}
// XX need a ur_bsr_words_any()
//
else {
c3_w* wor_w;
c3_y* byt_y;
c3_d byt_d = (len_d + 0x7) >> 3;
u3i_slab sab_u;
{
c3_d byt_d = (len_d >> 3) + !!ur_mask_3(len_d);
if ( 0xffffffffULL < byt_d) {
return ur_cue_meme;
}
// XX assumes little-endian
//
wor_w = u3a_slaq(3, byt_d);
byt_y = (c3_y*)wor_w;
if ( 0xffffffffULL < byt_d) {
return ur_cue_meme;
}
else {
u3i_slab_init(&sab_u, 3, byt_d);
ur_bsr_bytes_any(red_u, len_d, sab_u.buf_y);
*out = u3i_slab_mint_bytes(&sab_u);
}
ur_bsr_bytes_any(red_u, len_d, byt_y);
*out = u3a_malt(wor_w);
}
ur_dict32_put(rot_u, dic_u, bit_d, *out);
@ -863,27 +834,12 @@ _cs_cue_bytes_next(u3a_pile* pil_u,
if ( 31 >= len_d ) {
vat = (u3_noun)ur_bsr32_any(red_u, len_d);
}
// XX need a ur_bsr_words_any()
//
else {
c3_w* wor_w;
c3_y* byt_y;
u3i_slab sab_u;
u3i_slab_init(&sab_u, 0, len_d);
{
c3_d byt_d = (len_d >> 3) + !!ur_mask_3(len_d);
if ( 0xffffffffULL < byt_d) {
return u3m_bail(c3__meme);
}
// XX assumes little-endian
//
wor_w = u3a_slaq(3, byt_d);
byt_y = (c3_y*)wor_w;
}
ur_bsr_bytes_any(red_u, len_d, byt_y);
vat = u3a_malt(wor_w);
ur_bsr_bytes_any(red_u, len_d, sab_u.buf_y);
vat = u3i_slab_mint_bytes(&sab_u);
}
return _cs_cue_put(har_p, bit_d, vat);

View File

@ -338,13 +338,13 @@ _test_jam_spec(const c3_c* cap_c,
}
{
c3_w bit_w;
c3_w* wor_w = u3s_jam_fib(ref, &bit_w);
u3i_slab sab_u;
c3_w bit_w = u3s_jam_fib(&sab_u, ref);
out_d = (bit_w >> 3) + !!ur_mask_3(bit_w);
out_d = ((c3_d)bit_w + 0x7) >> 3;
// XX assumes little-endian
//
out_y = (c3_y*)wor_w;
out_y = sab_u.buf_y;
if ( 0 != memcmp(out_y, byt_y, len_w) ) {
fprintf(stderr, "\033[31mjam fib %s fail\033[0m\r\n", cap_c);
@ -352,7 +352,7 @@ _test_jam_spec(const c3_c* cap_c,
ret_i = 0;
}
u3a_wfree(wor_w);
u3i_slab_free(&sab_u);
}
return ret_i;