This commit is contained in:
ault011 2014-08-07 14:43:56 -07:00 committed by ault011
commit f3c6e4c34e
2 changed files with 428 additions and 165 deletions

499
f/meme.c
View File

@ -13,56 +13,172 @@
/* _me_boot_north(): install a north road.
*/
static void
_me_boot_north(void* mem_v, c3_w len_w)
static u2_road*
_me_boot_north(c3_w* mem_w, c3_w len_w)
{
for
c3_w* rut_w = mem_w;
c3_w* hat_w = rut_w;
c3_w* mat_w = ((mem_w + len_w) - c3_wiseof(u2_road));
c3_w* cap_w = mat_w;
u2_road* rod_u = (void*) mat_w;
memset(rod_u, 0, sizeof(u2_road));
rod_u->rut_w = rut_w;
rod_u->hat_w = hat_w;
rod_u->mat_w = mat_w;
rod_u->cap_w = cap_w;
return rod_u;
}
/* _me_boot_south(): install a south road.
*/
static u2_road*
_me_boot_south(c3_w* mem_w, c3_w len_w)
{
c3_w* rut_w = mem_w;
c3_w* hat_w = rut_w;
c3_w* mat_w = ((mem_w + len_w) - c3_wiseof(u2_road));
c3_w* cap_w = mat_w;
u2_road* rod_u = (void*) mat_w;
memset(rod_u, 0, sizeof(u2_road));
rod_u->rut_w = rut_w;
rod_u->hat_w = hat_w;
rod_u->mat_w = mat_w;
rod_u->cap_w = cap_w;
return rod_u;
}
/* u2_me_boot(): make u2R and u2H from nothing.
*/
void
u2_me_boot(void* mem_v, c3_w len_w)
{
c3_w* mem_w = mem_v;
u2H = (u2_road*) mem_v;
memset(u2H, 0, sizeof(u2_road));
u2H->rut_w = (mem_w + c3_sizeof(u2_road));
u2H->hat_w = u2H->rut_w;
u2H->mat_w = (mem_w + len_w);
u2H->cap_w = u2H->mat_w;
u2R = u2H;
u2H = u2R = _me_boot_north(mem_v, len_w);
}
/* u2_me_leap(): advance to inner road.
/* _me_road_all_hat(): in u2R, allocate directly on the hat.
*/
static c3_w*
_me_road_all_hat(c3_w len_w)
{
if ( len_w > u2_me_open ) {
return u2_me_bail(c3__meme);
}
if ( u2_yes == u2_me_is_north ) {
c3_w* all_w;
all_w = u2R->hat;
u2R->hat += len_w;
return all_w;
}
else {
u2R->hat -= len_w;
return u2R->hat;
}
}
/* _me_road_all_cap(): in u2R, allocate directly on the cap.
*/
static c3_w*
_me_road_all_hat(c3_w len_w)
{
if ( len_w > u2_me_open ) {
return u2_me_bail(c3__meme);
}
if ( u2_yes == u2_me_is_north ) {
u2R->cap -= len_w;
return u2R->cap;
}
else {
c3_w* all_w;
all_w = u2R->cap;
u2R->cap += len_w;
return all_w;
}
}
/* u2_me_leap(): in u2R, create a new road within the existing one.
*/
void
u2_me_leap(void)
u2_me_leap()
{
u2_road* rod_u;
if ( u2_yes == u2_me_is_north ) {
rod_u = _me_boot_south(u2R->hat_w, (u2R->cap_w - u2R->hat_w));
}
else {
rod_u = _me_boot_south(u2R->cap_w, (u2R->hat_w - u2R->cap_w));
}
c3_assert(0 == u2R->kid_u);
rod_u->par_u = u2R;
u2R->kid_u = rod_u;
u2R = rod_u;
}
/* u2_me_fall(): in u2R, return an inner road to its parent.
*/
void
u2_me_fall()
{
c3_assert(0 != u2R->par_u);
u2R->par_u->cap_w = u2R->hat_u;
u2R = u2R->par_u;
}
/* _me_free_slot(): select the right free list to search for a block.
/* u2_me_golf(): record cap length for u2_flog().
*/
c3_w
_me_free_slot(c3_w siz_w)
u2_me_golf(void)
{
if ( u2_yes == u2_me_is_north ) {
return u2R->mat - u2R->cap;
}
else {
return u2R->cap - u2R->mat;
}
}
/* u2_me_flog(): reset cap.
*/
void
u2_me_flog(c3_w gof_w)
{
if ( u2_yes == u2_me_is_north ) {
u2R->cap = u2R->mat - gof_w;
} else {
u2R->cap = u2R->mat + gof_w;
}
}
/* u2_me_water(): produce watermarks.
*/
void
u2_me_water(c3_w* low_w, c3_w* hig_w);
{
c3_assert(u2R == u2H);
*low_w = (u2H->hat_w - u2H->rut_w);
*hig_w = (u2H->mat_w - u2H->cap_w) + c3_wiseof(u2_road);
}
/* _me_box_slot(): select the right free list to search for a block.
*/
c3_w
_me_box_slot(c3_w siz_w)
{
if ( siz_w < 8 ) {
return 0;
@ -83,160 +199,241 @@ _me_free_slot(c3_w siz_w)
}
}
/* u2_me_walloc(): allocate storage measured in words.
/* _me_box_make(): construct a box.
*/
u2_me_box*
_me_box_make(c3_v* box_v, c3_w siz_w, c3_w use_w)
{
u2_me_box* box_u = box_v;
c3_w* box_w = box_v;
box_w[0] = siz_w;
box_w[siz_w - 1] = siz_w;
#ifdef U2_MEMORY_DEBUG
box_u->cod_w = COD_w;
#endif
box_u->use_w = use_w;
return box_u;
}
/* _me_box_attach(): attach a box to the free list.
*/
void
_me_box_attach(u2_me_box* box_u)
{
c3_assert(box_u->siz_w >= (1 + c3_wiseof(u2_me_free)));
{
c3_w sel_w = _me_box_slot(box_u->siz_w);
u2_me_free* fre_u = (void *)box_u;
u2_me_free** pfr_u = &u2R->all.fre_u[sel_w];
fre_u->pre_u = 0;
fre_u->nex_u = (*pfr_u);
(*pfr_u) = fre_u;
}
}
/* _me_box_detach(): detach a box from the free list.
*/
void
_me_box_detach(u2_me_box* box_u)
{
u2_me_free* fre_u = (void*) box_u;
if ( fre_u->pre_u ) {
fre_u->pre_u->nex_u = fre_u->nex_u;
}
else {
c3_w sel_w = _me_box_slot(box_u->siz_w);
u2R->all.fre_u[sel_w] = fre_u->nex_u;
}
}
/* u2_me_walloc(): allocate storage words on hat.
*/
void*
u2_me_walloc(c3_w len_w)
{
c3_w siz_w = c3_max(u2_me_minimum, u2_me_boxed(len_w));
c3_w sel_w = _me_free_slot(siz_w);
c3_w sel_w = _me_box_slot(siz_w);
// XX: this logic is totally bizarre, but preserve it.
//
if ( (sel_w != 0) && (sel_w != u2_me_free_no - 1) ) {
sel_w += 1;
}
while ( 1 ) {
u2_me_free* pfr_u = u2R->all.fre_u[sel_w];
c3_w* box_w;
u2_me_free** pfr_u = &u2R->all.fre_u[sel_w];
if ( 0 == pfr_u ) {
if ( sel_w < (u2_me_free_no - 1) ) {
sel_w += 1;
break;
}
else {
/* Nothing in top free list. Chip away at the hat.
*/
if ( u2_no == u2_me_open(siz_w) ) {
u2_loop_signal_memory();
while ( 1 ) {
if ( 0 == *pfr_u ) {
if ( sel_w < (u2_me_free_no - 1) ) {
sel_w += 1;
break;
}
else {
box_w = u2R->lay.hat_w;
u2R->lay.hat_w += siz_w;
_me_box_make(
box_r = u2_rail_hat_r(ral_r);
u2_rail_hat_r(ral_r) += siz_w;
_rl_bloq_make(ral_r, box_r, siz_w, 1);
_rl_live_grab(ral_r, siz_w);
_rl_bloq_cheq(box_r);
return (box_r + c3_wiseof(u2_loom_rail_box));
/* Nothing in top free list. Chip away at the hat.
*/
return u2_me_boxto(_me_box_make(_me_road_all_hat(siz_w), siz_w, 1));
}
}
}
}
pfr_r = u2_aftr(sop_r, u2_loom_soup, fre_r) + sel_w;
while ( 1 ) {
u2_ray fre_r = *u2_at_ray(pfr_r);
u2_ray box_r;
if ( 0 == fre_r ) {
if ( sel_w < (u2_me_free_no - 1) ) {
sel_w += 1;
break;
}
else {
/* Nothing in top free list. Chip away at the hat.
*/
if ( u2_no == u2_rl_open(ral_r, siz_w) ) {
#if 1
u2_loop_signal_memory();
#else
/* Yo, our rail is totally full.
*/
printf("lose: siz_w: %d sel_w: %d\n", siz_w, sel_w);
u2_rl_dump(ral_r);
u2_ho_warn_here();
// XX: integrate with integral wire.
//
// A bunch of testing is needed to make this actually work.
// return 0;
c3_assert(0);
#endif
}
else {
box_r = u2_rail_hat_r(ral_r);
u2_rail_hat_r(ral_r) += siz_w;
_rl_bloq_make(ral_r, box_r, siz_w, 1);
_rl_live_grab(ral_r, siz_w);
_rl_bloq_cheq(box_r);
return (box_r + c3_wiseof(u2_loom_rail_box));
}
}
} else {
if ( siz_w > u2_rail_hut_siz(fre_r) ) {
/* This free block is too small. Continue searching.
*/
pfr_r = u2_aftr(fre_r, u2_loom_rail_hut, nex_r);
}
else {
/* We have found a free block of adequate size. Remove it
** from the free list.
*/
box_r = fre_r;
else {
if ( siz_w > (*pfr_u)->box_u->siz_w ) {
/* This free block is too small. Continue searching.
*/
pfr_u = &((*pfr_u)->nex_u);
continue;
}
else {
u2_me_box* box_u = &((*pfr_u)->box_u);
/* We have found a free block of adequate size. Remove it
** from the free list.
*/
{
{
u2_ray pre_r = u2_rail_hut_pre(box_r);
u2_ray nex_r = u2_rail_hut_nex(box_r);
c3_assert((0 == pre_r) ||
(u2_at_ray(pfr_r) == &u2_rail_hut_nex(pre_r)));
*u2_at_ray(pfr_r) = nex_r;
if ( 0 != nex_r ) {
u2_rail_hut_pre(nex_r) = pre_r;
}
c3_assert((0 == (*pfr_u)->pre_u) ||
(*pfr_u)->pre_u->nex_u == (*pfr_u));
c3_assert((0 == (*pfr_u)->nex_u) ||
(*pfr_u)->nex_u->pre_u == (*pfr_u));
}
if ( (siz_w + 6) < u2_rail_hut_siz(box_r) ) {
/* Split the block.
*/
u2_ray end_r = (box_r + siz_w);
_rl_bloq_make(ral_r, end_r, u2_rail_hut_siz(fre_r) - siz_w, 0);
_rl_bloq_attach(ral_r, end_r);
_rl_bloq_make(ral_r, box_r, siz_w, 1);
_rl_live_grab(ral_r, siz_w);
if ( 0 != (*pfr_u)->nex_u ) {
(*pfr_u)->nex_u->pre_u = (*pfr_u)->pre_u;
}
else {
c3_assert(u2_rail_box_use(box_r) == 0);
u2_rail_box_use(box_r) = 1;
# ifdef U2_LEAK_DEBUG
*u2_at_ray(box_r + 2) = COD_w;
# endif
_rl_live_grab(ral_r, u2_rail_hut_siz(box_r));
}
_rl_bloq_cheq(box_r);
return (box_r + c3_wiseof(u2_loom_rail_box));
*pfr_u = (*pfr_u)->nex_u;
}
/* If we can chop off another block, do it.
*/
if ( (siz_w + c3_wiseof(u2_me_free) + 1) <= box_u->siz_w ) {
/* Split the block.
*/
c3_w* box_w = ((c3_w *)(void *)box_uy);
c3_w* end_w = box_w + siz_w;
c3_w lef_w = (box_u->siz_w - siz_w);
_me_box_attach(_me_box_make(end_w, lef_w, 0));
return u2_me_boxto(_me_box_make(box_w, siz_w, 1));
}
else {
c3_assert(0 == box_u->use_w);
#ifdef U2_MEMORY_DEBUG
box_u->cod_w = COD_w;
#endif
return u2_me_boxto(box_u);
}
}
}
}
}
/* u2_me_malloc(): allocate storage measured in bytes.
*/
void*
u2_me_malloc(c3_w len_w);
u2_me_malloc(c3_w len_w)
{
return u2_me_walloc((len_w + 3) >> 2);
}
/* u2_me_free(): free storage.
*/
void
u2_me_free(void* lag_v);
u2_me_free(void* tox_v);
{
c3_w* lag_w = lag_v;
return;
u2_me_box* box_u = u2_me_botox(tox_v);
c3_w* box_w = (c3_w *)(void *)box_u;
c3_assert(box_u->use_w != 0);
box_u->use_w -= 1;
if ( 0 != box_u->use_w ) return;
/* Clear the contents of the block, for debugging.
*/
{
c3_w i_w;
for ( i_w = c3_wiseof(u2_me_box); (i_w + 1) < box_u->siz_w; i_w++ ) {
((c3_w*)tox_v)[i_w] = 0xdeadbeef;
}
}
if ( u2_yes == u2_me_is_north ) {
c3_w* bot_w = u2R->rut_w;
c3_w* top_w = u2R->hat_w;
/* Try to coalesce with the previous block.
*/
if ( box_w != u2R->rut_w ) {
c3_w laz_w = *(box_w - 1);
u2_me_box* pox_u = (u2_me_box*)(void *)(box_w - laz_w);
if ( 0 == pox_u->use_w ) {
_me_box_detach(pox_u);
_me_box_make(pox_u, (laz_w + box_u->siz_w), 0);
box_u = pox_u;
box_w = (c3_w*)(void *)box_u;
}
}
/* Try to coalesce with the next block, or the wilderness.
*/
if ( (box_w + siz_w) == u2R->hat_w ) {
u2R->hat_w = box_w;
}
else {
u2_me_box* nox_u = (u2_me_box*)(void *)(box_w + box_u->siz_w);
if ( 0 == nox_u->use_w ) {
_me_nox_detach(nox_u);
_me_box_make(box_u, (nox_u->siz_w + box_u->siz_w));
}
_me_box_attach(box_u);
}
}
else {
if (
}
if ( ((c3_w*) tox_v) == u2
if ( box_r != beg_r ) {
c3_w las_w = *u2_at_ray(box_r - 1);
u2_ray tod_r = (box_r - las_w);
if ( 0 == u2_rail_hut_use(tod_r) ) {
_rl_bloq_detach(ral_r, tod_r);
_rl_bloq_make(ral_r, tod_r, (las_w + u2_rail_hut_siz(box_r)), 0);
box_r = tod_r;
}
}
/* Try to coalesce with the next block, or with the wilderness.
*/
{
c3_w siz_w = u2_rail_hut_siz(box_r);
if ( (box_r + siz_w == hat_r) ) {
u2_rail_hat_r(ral_r) = box_r;
}
else {
u2_ray hob_r = (box_r + siz_w);
if ( 0 == u2_rail_hut_use(hob_r) ) {
_rl_bloq_detach(ral_r, hob_r);
_rl_bloq_make(ral_r, box_r, (siz_w + u2_rail_hut_siz(hob_r)), 0);
}
/* Add to the appropriate free list.
*/
_rl_bloq_attach(ral_r, box_r);
}
}
}
//////// Atoms from proto-atoms.

View File

@ -24,6 +24,7 @@
** ---
** siz_w
** use_w
** if(debug) cod_w
** user data
** siz_w
** ---
@ -33,16 +34,25 @@
typedef struct _u2_me_box {
c3_w siz_w; // size of this box
c3_w use_w; // reference count; free if 0
# ifdef U2_LEAK_DEBUG
# ifdef U2_MEMORY_DEBUG
c3_w cod_w; // tracing code
# endif
} u2_me_box;
# define u2_me_boxed(len_w) (len_w + c3_wiseof(u2_me_box) + 1)
# define u2_me_boxof(box_v) ( (void *) \
# define u2_me_boxto(box_v) ( (void *) \
( ((c3_w *)(void*)(box_v)) + \
c3_wiseof(u2_me_box) ) )
# define u2_me_botox(tox_v) ( (struct _u2_me_box *) \
(void *) \
( ((c3_w *)(void*)(tox_v)) - \
c3_wiseof(u2_me_box) ) )
((box_w) + c3_wiseof(u2_me_box))
/* u2_me_free: free node in heap. Sets minimum node size.
**
** XXO: pre_u and nex_u should live in box.
*/
typedef struct _u2_me_free {
u2_me_box box_u;
@ -75,9 +85,10 @@
** (stack); ~ is deep storage (immutable); $ is the allocation block;
** # is free memory.
**
** Pointer restrictions: pointers stored in + can point anywhere;
** pointers in - can only point to - or ~; pointers in ~ can only
** point to ~.
** Pointer restrictions: pointers stored in + can point anywhere,
** except to more central pointers in +. (Ie, all pointers from
** stack to stack must point downward on the stack.) Pointers in
** - can only point to - or ~; pointers in ~ only point to ~.
**
** To "leap" is to create a new inner road in the ### free space.
** but in the reverse direction, so that when the inner road
@ -89,14 +100,28 @@
*/
typedef struct _u2_me_road {
struct _u2_me_road* par_u; // parent road
struct _u2_me_road* kid_u; // child road list
struct _u2_me_road* nex_u; // sibling road
struct { // layout information
c3_w* cap_w; // top of transient region
c3_w* hat_w; // top of durable region
c3_w* mat_w; // bottom of transient region
c3_w* rut_w; // bottom of durable region
c3_w* gar_w; // bottom of guard region (future)
c3_w* rag_w; // top of guard region (future)
c3_w pad_w[4]; // future interesting info
} lay;
struct { // escape buffer
union {
jmp_buf buf;
c3_w buf_w[256]; // futureproofing
};
} esc;
struct { // allocation pools
u2_me_free* fre_u[u2_me_free_no]; // heap by node size log
# ifdef U2_MEMORY_DEBUG
@ -112,6 +137,10 @@
u2_noun fly; // $+(* (unit))
} ski;
struct { // need state
u2_noun nyd; // (list path)
} nyd;
struct { // trace stack
u2_noun tax; // (list ,*)
} bug;
@ -147,27 +176,51 @@
/** Macros.
**/
# define u2_me_is_north ((u2R->cap > u2R->hat) ? u2_yes : u2_no)
# define u2_me_is_south (!u2_me_is_north)
# define u2_me_is_south ((u2_yes == u2_me_is_north) ? u2_no : u2_yes)
# define u2_me_open ( (u2_yes == u2_me_is_north) \
? (c3_w)(u2R->cap - u2R->hat) \
: (c3_w)(u2R->hat - u2R->cap) )
# define u2_me_into(x) (((c3_w*)(void*)u2H) + (x))
# define u2_me_outa(p) (((c3_w*)(void*)(p)) - (c3w*)(void*)u2H)
/** Functions.
**/
**/
/* u2_me_boot(): make u2R and u2H from `len` words at `mem`.
*/
void
u2_me_boot(void* mem_v, c3_w len_w);
/* u2_me_grab(): garbage-collect memory. Assumes u2R == u2H.
/* u2_me_trap(): setjmp within road.
*/
#if 0
u2_noun
u2_me_trap(void);
#else
# define u2_me_trap() (u2_noun)(setjmp(u2R->esc.buf))
#endif
/* u2_me_bail(): bail out. Does not return.
**
** Bail motes:
**
** %exit :: semantic failure
** %intr :: interrupt
** %fail :: execution failure
** %need :: network block
** %meme :: out of memory
*/
c3_i
u2_me_bail(c3_m how_m);
/* u2_me_grab(): garbage-collect memory. Asserts u2R == u2H.
*/
void
u2_me_grab(void);
/* u2_me_check(): checkpoint memory to file.
**
** Assumes u2R == u2H.
/* u2_me_check(): checkpoint memory to file. Asserts u2R == u2H.
*/
void
u2_me_check(void);
@ -182,19 +235,32 @@
void
u2_me_leap(void);
/* u2_me_flog(): release inner-allocated storage.
/* u2_me_golf(): record cap length for u2_flog().
*/
c3_w
u2_me_golf(void);
/* u2_me_flog(): pop the cap.
**
** The proper sequence for inner allocation is:
** A common sequence for inner allocation is:
**
** c3_w gof_w = u2_me_golf();
** u2_me_leap();
** // allocate some inner stuff...
** u2_me_fall();
** // inner stuff is still valid, but on cap
** u2_me_
**
** u2_me_flog(0) simply clears the cap.
*/
void
u2_me_flog(void);
/* u2_me_water(): produce high and low watermarks. Asserts u2R == u2H.
*/
void
u2_me_water(c3_w *low_w, c3_w *hig_w);
/** Allocation.
**/
/* Basic allocation.