From 05ff6c6b4d56b9a53c3b5e2e045406ce52923248 Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 01/26] .gitignore ignore tag files Is there a reason this was removed when transferring to /vere? --- .gitignore | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.gitignore b/.gitignore index 135d632ff8..251a0d7f0f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,15 @@ *.swo *.swp +# Tags +.tags +.etags +TAGS +TAGS* +GPATH +GRTAGS +GTAGS + # Fake ships. /zod /nec From 2da1f13cb795b68c6405a2af57b6e3a659ec46b4 Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 02/26] new canon --- pkg/c3/types.h | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/pkg/c3/types.h b/pkg/c3/types.h index 9126a510a1..8214fbca57 100644 --- a/pkg/c3/types.h +++ b/pkg/c3/types.h @@ -9,6 +9,8 @@ **/ /* Canonical integers. */ + typedef size_t c3_z; + typedef ssize_t c3_zs; typedef uint64_t c3_d; typedef int64_t c3_ds; typedef uint32_t c3_w; @@ -32,4 +34,42 @@ typedef uintptr_t c3_p; // pointer-length uint - really really bad typedef intptr_t c3_ps; // pointer-length int - really really bad + /* Print specifiers + */ + + /* c3_z */ + #define PRIc3_z "zu" /* unsigned dec */ + #define PRIc3_zs "zd" /* signed dec */ + #define PRIxc3_z "zx" /* unsigned hex */ + #define PRIXc3_z "zX" /* unsigned HEX */ + + /* c3_d */ + #define PRIc3_d PRIu64 + #define PRIc3_ds PRIi64 + #define PRIxc3_d PRIx64 + #define PRIXc3_d PRIX64 + + /* c3_w */ + #define PRIc3_w PRIu32 + #define PRIc3_ws PRIi32 + #define PRIxc3_w PRIx32 + #define PRIXc3_w PRIX32 + + /* c3_s */ + #define PRIc3_s PRIu16 + #define PRIc3_ss PRIi16 + #define PRIxc3_s PRIx16 + #define PRIXc3_s PRIX16 + + /* c3_y */ + #define PRIc3_y PRIu8 + #define PRIc3_ys PRIi8 + #define PRIxc3_y PRIx8 + #define PRIXc3_y PRIX8 + + /* c3_b */ + #define PRIc3_b PRIu8 + #define PRIxc3_b PRIx8 + #define PRIXc3_b PRIX8 + #endif /* ifndef C3_TYPES_H */ From f04b4637f2065ba40de1f972f362b00d5058ff0f Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 03/26] c3_dessert -- debug assert (breakpoint trap) --- .bazelrc | 2 ++ pkg/c3/defs.h | 25 +++++++++++++++++++++++++ pkg/c3/portable.h | 3 +++ 3 files changed, 30 insertions(+) diff --git a/.bazelrc b/.bazelrc index 575100c626..8db5579173 100644 --- a/.bazelrc +++ b/.bazelrc @@ -35,12 +35,14 @@ build --host_copt='-O3' # fake ship tests. build --host_copt='-DU3_CPU_DEBUG' build --host_copt='-DU3_MEMORY_DEBUG' +build --host_copt='-DC3DBG' # Enable maximum debug info and disable optimizations for debug config. It's # important that these lines come after setting the default debug and # optimization level flags above. build:dbg --copt='-O0' build:dbg --copt='-g3' +build:dbg --copt='-DC3DBG' # Any personal configuration should go in .user.bazelrc. try-import %workspace%/.user.bazelrc diff --git a/pkg/c3/defs.h b/pkg/c3/defs.h index e631705ba1..6b9846c5f8 100644 --- a/pkg/c3/defs.h +++ b/pkg/c3/defs.h @@ -22,6 +22,11 @@ /** Random useful C macros. **/ /* Assert. Good to capture. + + TODO: determine which c3_assert calls can rather call c3_dessert, i.e. in + public releases, which calls to c3_assert should abort and which should + no-op? If the latter, is the assert useful inter-development to validate + conditions we might accidentally break or not useful at all? */ # if defined(ASAN_ENABLED) && defined(__clang__) @@ -44,6 +49,26 @@ } while(0) #endif + /* Dessert. Debug assert. If a debugger is attached, it will break in and + execution can be allowed to proceed without aborting the process. + Otherwise, the unhandled SIGTRAP will dump core. + */ +#ifdef C3DBG + #if defined(__i386__) || defined(__x86_64__) + #define c3_dessert(x) do { if(!(x)) __asm__ volatile("int $3"); } while (0) + #elif defined(__thumb__) + #define c3_dessert(x) do { if(!(x)) __asm__ volatile(".inst 0xde01"); } while (0) + #elif defined(__aarch64__) + #define c3_dessert(x) do { if(!(x)) __asm__ volatile(".inst 0xd4200000"); } while (0) + #elif defined(__arm__) + #define c3_dessert(x) do { if(!(x)) __asm__ volatile(".inst 0xe7f001f0"); } while (0) + #else + STATIC_ASSERT(0, "debugger break instruction unimplemented"); + #endif +#else + #define c3_dessert(x) ((void)(0)) +#endif + /* Stub. */ # define c3_stub c3_assert(!"stub") diff --git a/pkg/c3/portable.h b/pkg/c3/portable.h index 7e5f6f0372..22b4481c83 100644 --- a/pkg/c3/portable.h +++ b/pkg/c3/portable.h @@ -225,6 +225,9 @@ # endif /* Static assertion. + + TODO: we could just use static_assert (c23)/_Static_assert (c11) in + */ # define ASSERT_CONCAT_(a, b) a##b # define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b) From 4b718a5b255f2c40164046845764683cea933b97 Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 04/26] use reserved bit in U3_OS_LoomBits for 4G loom --- pkg/c3/portable.h | 2 +- pkg/noun/manage.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/c3/portable.h b/pkg/c3/portable.h index 22b4481c83..002276834b 100644 --- a/pkg/c3/portable.h +++ b/pkg/c3/portable.h @@ -114,7 +114,7 @@ /** Address space layout. *** - *** NB: 2^29 words == 2GB + *** NB: 2^30 words == 4G **/ # if defined(U3_OS_linux) # ifdef __LP64__ diff --git a/pkg/noun/manage.c b/pkg/noun/manage.c index 80897dc580..a0ed4acfe8 100644 --- a/pkg/noun/manage.c +++ b/pkg/noun/manage.c @@ -493,7 +493,7 @@ _pave_road(c3_w* rut_w, c3_w* mat_w, c3_w* cap_w, c3_w siz_w) // enable in case of corruption // // memset(mem_w, 0, 4 * len_w); - memset(rod_u, 0, 4 * siz_w); + memset(rod_u, 0, sizeof(c3_w) * siz_w); // the top and bottom of the heap are initially the same // From 6d390007491fb27de20524fa459d425d78daaba0 Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 05/26] misc --- pkg/noun/allocate.c | 4 ++-- pkg/noun/allocate.h | 11 +++++------ pkg/noun/jets.c | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index 0b2a5579b5..64296d36ae 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -85,8 +85,8 @@ _box_make(void* box_v, c3_w siz_w, c3_w use_w) c3_assert(siz_w >= u3a_minimum); - box_w[0] = siz_w; - box_w[siz_w - 1] = siz_w; + box_u->siz_w = siz_w; + box_w[siz_w - 1] = siz_w; /* stor size at end of allocation as well */ box_u->use_w = use_w; # ifdef U3_MEMORY_DEBUG diff --git a/pkg/noun/allocate.h b/pkg/noun/allocate.h index 49211efcd1..22d3101e9d 100644 --- a/pkg/noun/allocate.h +++ b/pkg/noun/allocate.h @@ -186,15 +186,14 @@ /** Macros. Should be better commented. **/ /* In and out of the box. + u3a_boxed -> sizeof u3a_box + allocation size (len_w) + 1 (for storing the redundant size) + u3a_boxto -> the region of memory adjacent to the box. + u3a_botox -> the box adjacent to the region of memory */ # define u3a_boxed(len_w) (len_w + c3_wiseof(u3a_box) + 1) # define u3a_boxto(box_v) ( (void *) \ - ( ((c3_w *)(void*)(box_v)) + \ - c3_wiseof(u3a_box) ) ) -# define u3a_botox(tox_v) ( (struct _u3a_box *) \ - (void *) \ - ( ((c3_w *)(void*)(tox_v)) - \ - c3_wiseof(u3a_box) ) ) + ( (u3a_box *)(void *)(box_v) + 1 ) ) +# define u3a_botox(tox_v) ( (u3a_box *)(void *)(tox_v) - 1 ) /* Inside a noun. */ diff --git a/pkg/noun/jets.c b/pkg/noun/jets.c index 96799e069b..84f8a4c60f 100644 --- a/pkg/noun/jets.c +++ b/pkg/noun/jets.c @@ -815,7 +815,7 @@ u3j_boot(c3_o nuu_o) { c3_assert(u3R == &(u3H->rod_u)); - u3D.len_l =_cj_count(0, u3D.dev_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)); From bcac1d6d2475550d734cc47c2dca900a32b49112 Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 06/26] misc. semantically inconsequential --- pkg/noun/allocate.c | 56 ++++++++++++++++++++++++++++++--------------- pkg/vere/lord.c | 1 + 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index 64296d36ae..16d2de785c 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -52,6 +52,15 @@ _box_count(c3_ws siz_ws) { } #endif /* _box_slot(): select the right free list to search for a block. + TODO: do we really need a loop to do this? + + so our free list logic looks like this: + siz_w < 6 words then [0] + siz_w < 16 then [1] + siz_w < 32 then [2] + siz_w < 64 then [3] + ... + siz_w > 4G then [26] */ static c3_w _box_slot(c3_w siz_w) @@ -59,23 +68,18 @@ _box_slot(c3_w siz_w) if ( siz_w < u3a_minimum ) { return 0; } - else { - c3_w i_w = 1; - while ( 1 ) { - if ( i_w == u3a_fbox_no ) { - return (i_w - 1); - } - if ( siz_w < 16 ) { - return i_w; - } - siz_w = (siz_w + 1) >> 1; - i_w += 1; - } + for (c3_w i_w = 1; i_w < u3a_fbox_no; i_w++) { + if ( siz_w < 16 ) return i_w; + siz_w = siz_w + 1 >> 1; } + return u3a_fbox_no - 1; } /* _box_make(): construct a box. + box_v - start addr of box + siz_w - size of allocated space adjacent to block + use_w - box's refcount */ static u3a_box* _box_make(void* box_v, c3_w siz_w, c3_w use_w) @@ -438,8 +442,18 @@ _ca_willoc(c3_w len_w, c3_w ald_w, c3_w alp_w) alp_w = (alp_w + c3_wiseof(u3a_box)) % ald_w; - // XX: this logic is totally bizarre, but preserve it. - // + /* XX: this logic is totally bizarre, but preserve it. + ** + ** This means we use the next size bigger instead of the "correct" + ** size. For example, a 20 word allocation will be freed into free + ** list 2 but will be allocated from free list 3. + ** + ** This is important to preserve because the sequential search may be + ** very slow. On a real-world task involving many compilations, + ** removing this line made this function appear in ~80% of samples. + ** + ** For reference, this was added in cgyarvin/urbit ffed9e748d8f6c. + */ if ( (sel_w != 0) && (sel_w != u3a_fbox_no - 1) ) { sel_w += 1; } @@ -449,6 +463,7 @@ _ca_willoc(c3_w len_w, c3_w ald_w, c3_w alp_w) u3p(u3a_fbox) *pfr_p = &u3R->all.fre_p[sel_w]; while ( 1 ) { + /* increment until we get a non-null freelist */ if ( 0 == *pfr_p ) { if ( sel_w < (u3a_fbox_no - 1) ) { sel_w += 1; @@ -480,7 +495,7 @@ _ca_willoc(c3_w len_w, c3_w ald_w, c3_w alp_w) else return u3a_boxto(box_u); } } - else { + else { /* we got a non-null freelist */ c3_w pad_w = _me_align_pad(*pfr_p, ald_w, alp_w); if ( 1 == ald_w ) c3_assert(0 == pad_w); @@ -491,7 +506,7 @@ _ca_willoc(c3_w len_w, c3_w ald_w, c3_w alp_w) pfr_p = &(u3to(u3a_fbox, *pfr_p)->nex_p); continue; } - else { + else { /* free block fits desired alloc size */ u3a_box* box_u = &(u3to(u3a_fbox, *pfr_p)->box_u); /* We have found a free block of adequate size. Remove it @@ -499,25 +514,30 @@ _ca_willoc(c3_w len_w, c3_w ald_w, c3_w alp_w) */ siz_w += pad_w; _box_count(-(box_u->siz_w)); + /* misc free list consistency checks. + TODO: in the future should probably only run for C3DBG builds */ { if ( (0 != u3to(u3a_fbox, *pfr_p)->pre_p) && (u3to(u3a_fbox, u3to(u3a_fbox, *pfr_p)->pre_p)->nex_p != (*pfr_p)) ) - { + { /* this->pre->nex isn't this */ c3_assert(!"loom: corrupt"); } if( (0 != u3to(u3a_fbox, *pfr_p)->nex_p) && (u3to(u3a_fbox, u3to(u3a_fbox, *pfr_p)->nex_p)->pre_p != (*pfr_p)) ) - { + { /* this->nex->pre isn't this */ c3_assert(!"loom: corrupt"); } + /* pop the block */ + /* this->nex->pre = this->pre */ if ( 0 != u3to(u3a_fbox, *pfr_p)->nex_p ) { u3to(u3a_fbox, u3to(u3a_fbox, *pfr_p)->nex_p)->pre_p = u3to(u3a_fbox, *pfr_p)->pre_p; } + /* this = this->nex */ *pfr_p = u3to(u3a_fbox, *pfr_p)->nex_p; } diff --git a/pkg/vere/lord.c b/pkg/vere/lord.c index 126c1120e9..bdb68b4981 100644 --- a/pkg/vere/lord.c +++ b/pkg/vere/lord.c @@ -1220,6 +1220,7 @@ u3_lord_init(c3_c* pax_c, c3_w wag_w, c3_d key_d[4], u3_lord_cb cb_u) god_u->ops_u.file = arg_c[0]; god_u->ops_u.args = arg_c; + /* spawns worker thread */ if ( (err_i = uv_spawn(u3L, &god_u->cub_u, &god_u->ops_u)) ) { fprintf(stderr, "spawn: %s: %s\r\n", arg_c[0], uv_strerror(err_i)); From abfd14c72ad3c4f751897a3ac0432bed26952a62 Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 07/26] make u3a_[into|outa|to[off|ptr|wtr]] macros inline funcs --- pkg/noun/allocate.c | 6 ++++++ pkg/noun/allocate.h | 50 +++++++++++++++++++++++++++++---------------- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index 16d2de785c..6db8fe33e3 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -18,6 +18,12 @@ c3_w u3_Code; // declarations of inline functions // +void *u3a_into(c3_w x); +c3_w u3a_outa(void *p); +c3_w u3a_to_off(c3_w som); +void *u3a_to_ptr(c3_w som); +c3_w *u3a_to_wtr(c3_w som); + void u3a_drop(const u3a_pile* pil_u); void* diff --git a/pkg/noun/allocate.h b/pkg/noun/allocate.h index 22d3101e9d..d4c5d71c2a 100644 --- a/pkg/noun/allocate.h +++ b/pkg/noun/allocate.h @@ -194,6 +194,7 @@ # define u3a_boxto(box_v) ( (void *) \ ( (u3a_box *)(void *)(box_v) + 1 ) ) # define u3a_botox(tox_v) ( (u3a_box *)(void *)(tox_v) - 1 ) + /* Inside a noun. */ @@ -213,18 +214,6 @@ */ # define u3a_is_pom(som) ((0b11 == ((som) >> 30)) ? c3y : c3n) - /* u3a_to_off(): mask off bits 30 and 31 from noun [som]. - */ -# define u3a_to_off(som) ((som) & 0x3fffffff) - - /* u3a_to_ptr(): convert noun [som] into generic pointer into loom. - */ -# define u3a_to_ptr(som) (u3a_into(u3a_to_off(som))) - - /* u3a_to_wtr(): convert noun [som] into word pointer into loom. - */ -# define u3a_to_wtr(som) ((c3_w *)u3a_to_ptr(som)) - /* u3a_to_pug(): set bit 31 of [off]. */ # define u3a_to_pug(off) (off | 0x80000000) @@ -260,15 +249,9 @@ : u3m_bail(c3__exit) ) # define u3t(som) u3a_t(som) - /* u3a_into(): convert loom offset [x] into generic pointer. - */ -# define u3a_into(x) ((void *)(u3_Loom + (x))) # define u3to(type, x) ((type *)u3a_into(x)) # define u3tn(type, x) (x) ? (type*)u3a_into(x) : (void*)NULL - /* u3a_outa(): convert pointer [p] into word offset into loom. - */ -# define u3a_outa(p) (((c3_w*)(void*)(p)) - u3_Loom) # define u3of(type, x) (u3a_outa((type*)x)) /* u3a_is_north(): yes if road [r] is north road. @@ -368,6 +351,37 @@ /** inline functions. **/ + + /* u3a_into(): convert loom offset [x] into generic pointer. + */ + inline void *u3a_into(c3_w x) { + return u3_Loom + x; + } + + /* u3a_outa(): convert pointer [p] into word offset into loom. + */ + inline c3_w u3a_outa(void *p) { + return ((c3_w *)p) - u3_Loom; + } + + /* u3a_to_off(): mask off bits 30 and 31 from noun [som]. + */ + inline c3_w u3a_to_off(c3_w som) { + return som & 0x3fffffff; /* 1 << 30 - 1 */ + } + + /* u3a_to_ptr(): convert noun [som] into generic pointer into loom. + */ + inline void *u3a_to_ptr(c3_w som) { + return u3a_into(u3a_to_off(som)); + } + + /* u3a_to_wtr(): convert noun [som] into word pointer into loom. + */ + inline c3_w *u3a_to_wtr(c3_w som) { + return (c3_w *)u3a_to_ptr(som); + } + /** road stack. **/ /* u3a_drop(): drop a road stack frame per [pil_u]. From d6261e914fd52f00fe6c5bd37188b6f0318722bf Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 08/26] DWORD aligned heap allocs --- pkg/c3/defs.h | 34 +++++++++++ pkg/noun/allocate.c | 145 +++++++++++++++++++++++++++++++++----------- pkg/noun/allocate.h | 39 +++++++++++- pkg/noun/manage.c | 77 +++++++++++++++-------- 4 files changed, 233 insertions(+), 62 deletions(-) diff --git a/pkg/c3/defs.h b/pkg/c3/defs.h index 6b9846c5f8..0a4948b484 100644 --- a/pkg/c3/defs.h +++ b/pkg/c3/defs.h @@ -186,4 +186,38 @@ # define c3_rename(a, b) ({ \ rename(a, b);}) +/* c3_align: hi or lo align x to al + + unless effective type of x is c3_w or c3_d, assumes x is a pointer. + */ +#define c3_align(x, al, hilo) \ + _Generic((x), \ + c3_w : c3_align_w, \ + c3_d : c3_align_d, \ + default : c3_align_p) \ + (x, al, hilo) +typedef enum { ALHI=1, ALLO=0 } align_dir; +inline c3_w +c3_align_w(c3_w x, c3_w al, align_dir hilo) { + c3_dessert(hilo <= ALHI && hilo >= ALLO); + x += hilo * (al - 1); + x &= ~(al - 1); + return x; +} +inline c3_d +c3_align_d(c3_d x, c3_d al, align_dir hilo) { + c3_dessert(hilo <= ALHI && hilo >= ALLO); + x += hilo * (al - 1); + x &= ~(al - 1); + return x; +} +inline void* +c3_align_p(void const * p, size_t al, align_dir hilo) { + uintptr_t x = (uintptr_t)p; + c3_dessert(hilo <= ALHI && hilo >= ALLO); + x += hilo * (al - 1); + x &= ~(al - 1); + return (void*)x; +} + #endif /* ifndef C3_DEFS_H */ diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index 6db8fe33e3..a121a474de 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -18,6 +18,9 @@ c3_w u3_Code; // declarations of inline functions // +c3_w c3_align_w(c3_w x, c3_w al, align_dir hilo); +c3_d c3_align_d(c3_d x, c3_d al, align_dir hilo); +void *c3_align_p(void const * p, size_t al, align_dir hilo); void *u3a_into(c3_w x); c3_w u3a_outa(void *p); c3_w u3a_to_off(c3_w som); @@ -57,6 +60,20 @@ static void _box_count(c3_ws siz_ws) { } #endif +/* _box_vaal(): validate box alignment. no-op without C3DBG + + TODO: I think validation code that might be compiled out like this, + _box_count, (others?) should have perhaps its own header and certainly its + own prefix. having to remind yourself that _box_count doesn't actually do + anything unless U3_CPU_DEBUG is defined is annoying. */ +#define _box_vaal(box_u) \ + do { \ + c3_dessert(((uintptr_t)u3a_boxto(box_u) \ + & u3a_balign-1) == 0); \ + c3_dessert((((u3a_box*)(box_u))->siz_w \ + & u3a_walign-1) == 0); \ + } while(0) + /* _box_slot(): select the right free list to search for a block. TODO: do we really need a loop to do this? @@ -99,6 +116,8 @@ _box_make(void* box_v, c3_w siz_w, c3_w use_w) box_w[siz_w - 1] = siz_w; /* stor size at end of allocation as well */ box_u->use_w = use_w; + _box_vaal(box_u); + # ifdef U3_MEMORY_DEBUG box_u->cod_w = u3_Code; box_u->eus_w = 0; @@ -189,6 +208,8 @@ _box_free(u3a_box* box_u) return; } + _box_vaal(box_u); + #if 0 /* Clear the contents of the block, for debugging. */ @@ -201,12 +222,12 @@ _box_free(u3a_box* box_u) } #endif - if ( c3y == u3a_is_north(u3R) ) { + if ( c3y == u3a_is_north(u3R) ) { /* north */ /* Try to coalesce with the block below. */ if ( box_w != u3a_into(u3R->rut_p) ) { - c3_w laz_w = *(box_w - 1); - u3a_box* pox_u = (u3a_box*)(void *)(box_w - laz_w); + c3_w laz_w = *(box_w - 1); /* the size of a box stored at the end of its allocation */ + u3a_box* pox_u = (u3a_box*)(void *)(box_w - laz_w); /* the head of the adjacent box below */ if ( 0 == pox_u->use_w ) { _box_detach(pox_u); @@ -231,8 +252,8 @@ _box_free(u3a_box* box_u) } _box_attach(box_u); } - } - else { + } /* end north */ + else { /* south */ /* Try to coalesce with the block above. */ if ( (box_w + box_u->siz_w) != u3a_into(u3R->rut_p) ) { @@ -260,7 +281,7 @@ _box_free(u3a_box* box_u) } _box_attach(box_u); } - } + } /* end south */ } /* _me_align_pad(): pad to first point after pos_p aligned at (ald_w, alp_w). @@ -301,29 +322,29 @@ _ca_box_make_hat(c3_w len_w, c3_w ald_w, c3_w alp_w, c3_w use_w) if ( c3y == u3a_is_north(u3R) ) { all_p = u3R->hat_p; - pad_w = _me_align_pad(all_p, ald_w, alp_w); - siz_w = (len_w + pad_w); + pad_w = c3_align(all_p, ald_w, ALHI) - all_p; + siz_w = c3_align(len_w + pad_w, u3a_walign, ALHI); // hand-inlined: siz_w >= u3a_open(u3R) // if ( (siz_w >= (u3R->cap_p - u3R->hat_p)) ) { return 0; } - u3R->hat_p = (all_p + siz_w); + u3R->hat_p += siz_w; } else { - all_p = (u3R->hat_p - len_w); - pad_w = _me_align_dap(all_p, ald_w, alp_w); - siz_w = (len_w + pad_w); - all_p -= pad_w; + all_p = u3R->hat_p - len_w; + pad_w = all_p - c3_align(all_p, ald_w, ALLO); + siz_w = c3_align(len_w + pad_w, u3a_walign, ALHI); // hand-inlined: siz_w >= u3a_open(u3R) // if ( siz_w >= (u3R->hat_p - u3R->cap_p) ) { return 0; } - u3R->hat_p = all_p; + all_p = u3R->hat_p -= siz_w; } + return _box_make(u3a_into(all_p), siz_w, use_w); } @@ -503,10 +524,11 @@ _ca_willoc(c3_w len_w, c3_w ald_w, c3_w alp_w) } else { /* we got a non-null freelist */ c3_w pad_w = _me_align_pad(*pfr_p, ald_w, alp_w); + c3_w des_w = c3_align(siz_w + pad_w, u3a_walign, ALHI); if ( 1 == ald_w ) c3_assert(0 == pad_w); - if ( (siz_w + pad_w) > u3to(u3a_fbox, *pfr_p)->box_u.siz_w ) { + if ( (des_w) > u3to(u3a_fbox, *pfr_p)->box_u.siz_w ) { /* This free block is too small. Continue searching. */ pfr_p = &(u3to(u3a_fbox, *pfr_p)->nex_p); @@ -518,7 +540,7 @@ _ca_willoc(c3_w len_w, c3_w ald_w, c3_w alp_w) /* We have found a free block of adequate size. Remove it ** from the free list. */ - siz_w += pad_w; + _box_count(-(box_u->siz_w)); /* misc free list consistency checks. TODO: in the future should probably only run for C3DBG builds */ @@ -549,15 +571,21 @@ _ca_willoc(c3_w len_w, c3_w ald_w, c3_w alp_w) /* If we can chop off another block, do it. */ - if ( (siz_w + u3a_minimum) <= box_u->siz_w ) { + if ( (des_w + u3a_minimum) <= box_u->siz_w ) { /* Split the block. */ + + /* XXX: Despite the fact that we're making a box here, we don't + actually have to ensure it's aligned, since siz_w and all boxes + already on the loom /are/ aligned. A debug break here implies + that you broke those conditions, not that this needs to handle + alignment. abandon hope. */ c3_w* box_w = ((c3_w *)(void *)box_u); - c3_w* end_w = box_w + siz_w; - c3_w lef_w = (box_u->siz_w - siz_w); + c3_w* end_w = box_w + des_w; + c3_w lef_w = (box_u->siz_w - des_w); _box_attach(_box_make(end_w, lef_w, 0)); - return u3a_boxto(_box_make(box_w, siz_w, 1)); + return u3a_boxto(_box_make(box_w, des_w, 1)); } else { c3_assert(0 == box_u->use_w); @@ -580,14 +608,31 @@ static void* _ca_walloc(c3_w len_w, c3_w ald_w, c3_w alp_w) { void* ptr_v; + c3_w req_w; /* allocation request length */ - while ( 1 ) { - ptr_v = _ca_willoc(len_w, ald_w, alp_w); + /* N.B: This odd looking logic is to generalize correct allocation lengths + requested from _ca_willoc to alignments other than DWORD. For DWORD (8 + byte) aligned references, this is eq to `req_w = len_w | 1`; + + ie we request an odd allocation length because c3_wiseof(u3a_box) + 1 is 3 + and 3 + {1,3,5,...} % 2 == 0 + + This works only because when we strip off mem from the hat or from a larger + fbox, we don't strip off any more than what was requested (+ padding) + */ + req_w = len_w + + (c3_wiseof(u3a_box) + 1) + + u3a_walign + & ~(u3a_walign - 1) + - (c3_wiseof(u3a_box) + 1); + for (;;) { + ptr_v = _ca_willoc(req_w, ald_w, alp_w); if ( 0 != ptr_v ) { break; } _ca_reclaim_half(); } + _box_vaal(u3a_botox(ptr_v)); return ptr_v; } @@ -614,6 +659,7 @@ u3a_walloc(c3_w len_w) xuc_i++; } #endif + _box_vaal(u3a_botox(ptr_v)); return ptr_v; } @@ -622,15 +668,24 @@ u3a_walloc(c3_w len_w) void* u3a_wealloc(void* lag_v, c3_w len_w) { + c3_w req_w; /* allocation request length */ + + /* N.B: see related note in _ca_walloc */ + req_w = len_w + + (c3_wiseof(u3a_box) + 1) + + u3a_walign + & ~(u3a_walign - 1) + - (c3_wiseof(u3a_box) + 1); + if ( !lag_v ) { - return u3a_malloc(len_w); + return u3a_malloc(req_w); } else { u3a_box* box_u = u3a_botox(lag_v); c3_w* old_w = lag_v; - c3_w tiz_w = c3_min(box_u->siz_w, len_w); + c3_w tiz_w = c3_min(box_u->siz_w, req_w); { - c3_w* new_w = u3a_walloc(len_w); + c3_w* new_w = u3a_walloc(req_w); c3_w i_w; for ( i_w = 0; i_w < tiz_w; i_w++ ) { @@ -670,23 +725,37 @@ u3a_wfree(void* tox_v) } /* u3a_wtrim(): trim storage. + + old_w - old length + len_w - new length */ 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; + if ( (old_w > len_w) + && ((old_w - len_w) >= u3a_minimum) ) + { + u3a_box* box_u = u3a_botox(nov_w); + c3_w* box_w = (void*)u3a_botox(nov_w); - _box_attach(_box_make(end_w, bsz_w, 0)); + c3_w* end_w = c3_align(nov_w + len_w + 1, /* +1 for trailing allocation size */ + u3a_balign, + ALHI); - box_w[0] = asz_w; + c3_w asz_w = (end_w - box_w); /* total size in words of new allocation */ + if (box_u->siz_w <= asz_w) return; + c3_w bsz_w = box_u->siz_w - asz_w; /* size diff in words between old and new */ + + c3_dessert(asz_w && ((asz_w & u3a_walign-1) == 0)); /* new allocation size must be non-zero and DWORD multiple */ + c3_dessert(end_w < (box_w + box_u->siz_w)); /* desired alloc end must not exceed existing boundaries */ + c3_dessert(((uintptr_t)end_w & u3a_balign-1) == 0); /* address of box getting freed must be DWORD aligned */ + c3_dessert((bsz_w & u3a_walign-1) == 0); /* size of box getting freed must be DWORD multiple */ + + _box_attach(_box_make(end_w, bsz_w, 0)); /* free the unneeded space */ + + box_u->siz_w = asz_w; box_w[asz_w - 1] = asz_w; } } @@ -732,6 +801,9 @@ u3a_malloc(size_t len_i) } /* u3a_cellblock(): allocate a block of cells on the hat. + + XXX beware when we stop boxing cells and QWORD align references. Alignment + not guaranteed to be preserved after a call. */ static c3_o u3a_cellblock(c3_w num_w) @@ -756,7 +828,7 @@ u3a_cellblock(c3_w num_w) // hand inline of _box_make(u3a_into(all_p), u3a_minimum, 1) { - box_w[0] = u3a_minimum; + box_u->siz_w = u3a_minimum; box_w[u3a_minimum - 1] = u3a_minimum; box_u->use_w = 1; #ifdef U3_MEMORY_DEBUG @@ -791,7 +863,7 @@ u3a_cellblock(c3_w num_w) // hand inline of _box_make(u3a_into(all_p), u3a_minimum, 1); { - box_w[0] = u3a_minimum; + box_u->siz_w = u3a_minimum; box_w[u3a_minimum - 1] = u3a_minimum; box_u->use_w = 1; # ifdef U3_MEMORY_DEBUG @@ -812,6 +884,7 @@ u3a_cellblock(c3_w num_w) } /* u3a_celloc(): allocate a cell. + XXX beware when we stop boxing cells and QWORD align references */ c3_w* u3a_celloc(void) diff --git a/pkg/noun/allocate.h b/pkg/noun/allocate.h index d4c5d71c2a..3f20223ac1 100644 --- a/pkg/noun/allocate.h +++ b/pkg/noun/allocate.h @@ -9,6 +9,19 @@ */ # define u3a_bits U3_OS_LoomBits + /* u3a_vits: number of virtual bits in a noun reference + gained via alignment + shifting + */ +# define u3a_vits ((c3_y)1) + + /* u3a_walign: references into the loom are guaranteed to be word-aligned to: + */ +# define u3a_walign ((c3_y)1 << u3a_vits) + + /* u3a_balign: u3a_walign in bytes + */ +# define u3a_balign (sizeof(c3_w)*u3a_walign) + /* u3a_page: number of bits in word-addressed page. 12 == 16Kbyte page. */ # define u3a_page 12 @@ -40,7 +53,7 @@ /* u3a_fbox_no: number of free lists per size. */ -# define u3a_fbox_no 27 +# define u3a_fbox_no 27 /* why 27? Perhaps because 16 = 1 << 4 and 31 - 4 = 27 */ /** Structures. @@ -335,6 +348,30 @@ : (u3a_botox(u3a_to_ptr(som))->use_w == 1) \ ? c3y : c3n ) +/* like _box_vaal but for rods. Again, probably want to prefix validation + functions at the very least. Maybe they can be defined in their own header. + + ps. while arguably cooler to have this compile to + + do {(void(0));(void(0));} while(0) + + It may be nicer to just wrap an inline function in #ifdef C3DBG guards. You + could even return the then validated road like + + u3a_road f() { + u3a_road rod_u; + ... + return _rod_vaal(rod_u); + } +*/ +# define _rod_vaal(rod_u) \ + do { \ + c3_dessert(((uintptr_t)((u3a_road*)(rod_u))->hat_p \ + & u3a_walign-1) == 0); \ + } while(0) + + + /** Globals. **/ /// Current road (thread-local). diff --git a/pkg/noun/manage.c b/pkg/noun/manage.c index a0ed4acfe8..283c6ecb17 100644 --- a/pkg/noun/manage.c +++ b/pkg/noun/manage.c @@ -483,11 +483,12 @@ _pave_parts(void) u3R->byc.har_p = u3h_new(); } -/* _pave_road(): initialize road boundaries +/* _pave_road(): writes road boundaries to loom mem (stored at mat_w) */ static u3_road* _pave_road(c3_w* rut_w, c3_w* mat_w, c3_w* cap_w, c3_w siz_w) { + c3_dessert(((uintptr_t)rut_w & u3a_balign-1) == 0); u3_road* rod_u = (void*) mat_w; // enable in case of corruption @@ -504,10 +505,17 @@ _pave_road(c3_w* rut_w, c3_w* mat_w, c3_w* cap_w, c3_w siz_w) rod_u->mat_p = u3of(c3_w, mat_w); // stack bottom rod_u->cap_p = u3of(c3_w, cap_w); // stack top + _rod_vaal(rod_u); return rod_u; } /* _pave_north(): calculate boundaries and initialize north road. + + mem_w - the "beginning" of your loom (its lowest address). Corresponds to rut + in a north road. + siz_w - the size in bytes of your road record (or home record in the case of + paving home). + len_w - size of your loom in words */ static u3_road* _pave_north(c3_w* mem_w, c3_w siz_w, c3_w len_w) @@ -518,14 +526,23 @@ _pave_north(c3_w* mem_w, c3_w siz_w, c3_w len_w) // the stack starts at the end of the memory segment, // minus space for the road structure [siz_w] // - c3_w* rut_w = mem_w; - c3_w* mat_w = ((mem_w + len_w) - siz_w); + // 00~~~|R|---|H|######|C|+++|M|~~~FF + // ^--u3R which _pave_road returns (u3H for home road) + // + c3_w* mat_w = c3_align(mem_w + len_w - siz_w, u3a_balign, ALLO); + c3_w* rut_w = c3_align(mem_w, u3a_balign, ALHI); c3_w* cap_w = mat_w; return _pave_road(rut_w, mat_w, cap_w, siz_w); } /* _pave_south(): calculate boundaries and initialize south road. + + mem_w - the "beginning" of your loom (its lowest address). Corresponds to mat + in a south road. + siz_w - the size in bytes of your road record (or home record in the case of + paving home). + len_w - size of your loom in words */ static u3_road* _pave_south(c3_w* mem_w, c3_w siz_w, c3_w len_w) @@ -536,8 +553,10 @@ _pave_south(c3_w* mem_w, c3_w siz_w, c3_w len_w) // the stack starts at the base memory pointer [mem_w], // and ends after the space for the road structure [siz_w] // - c3_w* rut_w = (mem_w + len_w); - c3_w* mat_w = mem_w; + // 00~~~|M|+++|C|######|H|---|R|~~~FFF + // ^---u3R which _pave_road returns + c3_w* mat_w = c3_align(mem_w, u3a_balign, ALHI); + c3_w* rut_w = c3_align(mem_w + len_w, u3a_balign, ALLO); c3_w* cap_w = mat_w + siz_w; return _pave_road(rut_w, mat_w, cap_w, siz_w); @@ -548,9 +567,9 @@ _pave_south(c3_w* mem_w, c3_w siz_w, c3_w len_w) static void _pave_home(void) { - c3_w* mem_w = u3_Loom + 1; + c3_w* mem_w = u3_Loom + u3a_walign; c3_w siz_w = c3_wiseof(u3v_home); - c3_w len_w = u3C.wor_i - 1; + c3_w len_w = u3C.wor_i - u3a_walign; u3H = (void *)_pave_north(mem_w, siz_w, len_w); u3H->ver_w = u3v_version; @@ -569,9 +588,10 @@ _find_home(void) { // NB: the home road is always north // - c3_w* mem_w = u3_Loom + 1; + c3_w* mem_w = u3_Loom + u3a_walign; c3_w siz_w = c3_wiseof(u3v_home); - c3_w len_w = u3C.wor_i - 1; + c3_w len_w = u3C.wor_i - u3a_walign; + c3_w* mat_w; { c3_w ver_w = *((mem_w + len_w) - 1); @@ -585,13 +605,16 @@ _find_home(void) } } - u3H = (void *)((mem_w + len_w) - siz_w); + mat_w = c3_align(mem_w + len_w - siz_w, u3a_balign, ALLO); + u3H = (void *)mat_w; u3R = &u3H->rod_u; // this looks risky, but there are no legitimate scenarios // where it's wrong // u3R->cap_p = u3R->mat_p = u3C.wor_i - c3_wiseof(*u3H); + + _rod_vaal(u3R); } /* u3m_pave(): instantiate or activate image. @@ -780,9 +803,11 @@ u3m_error(c3_c* str_c) void u3m_leap(c3_w pad_w) { - c3_w len_w; + c3_w len_w; /* the length of the new road (avail - (pad [4M] + wiseof(u3a_road))) */ u3_road* rod_u; + _rod_vaal(u3R); + /* Measure the pad - we'll need it. */ { @@ -795,40 +820,40 @@ u3m_leap(c3_w pad_w) } #endif if ( (pad_w + c3_wiseof(u3a_road)) >= u3a_open(u3R) ) { + /* not enough storage to leap */ u3m_bail(c3__meme); } - len_w = u3a_open(u3R) - (pad_w + c3_wiseof(u3a_road)); + pad_w += c3_wiseof(u3a_road); + len_w = u3a_open(u3R) - pad_w; + c3_align(len_w, u3a_walign, ALHI); } /* Allocate a region on the cap. */ { - u3p(c3_w) bot_p; + u3p(c3_w) bot_p; /* S: bot_p = new mat. N: bot_p = new rut */ if ( c3y == u3a_is_north(u3R) ) { - bot_p = (u3R->cap_p - len_w); - u3R->cap_p -= len_w; + bot_p = u3R->hat_p + pad_w; rod_u = _pave_south(u3a_into(bot_p), c3_wiseof(u3a_road), len_w); u3e_ward(rod_u->cap_p, rod_u->hat_p); #if 0 - fprintf(stderr, "leap: from north %p (cap 0x%x), to south %p\r\n", - u3R, - u3R->cap_p + len_w, - rod_u); + fprintf(stderr, "NPAR.hat_p: 0x%x %p, SKID.hat_p: 0x%x %p\r\n", + u3R->hat_p, u3a_into(u3R->hat_p), + rod_u->hat_p, u3a_into(rod_u->hat_p)); #endif } else { bot_p = u3R->cap_p; - u3R->cap_p += len_w; rod_u = _pave_north(u3a_into(bot_p), c3_wiseof(u3a_road), len_w); u3e_ward(rod_u->hat_p, rod_u->cap_p); #if 0 - fprintf(stderr, "leap: from south %p (cap 0x%x), to north %p\r\n", - u3R, - u3R->cap_p - len_w, - rod_u); + fprintf(stderr, "SPAR.hat_p: 0x%x %p, NKID.hat_p: 0x%x %p\r\n", + u3R->hat_p, u3a_into(u3R->hat_p), + rod_u->hat_p, u3a_into(rod_u->hat_p)); + #endif } } @@ -850,6 +875,8 @@ u3m_leap(c3_w pad_w) #ifdef U3_MEMORY_DEBUG rod_u->all.fre_w = 0; #endif + + _rod_vaal(u3R); } void @@ -1304,7 +1331,7 @@ u3m_soft(c3_w mil_w, { u3_noun why; - why = u3m_soft_top(mil_w, (1 << 20), fun_f, arg); // 2MB pad + why = u3m_soft_top(mil_w, (1 << 20), fun_f, arg); // 4M pad if ( 0 == u3h(why) ) { return why; From 8413fddb33d7b04167bf5e4d64e3c0e3994164e4 Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 09/26] pointer compression on 4G loom --- pkg/noun/allocate.c | 2 ++ pkg/noun/allocate.h | 24 +++++++++++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index a121a474de..59cf7dc307 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -26,6 +26,8 @@ c3_w u3a_outa(void *p); c3_w u3a_to_off(c3_w som); void *u3a_to_ptr(c3_w som); c3_w *u3a_to_wtr(c3_w som); +c3_w u3a_to_pug(c3_w off); +c3_w u3a_to_pom(c3_w off); void u3a_drop(const u3a_pile* pil_u); diff --git a/pkg/noun/allocate.h b/pkg/noun/allocate.h index 3f20223ac1..338bef8a70 100644 --- a/pkg/noun/allocate.h +++ b/pkg/noun/allocate.h @@ -227,14 +227,6 @@ */ # define u3a_is_pom(som) ((0b11 == ((som) >> 30)) ? c3y : c3n) - /* u3a_to_pug(): set bit 31 of [off]. - */ -# define u3a_to_pug(off) (off | 0x80000000) - - /* u3a_to_pom(): set bits 30 and 31 of [off]. - */ -# define u3a_to_pom(off) (off | 0xc0000000) - /* u3a_is_atom(): yes if noun [som] is direct atom or indirect atom. */ # define u3a_is_atom(som) c3o(u3a_is_cat(som), \ @@ -404,7 +396,7 @@ /* u3a_to_off(): mask off bits 30 and 31 from noun [som]. */ inline c3_w u3a_to_off(c3_w som) { - return som & 0x3fffffff; /* 1 << 30 - 1 */ + return (som & 0x3fffffff) << u3a_vits; } /* u3a_to_ptr(): convert noun [som] into generic pointer into loom. @@ -419,6 +411,20 @@ return (c3_w *)u3a_to_ptr(som); } + /* u3a_to_pug(): set bit 31 of [off]. + */ + inline c3_w u3a_to_pug(c3_w off) { + c3_dessert((off & u3a_walign-1) == 0); + return (off >> u3a_vits) | 0x80000000; + } + + /* u3a_to_pom(): set bits 30 and 31 of [off]. + */ + inline c3_w u3a_to_pom(c3_w off) { + c3_dessert((off & u3a_walign-1) == 0); + return (off >> u3a_vits) | 0xc0000000; + } + /** road stack. **/ /* u3a_drop(): drop a road stack frame per [pil_u]. From cea338ce27d289ecb09497915c1f9a3dc7b2f1ce Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 10/26] 4G -> 8G loom --- pkg/noun/allocate.h | 31 ++++++++++++++----------------- pkg/noun/hashtable.h | 6 +++--- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/pkg/noun/allocate.h b/pkg/noun/allocate.h index 338bef8a70..d282b7a5dc 100644 --- a/pkg/noun/allocate.h +++ b/pkg/noun/allocate.h @@ -7,54 +7,51 @@ **/ /* u3a_bits: number of bits in word-addressed pointer. 29 == 2GB. */ -# define u3a_bits U3_OS_LoomBits +# define u3a_bits U3_OS_LoomBits /* 30 */ - /* u3a_vits: number of virtual bits in a noun reference - gained via alignment + shifting + /* u3a_vits: number of virtual bits in a noun reference gained via shifting */ -# define u3a_vits ((c3_y)1) +# define u3a_vits 1 /* u3a_walign: references into the loom are guaranteed to be word-aligned to: */ -# define u3a_walign ((c3_y)1 << u3a_vits) +# define u3a_walign (1 << u3a_vits) /* u3a_balign: u3a_walign in bytes */ -# define u3a_balign (sizeof(c3_w)*u3a_walign) +# define u3a_balign (sizeof(c3_w)*u3a_walign) - /* u3a_page: number of bits in word-addressed page. 12 == 16Kbyte page. + /* u3a_page: number of bits in word-addressed page. 12 == 16K page */ -# define u3a_page 12 +# define u3a_page 12ULL /* u3a_pages: maximum number of pages in memory. */ -# define u3a_pages (1 << (u3a_bits - u3a_page)) +# define u3a_pages (1ULL << (u3a_bits + u3a_vits - u3a_page) ) /* u3a_words: maximum number of words in memory. */ -# define u3a_words (1 << u3a_bits) +# define u3a_words ( 1ULL << (u3a_bits + u3a_vits)) /* u3a_bytes: maximum number of bytes in memory. */ -# define u3a_bytes (sizeof(c3_w) * u3a_words) +# define u3a_bytes ((sizeof(c3_w) * u3a_words)) /* u3a_cells: number of representable cells. */ -# define u3a_cells (c3_w)(u3a_words / u3a_minimum) +# define u3a_cells (( u3a_words / u3a_minimum )) /* u3a_maximum: maximum loom object size (largest possible atom). */ -# define u3a_maximum \ - (c3_w)(u3a_words - (c3_wiseof(u3a_box) + c3_wiseof(u3a_atom))) +# define u3a_maximum ( u3a_words - (c3_wiseof(u3a_box) + c3_wiseof(u3a_atom) + 1)) /* u3a_minimum: minimum loom object size (actual size of a cell). */ -# define u3a_minimum (c3_w)(1 + c3_wiseof(u3a_box) + c3_wiseof(u3a_cell)) +# define u3a_minimum ((c3_w)( 1 + c3_wiseof(u3a_box) + c3_wiseof(u3a_cell) )) /* u3a_fbox_no: number of free lists per size. */ -# define u3a_fbox_no 27 /* why 27? Perhaps because 16 = 1 << 4 and 31 - 4 = 27 */ - +# define u3a_fbox_no 27 /** Structures. **/ diff --git a/pkg/noun/hashtable.h b/pkg/noun/hashtable.h index ffb17ae608..a117f50011 100644 --- a/pkg/noun/hashtable.h +++ b/pkg/noun/hashtable.h @@ -27,7 +27,7 @@ ** format - coordinate with allocate.h. The top two bits are: ** ** 00 - empty (in the root table only) - ** 01 - table + ** 01 - table (node or buck) ** 02 - entry, stale ** 03 - entry, fresh */ @@ -79,8 +79,8 @@ # define u3h_slot_is_node(sot) ((1 == ((sot) >> 30)) ? c3y : c3n) # define u3h_slot_is_noun(sot) ((1 == ((sot) >> 31)) ? c3y : c3n) # define u3h_slot_is_warm(sot) (((sot) & 0x40000000) ? c3y : c3n) -# define u3h_slot_to_node(sot) (u3a_into((sot) & 0x3fffffff)) -# define u3h_node_to_slot(ptr) (u3a_outa(ptr) | 0x40000000) +# define u3h_slot_to_node(sot) (u3a_into(((sot) & 0x3fffffff) << u3a_vits)) +# define u3h_node_to_slot(ptr) ((u3a_outa((ptr)) >> u3a_vits) | 0x40000000) # define u3h_noun_be_warm(sot) ((sot) | 0x40000000) # define u3h_noun_be_cold(sot) ((sot) & ~0x40000000) # define u3h_slot_to_noun(sot) (0x40000000 | (sot)) From 6c36069749f13855cd05d229b2cf6fa803d98b91 Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 11/26] golf u3r_met -- also fixes failing STATIC_ASSERT after 8G expansion I'm assuming the old switch-case was an attempted performance optimization - more constants with math that could be elided by the compiler, e.g. `if (gal_w > (UINT32_MAX - 35 >> 5))`. However, looking at -O3 disassembly, I really doubt it's any faster. There are at least as many conditional jumps and the instruction size is about 2x larger. === Moreover, this change does not artificially limit the size that gal_w can be. For instance, in the previous implementation, for a value of a_y=2, gal_w could not exceed the following without bailing: `(UINT32_MAX - 35) >> 5` => `0x07FFFFFF` Now, gal_w cannot exceed `((UINT32_MAX - (32 + max_y)) >> (5 - a_y))` => `((UINT32_MAX - 35) >> 3)` => `0x1FFFFFFF` === This has been confirmed to return exactly the same results as prior --- pkg/noun/retrieve.c | 85 ++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 51 deletions(-) diff --git a/pkg/noun/retrieve.c b/pkg/noun/retrieve.c index 80089e6892..41b2bcbaae 100644 --- a/pkg/noun/retrieve.c +++ b/pkg/noun/retrieve.c @@ -1033,63 +1033,46 @@ c3_w u3r_met(c3_y a_y, u3_atom b) { - c3_assert(u3_none != b); - c3_assert(_(u3a_is_atom(b))); + c3_dessert(u3_none != b); + c3_dessert(_(u3a_is_atom(b))); if ( b == 0 ) { return 0; } - else { - /* gal_w: number of words besides (daz_w) in (b). - ** daz_w: top word in (b). - */ - c3_w gal_w; - c3_w daz_w; + /* gal_w: number of words besides (daz_w) in (b). + ** daz_w: top word in (b). + */ + c3_w gal_w; + c3_w daz_w; - if ( _(u3a_is_cat(b)) ) { - gal_w = 0; - daz_w = b; - } - else { - u3a_atom* b_u = u3a_to_ptr(b); - - gal_w = (b_u->len_w) - 1; - daz_w = b_u->buf_w[gal_w]; - } - - switch ( a_y ) { - case 0: - case 1: - case 2: { - /* col_w: number of bits in (daz_w) - ** bif_w: number of bits in (b) - */ - c3_w bif_w, col_w; - - if ( gal_w > ((UINT32_MAX - 35) >> 5) ) { - return u3m_bail(c3__fail); - } - - col_w = c3_bits_word(daz_w); - bif_w = col_w + (gal_w << 5); - - return (bif_w + ((1 << a_y) - 1)) >> a_y; - } - - STATIC_ASSERT((UINT32_MAX > ((c3_d)u3a_maximum << 2)), - "met overflow"); - - case 3: return (gal_w << 2) + ((c3_bits_word(daz_w) + 7) >> 3); - - case 4: return (gal_w << 1) + ((c3_bits_word(daz_w) + 15) >> 4); - - default: { - c3_y gow_y = (a_y - 5); - - return ((gal_w + 1) + ((1 << gow_y) - 1)) >> gow_y; - } - } + if ( _(u3a_is_cat(b)) ) { + gal_w = 0; + daz_w = b; } + else { + u3a_atom* b_u = u3a_to_ptr(b); + + gal_w = (b_u->len_w) - 1; + daz_w = b_u->buf_w[gal_w]; + } + + /* 5 because 1<<2 bytes in c3_w, 1<<3 bits in byte. + aka log2(CHAR_BIT * sizeof gal_w) + a_y < 5 informs whether we shift return left or right + */ + if (a_y < 5) { + c3_y max_y = (1 << a_y) - 1; + c3_y gow_y = 5 - a_y; + + if (gal_w > ((UINT32_MAX - (32 + max_y)) >> gow_y)) + return u3m_bail(c3__fail); + + return (gal_w << gow_y) + + ((c3_bits_word(daz_w) + max_y) + >> a_y); + } + c3_y gow_y = (a_y - 5); + return ((gal_w + 1) + ((1 << gow_y) - 1)) >> gow_y; } /* u3r_bit(): From fbf69a018e7a225945876cb9cc3bbc38e85a2823 Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 12/26] prevent overflow when printing memory with |mass Previously, anything above 4G would overflow and print as less memory --- pkg/noun/allocate.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index 59cf7dc307..974cba91e6 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -2011,25 +2011,28 @@ u3a_print_memory(FILE* fil_u, c3_c* cap_c, c3_w wor_w) { c3_assert( 0 != fil_u ); - c3_w byt_w = (wor_w * 4); - c3_w gib_w = (byt_w / 1000000000); - c3_w mib_w = (byt_w % 1000000000) / 1000000; - c3_w kib_w = (byt_w % 1000000) / 1000; - c3_w bib_w = (byt_w % 1000); + c3_z byt_z = ((c3_z)wor_w * 4); + c3_z gib_z = (byt_z / 1000000000); + c3_z mib_z = (byt_z % 1000000000) / 1000000; + c3_z kib_z = (byt_z % 1000000) / 1000; + c3_z bib_z = (byt_z % 1000); - if ( byt_w ) { - if ( gib_w ) { - fprintf(fil_u, "%s: GB/%d.%03d.%03d.%03d\r\n", - cap_c, gib_w, mib_w, kib_w, bib_w); + if ( byt_z ) { + if ( gib_z ) { + fprintf(fil_u, "%s: GB/%" PRIc3_z ".%03" PRIc3_z ".%03" PRIc3_z ".%03" PRIc3_z "\r\n", + cap_c, gib_z, mib_z, kib_z, bib_z); } - else if ( mib_w ) { - fprintf(fil_u, "%s: MB/%d.%03d.%03d\r\n", cap_c, mib_w, kib_w, bib_w); + else if ( mib_z ) { + fprintf(fil_u, "%s: MB/%" PRIc3_z ".%03" PRIc3_z ".%03" PRIc3_z "\r\n", + cap_c, mib_z, kib_z, bib_z); } - else if ( kib_w ) { - fprintf(fil_u, "%s: KB/%d.%03d\r\n", cap_c, kib_w, bib_w); + else if ( kib_z ) { + fprintf(fil_u, "%s: KB/%" PRIc3_z ".%03" PRIc3_z "\r\n", + cap_c, kib_z, bib_z); } - else if ( bib_w ) { - fprintf(fil_u, "%s: B/%d\r\n", cap_c, bib_w); + else if ( bib_z ) { + fprintf(fil_u, "%s: B/%" PRIc3_z "\r\n", + cap_c, bib_z); } } } From c93ef2e82c6330a9a15da41f1795248afb203b23 Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 13/26] fix snapshot crashes caused by > (2^32) addressable bytes in loom Changes in next/vere also fixed this. This is nearly a subset of those changes. --- pkg/noun/events.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pkg/noun/events.c b/pkg/noun/events.c index 2ff5d3206d..17aa0ee8fd 100644 --- a/pkg/noun/events.c +++ b/pkg/noun/events.c @@ -442,7 +442,7 @@ _ce_patch_delete(void) { c3_c ful_c[8193]; - snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c); + snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c); if ( unlink(ful_c) ) { fprintf(stderr, "loom: failed to delete control.bin: %s\r\n", strerror(errno)); @@ -460,8 +460,9 @@ _ce_patch_delete(void) static c3_o _ce_patch_verify(u3_ce_patch* pat_u) { + c3_w pag_w, mug_w; + c3_w mem_w[pag_wiz_i]; ssize_t ret_i; - c3_w i_w; if ( u3e_version != pat_u->con_u->ver_y ) { fprintf(stderr, "loom: patch version mismatch: have %u, need %u\r\n", @@ -470,10 +471,9 @@ _ce_patch_verify(u3_ce_patch* pat_u) return c3n; } - for ( i_w = 0; i_w < pat_u->con_u->pgs_w; i_w++ ) { - c3_w pag_w = pat_u->con_u->mem_u[i_w].pag_w; - c3_w mug_w = pat_u->con_u->mem_u[i_w].mug_w; - c3_w mem_w[1 << u3a_page]; + for ( c3_z i_w = 0; i_w < pat_u->con_u->pgs_w; i_w++ ) { + pag_w = pat_u->con_u->mem_u[i_w].pag_w; + mug_w = pat_u->con_u->mem_u[i_w].mug_w; if ( -1 == lseek(pat_u->mem_i, (i_w << (u3a_page + 2)), SEEK_SET) ) { fprintf(stderr, "loom: patch seek: %s\r\n", strerror(errno)); @@ -492,13 +492,13 @@ _ce_patch_verify(u3_ce_patch* pat_u) c3_w nug_w = u3r_mug_words(mem_w, pag_wiz_i); if ( mug_w != nug_w ) { - fprintf(stderr, "loom: patch mug mismatch %d/%d; (%x, %x)\r\n", + fprintf(stderr, "loom: patch mug mismatch %d/%zu; (%x, %x)\r\n", pag_w, i_w, mug_w, nug_w); return c3n; } #if 0 else { - u3l_log("verify: patch %d/%d, %x", pag_w, i_w, mug_w); + u3l_log("verify: patch %d/%zu, %x", pag_w, i_w, mug_w); } #endif } @@ -787,7 +787,7 @@ _ce_patch_apply(u3_ce_patch* pat_u) c3_w pag_w = pat_u->con_u->mem_u[i_w].pag_w; c3_w mem_w[pag_wiz_i]; c3_i fid_i; - c3_w off_w; + c3_z off_w; if ( pag_w < pat_u->con_u->nor_w ) { fid_i = u3P.nor_u.fid_i; From b5bef4fc0951e058602fc752a19c0f34e0ad1b0e Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 14/26] refactor _ce_patch_verify -- use new PRIc3... printf specifiers --- pkg/noun/events.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/pkg/noun/events.c b/pkg/noun/events.c index 17aa0ee8fd..aa9123dd1c 100644 --- a/pkg/noun/events.c +++ b/pkg/noun/events.c @@ -460,31 +460,32 @@ _ce_patch_delete(void) static c3_o _ce_patch_verify(u3_ce_patch* pat_u) { - c3_w pag_w, mug_w; - c3_w mem_w[pag_wiz_i]; - ssize_t ret_i; + c3_w pag_w, mug_w; + c3_w mem_w[pag_wiz_i]; + c3_zs ret_zs; if ( u3e_version != pat_u->con_u->ver_y ) { - fprintf(stderr, "loom: patch version mismatch: have %u, need %u\r\n", + fprintf(stderr, "loom: patch version mismatch: have %"PRIc3_y", need %u\r\n", pat_u->con_u->ver_y, u3e_version); return c3n; } - for ( c3_z i_w = 0; i_w < pat_u->con_u->pgs_w; i_w++ ) { - pag_w = pat_u->con_u->mem_u[i_w].pag_w; - mug_w = pat_u->con_u->mem_u[i_w].mug_w; + for ( c3_z i_z = 0; i_z < pat_u->con_u->pgs_w; i_z++ ) { + pag_w = pat_u->con_u->mem_u[i_z].pag_w; + mug_w = pat_u->con_u->mem_u[i_z].mug_w; - if ( -1 == lseek(pat_u->mem_i, (i_w << (u3a_page + 2)), SEEK_SET) ) { + if ( -1 == lseek(pat_u->mem_i, (i_z << (u3a_page + 2)), SEEK_SET) ) { fprintf(stderr, "loom: patch seek: %s\r\n", strerror(errno)); return c3n; } - if ( pag_siz_i != (ret_i = read(pat_u->mem_i, mem_w, pag_siz_i)) ) { - if ( 0 < ret_i ) { - fprintf(stderr, "loom: patch partial read: %zu\r\n", (size_t)ret_i); + if ( pag_siz_i != (ret_zs = read(pat_u->mem_i, mem_w, pag_siz_i)) ) { + if ( 0 < ret_zs ) { + fprintf(stderr, "loom: patch partial read: %"PRIc3_zs"\r\n", ret_zs); } else { - fprintf(stderr, "loom: patch read fail: %s\r\n", strerror(errno)); + fprintf(stderr, "loom: patch read: fail %"PRIc3_zs" of %"PRIc3_z" bytes\r\n", + ret_zs, pag_siz_i); } return c3n; } @@ -492,13 +493,13 @@ _ce_patch_verify(u3_ce_patch* pat_u) c3_w nug_w = u3r_mug_words(mem_w, pag_wiz_i); if ( mug_w != nug_w ) { - fprintf(stderr, "loom: patch mug mismatch %d/%zu; (%x, %x)\r\n", - pag_w, i_w, mug_w, nug_w); + fprintf(stderr, "loom: patch mug mismatch %"PRIc3_w"/%"PRIc3_z"; (%"PRIxc3_w", %"PRIxc3_w")\r\n", + pag_w, i_z, mug_w, nug_w); return c3n; } #if 0 else { - u3l_log("verify: patch %d/%zu, %x", pag_w, i_w, mug_w); + u3l_log("verify: patch %"PRIc3_w"/%"PRIc3_z", %"PRIxc3_w"\r\n", pag_w, i_z, mug_w); } #endif } From 8c0cc711274519a563ba4e4712544457e64f4237 Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 15/26] specify up to 33 bits (8G) with --loom Unsure how we should ultimately do this. Specifying 33 bits should be conditional on the loom having compressed pointers obviously. P.S. Having implemented the migration by now, the migration is not optional, so this is fine. --- pkg/noun/allocate.h | 4 ++++ pkg/vere/main.c | 48 ++++++++++++++++++++++----------------------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/pkg/noun/allocate.h b/pkg/noun/allocate.h index d282b7a5dc..d084c0ee2a 100644 --- a/pkg/noun/allocate.h +++ b/pkg/noun/allocate.h @@ -21,6 +21,10 @@ */ # define u3a_balign (sizeof(c3_w)*u3a_walign) + /* u3a_bits_max: max loom bex + */ +# define u3a_bits_max (8 * sizeof(c3_w) + u3a_vits_max) + /* u3a_page: number of bits in word-addressed page. 12 == 16K page */ # define u3a_page 12ULL diff --git a/pkg/vere/main.c b/pkg/vere/main.c index 477aaa871e..9b3c352214 100644 --- a/pkg/vere/main.c +++ b/pkg/vere/main.c @@ -166,8 +166,8 @@ _main_init(void) u3_Host.ops_u.hap_w = 50000; u3_Host.ops_u.kno_w = DefaultKernel; - u3_Host.ops_u.lut_y = u3a_bits + 1; - u3_Host.ops_u.lom_y = u3a_bits + 1; + u3_Host.ops_u.lut_y = 31; /* aka 2G */ + u3_Host.ops_u.lom_y = 31; } /* _main_pier_run(): get pier from binary path (argv[0]), if appropriate @@ -256,9 +256,9 @@ _main_getopt(c3_i argc, c3_c** argv) switch ( ch_i ) { case 5: { // urth-loom c3_w lut_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lut_w); + c3_o res_o = _main_readw(optarg, u3a_bits_max+1, &lut_w); if ( (c3n == res_o) || (lut_w < 20) ) { - fprintf(stderr, "error: --urth-loom must be >= 20 and <= %u\r\n", u3a_bits + 2); + fprintf(stderr, "error: --urth-loom must be >= 20 and <= %zu\r\n", u3a_bits_max); return c3n; } @@ -367,9 +367,9 @@ _main_getopt(c3_i argc, c3_c** argv) } case c3__loom: { c3_w lom_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w); + c3_o res_o = _main_readw(optarg, u3a_bits_max+1, &lom_w); if ( (c3n == res_o) || (lom_w < 20) ) { - fprintf(stderr, "error: --loom must be >= 20 and <= %u\r\n", u3a_bits + 2); + fprintf(stderr, "error: --loom must be >= 20 and <= %zu\r\n", u3a_bits_max); return c3n; } u3_Host.ops_u.lom_y = lom_w; @@ -1176,9 +1176,9 @@ _cw_eval(c3_i argc, c3_c* argv[]) switch ( ch_i ) { case c3__loom: { c3_w lom_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w); + c3_o res_o = _main_readw(optarg, u3a_bits_max+1, &lom_w); if ( (c3n == res_o) || (lom_w < 24) ) { - fprintf(stderr, "error: --loom must be >= 24 and <= %u\r\n", u3a_bits + 2); + fprintf(stderr, "error: --loom must be >= 24 and <= %zu\r\n", u3a_bits_max); exit(1); } u3_Host.ops_u.lom_y = lom_w; @@ -1373,9 +1373,9 @@ _cw_cram(c3_i argc, c3_c* argv[]) switch ( ch_i ) { case c3__loom: { c3_w lom_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w); + c3_o res_o = _main_readw(optarg, u3a_bits_max+1, &lom_w); if ( (c3n == res_o) || (lom_w < 20) ) { - fprintf(stderr, "error: --loom must be >= 20 and <= %u\r\n", u3a_bits + 2); + fprintf(stderr, "error: --loom must be >= 20 and <= %zu\r\n", u3a_bits_max); exit(1); } u3_Host.ops_u.lom_y = lom_w; @@ -1452,9 +1452,9 @@ _cw_queu(c3_i argc, c3_c* argv[]) switch ( ch_i ) { case c3__loom: { c3_w lom_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w); + c3_o res_o = _main_readw(optarg, u3a_bits_max+1, &lom_w); if ( (c3n == res_o) || (lom_w < 20) ) { - fprintf(stderr, "error: --loom must be >= 20 and <= %u\r\n", u3a_bits + 2); + fprintf(stderr, "error: --loom must be >= 20 and <= %zu\r\n", u3a_bits_max); exit(1); } u3_Host.ops_u.lom_y = lom_w; @@ -1537,9 +1537,9 @@ _cw_meld(c3_i argc, c3_c* argv[]) switch ( ch_i ) { case c3__loom: { c3_w lom_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w); + c3_o res_o = _main_readw(optarg, u3a_bits_max+1, &lom_w); if ( (c3n == res_o) || (lom_w < 20) ) { - fprintf(stderr, "error: --loom must be >= 20 and <= %u\r\n", u3a_bits + 2); + fprintf(stderr, "error: --loom must be >= 20 and <= %zu\r\n", u3a_bits_max); exit(1); } u3_Host.ops_u.lom_y = lom_w; @@ -1611,9 +1611,9 @@ _cw_next(c3_i argc, c3_c* argv[]) case c3__loom: { c3_w lom_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w); + c3_o res_o = _main_readw(optarg, u3a_bits_max+1, &lom_w); if ( (c3n == res_o) || (lom_w < 20) ) { - fprintf(stderr, "error: --loom must be >= 20 and <= %u\r\n", u3a_bits + 2); + fprintf(stderr, "error: --loom must be >= 20 and <= %zu\r\n", u3a_bits_max); exit(1); } u3_Host.ops_u.lom_y = lom_w; @@ -1670,9 +1670,9 @@ _cw_pack(c3_i argc, c3_c* argv[]) switch ( ch_i ) { case c3__loom: { c3_w lom_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w); + c3_o res_o = _main_readw(optarg, u3a_bits_max+1, &lom_w); if ( (c3n == res_o) || (lom_w < 20) ) { - fprintf(stderr, "error: --loom must be >= 20 and <= %u\r\n", u3a_bits + 2); + fprintf(stderr, "error: --loom must be >= 20 and <= %zu\r\n", u3a_bits_max); exit(1); } u3_Host.ops_u.lom_y = lom_w; @@ -1785,9 +1785,9 @@ _cw_prep(c3_i argc, c3_c* argv[]) switch ( ch_i ) { case c3__loom: { c3_w lom_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w); + c3_o res_o = _main_readw(optarg, u3a_bits_max+1, &lom_w); if ( (c3n == res_o) || (lom_w < 20) ) { - fprintf(stderr, "error: --loom must be >= 20 and <= %u\r\n", u3a_bits + 2); + fprintf(stderr, "error: --loom must be >= 20 and <= %zu\r\n", u3a_bits_max); exit(1); } u3_Host.ops_u.lom_y = lom_w; @@ -1843,9 +1843,9 @@ _cw_chop(c3_i argc, c3_c* argv[]) switch ( ch_i ) { case c3__loom: { c3_w lom_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w); + c3_o res_o = _main_readw(optarg, u3a_bits_max+1, &lom_w); if ( (c3n == res_o) || (lom_w < 20) ) { - fprintf(stderr, "error: --loom must be >= 20 and <= %u\r\n", u3a_bits + 2); + fprintf(stderr, "error: --loom must be >= 20 and <= %zu\r\n", u3a_bits_max); exit(1); } u3_Host.ops_u.lom_y = lom_w; @@ -2130,9 +2130,9 @@ _cw_vile(c3_i argc, c3_c* argv[]) switch ( ch_i ) { case c3__loom: { c3_w lom_w; - c3_o res_o = _main_readw(optarg, u3a_bits + 3, &lom_w); + c3_o res_o = _main_readw(optarg, u3a_bits_max+1, &lom_w); if ( (c3n == res_o) || (lom_w < 20) ) { - fprintf(stderr, "error: --loom must be >= 20 and <= %u\r\n", u3a_bits + 2); + fprintf(stderr, "error: --loom must be >= 20 and <= %zu\r\n", u3a_bits_max); exit(1); } u3_Host.ops_u.lom_y = lom_w; From 0966fb01955a78ed11029fd248273d57ff735dda Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 16/26] fix patch control version var name pat_u->con_u->ver_y -> ver_w --- pkg/noun/events.c | 8 ++++---- pkg/noun/events.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/noun/events.c b/pkg/noun/events.c index aa9123dd1c..03774353ef 100644 --- a/pkg/noun/events.c +++ b/pkg/noun/events.c @@ -464,9 +464,9 @@ _ce_patch_verify(u3_ce_patch* pat_u) c3_w mem_w[pag_wiz_i]; c3_zs ret_zs; - if ( u3e_version != pat_u->con_u->ver_y ) { - fprintf(stderr, "loom: patch version mismatch: have %"PRIc3_y", need %u\r\n", - pat_u->con_u->ver_y, + if ( u3e_version != pat_u->con_u->ver_w ) { + fprintf(stderr, "loom: patch version mismatch: have %"PRIc3_w", need %u\r\n", + pat_u->con_u->ver_w, u3e_version); return c3n; } @@ -692,7 +692,7 @@ _ce_patch_compose(void) _ce_patch_create(pat_u); pat_u->con_u = c3_malloc(sizeof(u3e_control) + (pgs_w * sizeof(u3e_line))); - pat_u->con_u->ver_y = u3e_version; + pat_u->con_u->ver_w = u3e_version; pgc_w = 0; for ( i_w = 0; i_w < nor_w; i_w++ ) { diff --git a/pkg/noun/events.h b/pkg/noun/events.h index 7c71658e47..d7345799c2 100644 --- a/pkg/noun/events.h +++ b/pkg/noun/events.h @@ -18,7 +18,7 @@ /* u3e_control: memory change, control file. */ typedef struct _u3e_control { - c3_w ver_y; // version number + c3_w ver_w; // version number c3_w nor_w; // new page count north c3_w sou_w; // new page count south c3_w pgs_w; // number of changed pages From 48e326ff03a5fb74e54099ba0fbf93d40f0d679a Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 17/26] loom migration to support compressed pointers --- pkg/noun/allocate.c | 46 ++++++---- pkg/noun/allocate.h | 47 ++++++---- pkg/noun/hashtable.c | 14 +++ pkg/noun/hashtable.h | 4 +- pkg/noun/manage.c | 209 +++++++++++++++++++++++++++++++++++++------ pkg/noun/manage.h | 6 ++ pkg/noun/options.h | 9 +- pkg/noun/vortex.h | 12 ++- 8 files changed, 282 insertions(+), 65 deletions(-) diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index 974cba91e6..2928bbb95a 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -18,7 +18,9 @@ c3_w u3_Code; // declarations of inline functions // -c3_w c3_align_w(c3_w x, c3_w al, align_dir hilo); + +void u3a_config_loom(c3_w ver_w); +c3_w c3_align_w(c3_w x, c3_w al, align_dir hilo); /* ;;: after rebasing on /vere, these should be declared somewhere else (the align functions) */ c3_d c3_align_d(c3_d x, c3_d al, align_dir hilo); void *c3_align_p(void const * p, size_t al, align_dir hilo); void *u3a_into(c3_w x); @@ -71,9 +73,9 @@ _box_count(c3_ws siz_ws) { } #define _box_vaal(box_u) \ do { \ c3_dessert(((uintptr_t)u3a_boxto(box_u) \ - & u3a_balign-1) == 0); \ + & u3C.balign_d-1) == 0); \ c3_dessert((((u3a_box*)(box_u))->siz_w \ - & u3a_walign-1) == 0); \ + & u3C.walign_w-1) == 0); \ } while(0) /* _box_slot(): select the right free list to search for a block. @@ -325,7 +327,7 @@ _ca_box_make_hat(c3_w len_w, c3_w ald_w, c3_w alp_w, c3_w use_w) if ( c3y == u3a_is_north(u3R) ) { all_p = u3R->hat_p; pad_w = c3_align(all_p, ald_w, ALHI) - all_p; - siz_w = c3_align(len_w + pad_w, u3a_walign, ALHI); + siz_w = c3_align(len_w + pad_w, u3C.walign_w, ALHI); // hand-inlined: siz_w >= u3a_open(u3R) // @@ -337,7 +339,7 @@ _ca_box_make_hat(c3_w len_w, c3_w ald_w, c3_w alp_w, c3_w use_w) else { all_p = u3R->hat_p - len_w; pad_w = all_p - c3_align(all_p, ald_w, ALLO); - siz_w = c3_align(len_w + pad_w, u3a_walign, ALHI); + siz_w = c3_align(len_w + pad_w, u3C.walign_w, ALHI); // hand-inlined: siz_w >= u3a_open(u3R) // @@ -526,7 +528,7 @@ _ca_willoc(c3_w len_w, c3_w ald_w, c3_w alp_w) } else { /* we got a non-null freelist */ c3_w pad_w = _me_align_pad(*pfr_p, ald_w, alp_w); - c3_w des_w = c3_align(siz_w + pad_w, u3a_walign, ALHI); + c3_w des_w = c3_align(siz_w + pad_w, u3C.walign_w, ALHI); if ( 1 == ald_w ) c3_assert(0 == pad_w); @@ -624,8 +626,8 @@ _ca_walloc(c3_w len_w, c3_w ald_w, c3_w alp_w) */ req_w = len_w + (c3_wiseof(u3a_box) + 1) - + u3a_walign - & ~(u3a_walign - 1) + + u3C.walign_w + & ~(u3C.walign_w - 1) - (c3_wiseof(u3a_box) + 1); for (;;) { ptr_v = _ca_willoc(req_w, ald_w, alp_w); @@ -675,8 +677,8 @@ u3a_wealloc(void* lag_v, c3_w len_w) /* N.B: see related note in _ca_walloc */ req_w = len_w + (c3_wiseof(u3a_box) + 1) - + u3a_walign - & ~(u3a_walign - 1) + + u3C.walign_w + & ~(u3C.walign_w - 1) - (c3_wiseof(u3a_box) + 1); if ( !lag_v ) { @@ -743,17 +745,17 @@ u3a_wtrim(void* tox_v, c3_w old_w, c3_w len_w) c3_w* box_w = (void*)u3a_botox(nov_w); c3_w* end_w = c3_align(nov_w + len_w + 1, /* +1 for trailing allocation size */ - u3a_balign, + u3C.balign_d, ALHI); c3_w asz_w = (end_w - box_w); /* total size in words of new allocation */ if (box_u->siz_w <= asz_w) return; c3_w bsz_w = box_u->siz_w - asz_w; /* size diff in words between old and new */ - c3_dessert(asz_w && ((asz_w & u3a_walign-1) == 0)); /* new allocation size must be non-zero and DWORD multiple */ + c3_dessert(asz_w && ((asz_w & u3C.walign_w-1) == 0)); /* new allocation size must be non-zero and DWORD multiple */ c3_dessert(end_w < (box_w + box_u->siz_w)); /* desired alloc end must not exceed existing boundaries */ - c3_dessert(((uintptr_t)end_w & u3a_balign-1) == 0); /* address of box getting freed must be DWORD aligned */ - c3_dessert((bsz_w & u3a_walign-1) == 0); /* size of box getting freed must be DWORD multiple */ + c3_dessert(((uintptr_t)end_w & u3C.balign_d-1) == 0); /* address of box getting freed must be DWORD aligned */ + c3_dessert((bsz_w & u3C.walign_w-1) == 0); /* size of box getting freed must be DWORD multiple */ _box_attach(_box_make(end_w, bsz_w, 0)); /* free the unneeded space */ @@ -1783,12 +1785,24 @@ u3a_rewritten_noun(u3_noun som) return som; } u3_post som_p = u3a_rewritten(u3a_to_off(som)); + + /* If this is being called during a migration, one-bit pointer compression + needs to be temporarily enabled so the rewritten reference is compressed */ + if (u3C.migration_state == MIG_REWRITE_COMPRESSED) + u3C.vits_w = 1; + if ( c3y == u3a_is_pug(som) ) { - return u3a_to_pug(som_p); + som_p = u3a_to_pug(som_p); } else { - return u3a_to_pom(som_p); + som_p = u3a_to_pom(som_p); } + + /* likewise, pointer compression is disabled until migration is complete */ + if (u3C.migration_state == MIG_REWRITE_COMPRESSED) + u3C.vits_w = 0; + + return som_p; } /* u3a_mark_mptr(): mark a malloc-allocated ptr for gc. diff --git a/pkg/noun/allocate.h b/pkg/noun/allocate.h index d084c0ee2a..969e22879a 100644 --- a/pkg/noun/allocate.h +++ b/pkg/noun/allocate.h @@ -2,6 +2,7 @@ #define U3_ALLOCATE_H #include "manage.h" +#include "options.h" /** Constants. **/ @@ -9,17 +10,10 @@ */ # define u3a_bits U3_OS_LoomBits /* 30 */ - /* u3a_vits: number of virtual bits in a noun reference gained via shifting + /* u3a_vits_max: number of virtual bits in a reference gained via pointer + compression */ -# define u3a_vits 1 - - /* u3a_walign: references into the loom are guaranteed to be word-aligned to: - */ -# define u3a_walign (1 << u3a_vits) - - /* u3a_balign: u3a_walign in bytes - */ -# define u3a_balign (sizeof(c3_w)*u3a_walign) +# define u3a_vits_max 1 /* u3a_bits_max: max loom bex */ @@ -31,11 +25,11 @@ /* u3a_pages: maximum number of pages in memory. */ -# define u3a_pages (1ULL << (u3a_bits + u3a_vits - u3a_page) ) +# define u3a_pages (1ULL << (u3a_bits + u3a_vits_max - u3a_page) ) /* u3a_words: maximum number of words in memory. */ -# define u3a_words ( 1ULL << (u3a_bits + u3a_vits)) +# define u3a_words ( 1ULL << (u3a_bits + u3a_vits_max )) /* u3a_bytes: maximum number of bytes in memory. */ @@ -360,7 +354,7 @@ # define _rod_vaal(rod_u) \ do { \ c3_dessert(((uintptr_t)((u3a_road*)(rod_u))->hat_p \ - & u3a_walign-1) == 0); \ + & u3C.walign_w-1) == 0); \ } while(0) @@ -381,6 +375,23 @@ /** inline functions. **/ + /* u3a_config_loom(): configure loom information by u3v version + */ + inline void u3a_config_loom(c3_w ver_w) { + switch (ver_w) { + case /* U3V_VER1 */ 1: + u3C.vits_w = 0; + break; + case /* U3V_VER2 */ 2: + u3C.vits_w = 1; + break; + default: + c3_assert(0); + } + + u3C.walign_w = 1 << u3C.vits_w; + u3C.balign_d = sizeof(c3_w) * u3C.walign_w; +} /* u3a_into(): convert loom offset [x] into generic pointer. */ @@ -397,7 +408,7 @@ /* u3a_to_off(): mask off bits 30 and 31 from noun [som]. */ inline c3_w u3a_to_off(c3_w som) { - return (som & 0x3fffffff) << u3a_vits; + return (som & 0x3fffffff) << u3C.vits_w; } /* u3a_to_ptr(): convert noun [som] into generic pointer into loom. @@ -415,15 +426,15 @@ /* u3a_to_pug(): set bit 31 of [off]. */ inline c3_w u3a_to_pug(c3_w off) { - c3_dessert((off & u3a_walign-1) == 0); - return (off >> u3a_vits) | 0x80000000; + c3_dessert((off & u3C.walign_w-1) == 0); + return (off >> u3C.vits_w) | 0x80000000; } /* u3a_to_pom(): set bits 30 and 31 of [off]. */ inline c3_w u3a_to_pom(c3_w off) { - c3_dessert((off & u3a_walign-1) == 0); - return (off >> u3a_vits) | 0xc0000000; + c3_dessert((off & u3C.walign_w-1) == 0); + return (off >> u3C.vits_w) | 0xc0000000; } /** road stack. diff --git a/pkg/noun/hashtable.c b/pkg/noun/hashtable.c index bcbe62facc..76b15d6d28 100644 --- a/pkg/noun/hashtable.c +++ b/pkg/noun/hashtable.c @@ -1017,8 +1017,15 @@ _ch_rewrite_node(u3h_node* han_u, c3_w lef_w) else { void* hav_v = u3h_slot_to_node(sot_w); u3h_node* nod_u = u3to(u3h_node,u3a_rewritten(u3of(u3h_node,hav_v))); + + if (u3C.migration_state == MIG_REWRITE_COMPRESSED) + u3C.vits_w = 1; + han_u->sot_w[i_w] = u3h_node_to_slot(nod_u); + if (u3C.migration_state == MIG_REWRITE_COMPRESSED) + u3C.vits_w = 0; + if ( 0 == lef_w ) { _ch_rewrite_buck(hav_v); } else { @@ -1050,8 +1057,15 @@ u3h_rewrite(u3p(u3h_root) har_p) else if ( _(u3h_slot_is_node(sot_w)) ) { u3h_node* han_u = u3h_slot_to_node(sot_w); u3h_node* nod_u = u3to(u3h_node,u3a_rewritten(u3of(u3h_node,han_u))); + + if (u3C.migration_state == MIG_REWRITE_COMPRESSED) + u3C.vits_w = 1; + har_u->sot_w[i_w] = u3h_node_to_slot(nod_u); + if (u3C.migration_state == MIG_REWRITE_COMPRESSED) + u3C.vits_w = 0; + _ch_rewrite_node(han_u, 25); } } diff --git a/pkg/noun/hashtable.h b/pkg/noun/hashtable.h index a117f50011..be1d3f93be 100644 --- a/pkg/noun/hashtable.h +++ b/pkg/noun/hashtable.h @@ -79,8 +79,8 @@ # define u3h_slot_is_node(sot) ((1 == ((sot) >> 30)) ? c3y : c3n) # define u3h_slot_is_noun(sot) ((1 == ((sot) >> 31)) ? c3y : c3n) # define u3h_slot_is_warm(sot) (((sot) & 0x40000000) ? c3y : c3n) -# define u3h_slot_to_node(sot) (u3a_into(((sot) & 0x3fffffff) << u3a_vits)) -# define u3h_node_to_slot(ptr) ((u3a_outa((ptr)) >> u3a_vits) | 0x40000000) +# define u3h_slot_to_node(sot) (u3a_into(((sot) & 0x3fffffff) << u3C.vits_w)) +# define u3h_node_to_slot(ptr) ((u3a_outa((ptr)) >> u3C.vits_w) | 0x40000000) # define u3h_noun_be_warm(sot) ((sot) | 0x40000000) # define u3h_noun_be_cold(sot) ((sot) & ~0x40000000) # define u3h_slot_to_noun(sot) (0x40000000 | (sot)) diff --git a/pkg/noun/manage.c b/pkg/noun/manage.c index 283c6ecb17..7416d625bb 100644 --- a/pkg/noun/manage.c +++ b/pkg/noun/manage.c @@ -488,7 +488,7 @@ _pave_parts(void) static u3_road* _pave_road(c3_w* rut_w, c3_w* mat_w, c3_w* cap_w, c3_w siz_w) { - c3_dessert(((uintptr_t)rut_w & u3a_balign-1) == 0); + c3_dessert(((uintptr_t)rut_w & u3C.balign_d-1) == 0); u3_road* rod_u = (void*) mat_w; // enable in case of corruption @@ -529,8 +529,8 @@ _pave_north(c3_w* mem_w, c3_w siz_w, c3_w len_w) // 00~~~|R|---|H|######|C|+++|M|~~~FF // ^--u3R which _pave_road returns (u3H for home road) // - c3_w* mat_w = c3_align(mem_w + len_w - siz_w, u3a_balign, ALLO); - c3_w* rut_w = c3_align(mem_w, u3a_balign, ALHI); + c3_w* mat_w = c3_align(mem_w + len_w - siz_w, u3C.balign_d, ALLO); + c3_w* rut_w = c3_align(mem_w, u3C.balign_d, ALHI); c3_w* cap_w = mat_w; return _pave_road(rut_w, mat_w, cap_w, siz_w); @@ -555,8 +555,8 @@ _pave_south(c3_w* mem_w, c3_w siz_w, c3_w len_w) // // 00~~~|M|+++|C|######|H|---|R|~~~FFF // ^---u3R which _pave_road returns - c3_w* mat_w = c3_align(mem_w, u3a_balign, ALHI); - c3_w* rut_w = c3_align(mem_w + len_w, u3a_balign, ALLO); + c3_w* mat_w = c3_align(mem_w, u3C.balign_d, ALHI); + c3_w* rut_w = c3_align(mem_w + len_w, u3C.balign_d, ALLO); c3_w* cap_w = mat_w + siz_w; return _pave_road(rut_w, mat_w, cap_w, siz_w); @@ -567,9 +567,12 @@ _pave_south(c3_w* mem_w, c3_w siz_w, c3_w len_w) static void _pave_home(void) { - c3_w* mem_w = u3_Loom + u3a_walign; + /* a pristine home road will always have compressed references */ + u3a_config_loom(/* U3V_LATEST */ 2); + + c3_w* mem_w = u3_Loom + u3C.walign_w; c3_w siz_w = c3_wiseof(u3v_home); - c3_w len_w = u3C.wor_i - u3a_walign; + c3_w len_w = u3C.wor_i - u3C.walign_w; u3H = (void *)_pave_north(mem_w, siz_w, len_w); u3H->ver_w = u3v_version; @@ -586,34 +589,34 @@ STATIC_ASSERT( ((c3_wiseof(u3v_home) * 4) == sizeof(u3v_home)), static void _find_home(void) { + c3_w ver_w = *(u3_Loom + u3C.wor_i - 1); + u3a_config_loom(ver_w); + // NB: the home road is always north // - c3_w* mem_w = u3_Loom + u3a_walign; + c3_w* mem_w = u3_Loom + u3C.walign_w; c3_w siz_w = c3_wiseof(u3v_home); - c3_w len_w = u3C.wor_i - u3a_walign; - c3_w* mat_w; + c3_w len_w = u3C.wor_i - u3C.walign_w; + c3_w* mat_w = c3_align(mem_w + len_w - siz_w, u3C.balign_d, ALLO); - { - c3_w ver_w = *((mem_w + len_w) - 1); - - if ( u3v_version != ver_w ) { - fprintf(stderr, "loom: checkpoint version mismatch: " - "have %u, need %u\r\n", - ver_w, - u3v_version); - abort(); - } - } - - mat_w = c3_align(mem_w + len_w - siz_w, u3a_balign, ALLO); u3H = (void *)mat_w; u3R = &u3H->rod_u; - // this looks risky, but there are no legitimate scenarios - // where it's wrong - // + // this looks risky, but there are no legitimate scenarios where it's wrong u3R->cap_p = u3R->mat_p = u3C.wor_i - c3_wiseof(*u3H); + if (u3v_version > ver_w) { + u3m_migrate(u3v_version); + u3a_config_loom(u3v_version); + } + else if ( u3v_version < ver_w ) { + fprintf(stderr, "loom: checkpoint version mismatch: " + "have %u, need %u\r\n", + ver_w, + u3v_version); + abort(); + } + _rod_vaal(u3R); } @@ -825,7 +828,7 @@ u3m_leap(c3_w pad_w) } pad_w += c3_wiseof(u3a_road); len_w = u3a_open(u3R) - pad_w; - c3_align(len_w, u3a_walign, ALHI); + c3_align(len_w, u3C.walign_w, ALHI); } /* Allocate a region on the cap. @@ -2008,3 +2011,155 @@ u3m_pack(void) return (u3a_open(u3R) - pre_w); } + +static void +_migrate_reclaim() +{ + fprintf(stderr, "loom: migration reclaim\r\n"); + u3m_reclaim(); +} + +static void +_migrate_seek(const u3a_road *rod_u) +{ + /* + very much like u3a_pack_seek with the following changes: + - there is no need to account for free space as |pack is performed before + the migration + - odd sized boxes will be padded by one word to achieve an even size + - rut will be moved from one word ahead of u3_Loom to two words ahead + */ + c3_w * box_w = u3a_into(rod_u->rut_p); + c3_w * end_w = u3a_into(rod_u->hat_p); + u3_post new_p = (rod_u->rut_p + 1 + c3_wiseof(u3a_box)); + u3a_box * box_u = (void *)box_w; + + fprintf(stderr, "loom: migration seek\r\n"); + + for (; box_w < end_w + ; box_w += box_u->siz_w + , box_u = (void*)box_w) + { + if (!box_u->use_w) + continue; + c3_assert(box_u->siz_w); + c3_assert(box_u->use_w); + box_w[box_u->siz_w - 1] = new_p; + new_p = c3_align(new_p + box_u->siz_w, 2, ALHI); + } +} + +static void +_migrate_rewrite() +{ + fprintf(stderr, "loom: migration rewrite\r\n"); + + /* So that rewritten pointers are compressed, this flag is set */ + u3C.migration_state = MIG_REWRITE_COMPRESSED; + _cm_pack_rewrite(); + u3C.migration_state = MIG_NONE; +} + +static void +_migrate_move(u3a_road *rod_u) +{ + fprintf(stderr, "loom: migration move\r\n"); + + c3_z hiz_z = u3a_heap(rod_u) * sizeof(c3_w); + + /* calculate required shift distance to prevent write head overlapping read head */ + c3_w off_w = 1; /* at least 1 word because u3R->rut_p migrates from 1 to 2 */ + for (u3a_box *box_u = u3a_into(rod_u->rut_p) + ; (void *)box_u < u3a_into(rod_u->hat_p) + ; box_u = (void *)((c3_w *)box_u + box_u->siz_w)) + off_w += box_u->siz_w & 1; /* odd-sized boxes are padded by one word */ + + /* shift */ + memmove(u3a_into(u3H->rod_u.rut_p + off_w), + u3a_into(u3H->rod_u.rut_p), + hiz_z); + /* manually zero the former rut */ + *(c3_w *)u3a_into(rod_u->rut_p) = 0; + + /* relocate boxes to DWORD-aligned addresses stored in trailing size word */ + c3_w *box_w = u3a_into(rod_u->rut_p + off_w); + c3_w *end_w = u3a_into(rod_u->hat_p + off_w); + u3a_box *old_u = (void *)box_w; + c3_w siz_w = old_u->siz_w; + u3p(c3_w) new_p = rod_u->rut_p + 1 + c3_wiseof(u3a_box); + c3_w *new_w; + + for (; box_w < end_w + ; box_w += siz_w + , old_u = (void *)box_w + , siz_w = old_u->siz_w) { + old_u->use_w &= 0x7fffffff; + + if (!old_u->use_w) + continue; + + new_w = (void *)u3a_botox(u3a_into(new_p)); + c3_assert(box_w[siz_w - 1] == new_p); + c3_assert(new_w <= box_w); + + c3_w i_w; + for (i_w = 0; i_w < siz_w - 1; i_w++) + new_w[i_w] = box_w[i_w]; + + if (siz_w & 1) { + new_w[i_w++] = 0; /* pad odd sized boxes */ + new_w[i_w++] = siz_w + 1; /* restore trailing size word */ + new_w[0] = siz_w + 1; /* and the leading size word */ + } + else { + new_w[i_w++] = siz_w; + } + + new_p += i_w; + } + + /* restore proper heap state */ + rod_u->rut_p = 2; + rod_u->hat_p = new_p - c3_wiseof(u3a_box); + + /* like |pack, clear the free lists and cell allocator */ + for (c3_w i_w = 0; i_w < u3a_fbox_no; i_w++) + u3R->all.fre_p[i_w] = 0; + + u3R->all.fre_w = 0; + u3R->all.cel_p = 0; +} + + +/* u3m_migrate: perform loom migration if necessary. + ver_w - target version +*/ +void +u3m_migrate(c3_w ver_w) +{ + if (u3H->ver_w == ver_w) + return; + + /* 1 -> 2 is all that is currently supported */ + c3_dessert(u3H->ver_w == 1 && + ver_w == 2); + /* only home road migration is supported */ + c3_dessert((uintptr_t)u3H == (uintptr_t)u3R); + + fprintf(stderr, "loom: migration running. This may take several minutes to perform\r\n"); + fprintf(stderr, "loom: have version: %" PRIc3_w " migrating to version: %" PRIc3_w "\r\n", + u3H->ver_w, ver_w); + + /* packing first simplifies migration logic and minimizes required buffer space */ + u3m_pack(); + + /* perform the migration in a pattern similar to |pack */ + _migrate_reclaim(); + _migrate_seek(&u3H->rod_u); + _migrate_rewrite(); + _migrate_move(&u3H->rod_u); + + /* finally update the version and commit to disk */ + u3H->ver_w = ver_w; + u3e_save(); +} diff --git a/pkg/noun/manage.h b/pkg/noun/manage.h index 06d5138003..271539f6bd 100644 --- a/pkg/noun/manage.h +++ b/pkg/noun/manage.h @@ -159,4 +159,10 @@ c3_w u3m_pack(void); + /* u3m_migrate: perform loom migration if necessary. + ver_w - target version + */ + void + u3m_migrate(c3_w ver_w); + #endif /* ifndef U3_MANAGE_H */ diff --git a/pkg/noun/options.h b/pkg/noun/options.h index f58918537b..475ad4b1f7 100644 --- a/pkg/noun/options.h +++ b/pkg/noun/options.h @@ -14,6 +14,14 @@ u3_noun who; // single identity c3_c* dir_c; // execution directory (pier) c3_w wag_w; // flags (both ways) + c3_w vits_w; // number of virtual bits in reference + c3_w walign_w; // word alignment + c3_d balign_d; // byte alignment + enum { + MIG_NONE, + MIG_REWRITE_COMPRESSED, + } migration_state; + size_t wor_i; // loom word-length (<= u3a_words) void (*stderr_log_f)(c3_c*); // errors from c code void (*slog_f)(u3_noun); // function pointer for slog @@ -45,5 +53,4 @@ extern u3o_config u3o_Config; # define u3C u3o_Config - #endif /* ifndef U3_OPTIONS_H */ diff --git a/pkg/noun/vortex.h b/pkg/noun/vortex.h index 87c185a93f..0e552c49f2 100644 --- a/pkg/noun/vortex.h +++ b/pkg/noun/vortex.h @@ -37,7 +37,17 @@ /** Constants. **/ -# define u3v_version 1 + /* + version change log: + 1 -> 2: + - 1 bit pointer compression to enable 8G loom + */ + +/* ;;: TODO: refactor so that this is possible -- dependency loop if used in options.h */ +/* # define U3V_VER1 1 */ +/* # define U3V_VER2 2 */ +/* # define u3v_version U3V_VER2 */ +# define u3v_version 2 /** Functions. **/ From 98ef6582f677ca4be7051b13985a08193ae63404 Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 18/26] paren wrap road argument in road macros u3a_open, u3a_full, etc --- pkg/noun/allocate.h | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/pkg/noun/allocate.h b/pkg/noun/allocate.h index 969e22879a..833699bb96 100644 --- a/pkg/noun/allocate.h +++ b/pkg/noun/allocate.h @@ -256,56 +256,56 @@ /* u3a_is_north(): yes if road [r] is north road. */ -# define u3a_is_north(r) __(r->cap_p > r->hat_p) +# define u3a_is_north(r) __((r)->cap_p > (r)->hat_p) /* u3a_is_south(): yes if road [r] is south road. */ -# define u3a_is_south(r) !u3a_is_north(r) +# define u3a_is_south(r) !u3a_is_north((r)) /* u3a_open(): words of contiguous free space in road [r] */ # define u3a_open(r) ( (c3y == u3a_is_north(r)) \ - ? (c3_w)(r->cap_p - r->hat_p) \ - : (c3_w)(r->hat_p - r->cap_p) ) + ? (c3_w)((r)->cap_p - (r)->hat_p) \ + : (c3_w)((r)->hat_p - (r)->cap_p) ) /* u3a_full(): total words in road [r]; ** u3a_full(r) == u3a_heap(r) + u3a_temp(r) + u3a_open(r) */ # define u3a_full(r) ( (c3y == u3a_is_north(r)) \ - ? (c3_w)(r->mat_p - r->rut_p) \ - : (c3_w)(r->rut_p - r->mat_p) ) + ? (c3_w)((r)->mat_p - (r)->rut_p) \ + : (c3_w)((r)->rut_p - (r)->mat_p) ) /* u3a_heap(): words of heap in road [r] */ # define u3a_heap(r) ( (c3y == u3a_is_north(r)) \ - ? (c3_w)(r->hat_p - r->rut_p) \ - : (c3_w)(r->rut_p - r->hat_p) ) + ? (c3_w)((r)->hat_p - (r)->rut_p) \ + : (c3_w)((r)->rut_p - (r)->hat_p) ) /* u3a_temp(): words of stack in road [r] */ # define u3a_temp(r) ( (c3y == u3a_is_north(r)) \ - ? (c3_w)(r->mat_p - r->cap_p) \ - : (c3_w)(r->cap_p - r->mat_p) ) + ? (c3_w)((r)->mat_p - (r)->cap_p) \ + : (c3_w)((r)->cap_p - (r)->mat_p) ) # define u3a_north_is_senior(r, dog) \ - __((u3a_to_off(dog) < r->rut_p) || \ - (u3a_to_off(dog) >= r->mat_p)) + __((u3a_to_off(dog) < (r)->rut_p) || \ + (u3a_to_off(dog) >= (r)->mat_p)) # define u3a_north_is_junior(r, dog) \ - __((u3a_to_off(dog) >= r->cap_p) && \ - (u3a_to_off(dog) < r->mat_p)) + __((u3a_to_off(dog) >= (r)->cap_p) && \ + (u3a_to_off(dog) < (r)->mat_p)) # define u3a_north_is_normal(r, dog) \ c3a(!(u3a_north_is_senior(r, dog)), \ !(u3a_north_is_junior(r, dog))) # define u3a_south_is_senior(r, dog) \ - __((u3a_to_off(dog) < r->mat_p) || \ - (u3a_to_off(dog) >= r->rut_p)) + __((u3a_to_off(dog) < (r)->mat_p) || \ + (u3a_to_off(dog) >= (r)->rut_p)) # define u3a_south_is_junior(r, dog) \ - __((u3a_to_off(dog) < r->cap_p) && \ - (u3a_to_off(dog) >= r->mat_p)) + __((u3a_to_off(dog) < (r)->cap_p) && \ + (u3a_to_off(dog) >= (r)->mat_p)) # define u3a_south_is_normal(r, dog) \ c3a(!(u3a_south_is_senior(r, dog)), \ From ef2c4bba4dfbaf94b9957d8eeaaf4fbeace06cc3 Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 19/26] introduce vere/version.h version numbers - currently for u3e and u3v - should be kept in their own header to avoid dependency loops since anything should be able to source these. I would like to avoid literal comparison like: if (ver_w == 2) { } and instead opt for if (ver_w == U3V_VER2) { } or if (ver_w == U3V_LATEST) { } Though this may seem overkill at first given the only version we've incremented is u3H->ver_w, this is the simplest solution to avoid dependency loops --- pkg/noun/allocate.h | 4 ++-- pkg/noun/events.c | 6 +++--- pkg/noun/events.h | 12 ++++++------ pkg/noun/manage.c | 25 +++++++++++++------------ pkg/noun/manage.h | 3 ++- pkg/noun/version.h | 22 ++++++++++++++++++++++ pkg/noun/vortex.h | 19 +++++-------------- 7 files changed, 53 insertions(+), 38 deletions(-) create mode 100644 pkg/noun/version.h diff --git a/pkg/noun/allocate.h b/pkg/noun/allocate.h index 833699bb96..6db6ae93a0 100644 --- a/pkg/noun/allocate.h +++ b/pkg/noun/allocate.h @@ -379,10 +379,10 @@ */ inline void u3a_config_loom(c3_w ver_w) { switch (ver_w) { - case /* U3V_VER1 */ 1: + case U3V_VER1: u3C.vits_w = 0; break; - case /* U3V_VER2 */ 2: + case U3V_VER2: u3C.vits_w = 1; break; default: diff --git a/pkg/noun/events.c b/pkg/noun/events.c index 03774353ef..cfd18c092f 100644 --- a/pkg/noun/events.c +++ b/pkg/noun/events.c @@ -464,10 +464,10 @@ _ce_patch_verify(u3_ce_patch* pat_u) c3_w mem_w[pag_wiz_i]; c3_zs ret_zs; - if ( u3e_version != pat_u->con_u->ver_w ) { + if ( U3E_VERLAT != pat_u->con_u->ver_w ) { fprintf(stderr, "loom: patch version mismatch: have %"PRIc3_w", need %u\r\n", pat_u->con_u->ver_w, - u3e_version); + U3E_VERLAT); return c3n; } @@ -692,7 +692,7 @@ _ce_patch_compose(void) _ce_patch_create(pat_u); pat_u->con_u = c3_malloc(sizeof(u3e_control) + (pgs_w * sizeof(u3e_line))); - pat_u->con_u->ver_w = u3e_version; + pat_u->con_u->ver_w = U3E_VERLAT; pgc_w = 0; for ( i_w = 0; i_w < nor_w; i_w++ ) { diff --git a/pkg/noun/events.h b/pkg/noun/events.h index d7345799c2..b4c78fe364 100644 --- a/pkg/noun/events.h +++ b/pkg/noun/events.h @@ -5,6 +5,7 @@ #include "c3.h" #include "allocate.h" +#include "version.h" /** Data structures. **/ @@ -18,11 +19,11 @@ /* u3e_control: memory change, control file. */ typedef struct _u3e_control { - c3_w ver_w; // version number - c3_w nor_w; // new page count north - c3_w sou_w; // new page count south - c3_w pgs_w; // number of changed pages - u3e_line mem_u[0]; // per page + u3e_version ver_w; // version number + c3_w nor_w; // new page count north + c3_w sou_w; // new page count south + c3_w pgs_w; // number of changed pages + u3e_line mem_u[0]; // per page } u3e_control; /* u3_cs_patch: memory change, top level. @@ -60,7 +61,6 @@ /** Constants. **/ -# define u3e_version 1 /** Functions. **/ diff --git a/pkg/noun/manage.c b/pkg/noun/manage.c index 7416d625bb..beec6f6d92 100644 --- a/pkg/noun/manage.c +++ b/pkg/noun/manage.c @@ -568,14 +568,14 @@ static void _pave_home(void) { /* a pristine home road will always have compressed references */ - u3a_config_loom(/* U3V_LATEST */ 2); + u3a_config_loom(U3V_VERLAT); c3_w* mem_w = u3_Loom + u3C.walign_w; c3_w siz_w = c3_wiseof(u3v_home); c3_w len_w = u3C.wor_i - u3C.walign_w; u3H = (void *)_pave_north(mem_w, siz_w, len_w); - u3H->ver_w = u3v_version; + u3H->ver_w = U3V_VERLAT; u3R = &u3H->rod_u; _pave_parts(); @@ -605,15 +605,15 @@ _find_home(void) // this looks risky, but there are no legitimate scenarios where it's wrong u3R->cap_p = u3R->mat_p = u3C.wor_i - c3_wiseof(*u3H); - if (u3v_version > ver_w) { - u3m_migrate(u3v_version); - u3a_config_loom(u3v_version); + if (U3V_VERLAT > ver_w) { + u3m_migrate(U3V_VERLAT); + u3a_config_loom(U3V_VERLAT); } - else if ( u3v_version < ver_w ) { + else if ( U3V_VERLAT < ver_w ) { fprintf(stderr, "loom: checkpoint version mismatch: " "have %u, need %u\r\n", ver_w, - u3v_version); + U3V_VERLAT); abort(); } @@ -2135,19 +2135,20 @@ _migrate_move(u3a_road *rod_u) ver_w - target version */ void -u3m_migrate(c3_w ver_w) +u3m_migrate(u3v_version ver_w) { if (u3H->ver_w == ver_w) return; /* 1 -> 2 is all that is currently supported */ - c3_dessert(u3H->ver_w == 1 && - ver_w == 2); + c3_dessert(u3H->ver_w == U3V_VER1 && + ver_w == U3V_VER2); + /* only home road migration is supported */ c3_dessert((uintptr_t)u3H == (uintptr_t)u3R); - fprintf(stderr, "loom: migration running. This may take several minutes to perform\r\n"); - fprintf(stderr, "loom: have version: %" PRIc3_w " migrating to version: %" PRIc3_w "\r\n", + fprintf(stderr, "loom: migration running. This may take several minutes to perform.\r\n"); + fprintf(stderr, "loom: have version: %"PRIc3_w" migrating to version: %"PRIc3_w"\r\n", u3H->ver_w, ver_w); /* packing first simplifies migration logic and minimizes required buffer space */ diff --git a/pkg/noun/manage.h b/pkg/noun/manage.h index 271539f6bd..539d45ca7c 100644 --- a/pkg/noun/manage.h +++ b/pkg/noun/manage.h @@ -5,6 +5,7 @@ #include "c3.h" #include "types.h" +#include "version.h" /** System management. **/ @@ -163,6 +164,6 @@ ver_w - target version */ void - u3m_migrate(c3_w ver_w); + u3m_migrate(u3v_version ver_w); #endif /* ifndef U3_MANAGE_H */ diff --git a/pkg/noun/version.h b/pkg/noun/version.h new file mode 100644 index 0000000000..9c55b8b06e --- /dev/null +++ b/pkg/noun/version.h @@ -0,0 +1,22 @@ +#ifndef U3_VERSION_H +#define U3_VERSION_H + +/* VORTEX + */ + +typedef enum u3v_version { + U3V_VER1 = 1, + /* 1 -> 2: 1 bit pointer compression to enable 8G loom */ + U3V_VER2 = 2, + U3V_VERLAT = U3V_VER2, +} u3v_version; + +/* EVENTS + */ + +typedef enum u3e_version { + U3E_VER1 = 1, + U3E_VERLAT = U3E_VER1, +} u3e_version; + +#endif /* ifndef U3_VERSION_H */ diff --git a/pkg/noun/vortex.h b/pkg/noun/vortex.h index 0e552c49f2..350f65816d 100644 --- a/pkg/noun/vortex.h +++ b/pkg/noun/vortex.h @@ -3,8 +3,10 @@ #ifndef U3_VORTEX_H #define U3_VORTEX_H +#include "allocate.h" #include "c3.h" #include "imprison.h" +#include "version.h" /** Data structures. **/ @@ -22,9 +24,9 @@ ** NB: version must be last for discriminability in north road */ typedef struct _u3v_home { - u3a_road rod_u; // storage state - u3v_arvo arv_u; // arvo state - c3_w ver_w; // version number + u3a_road rod_u; // storage state + u3v_arvo arv_u; // arvo state + u3v_version ver_w; // version number } u3v_home; @@ -37,17 +39,6 @@ /** Constants. **/ - /* - version change log: - 1 -> 2: - - 1 bit pointer compression to enable 8G loom - */ - -/* ;;: TODO: refactor so that this is possible -- dependency loop if used in options.h */ -/* # define U3V_VER1 1 */ -/* # define U3V_VER2 2 */ -/* # define u3v_version U3V_VER2 */ -# define u3v_version 2 /** Functions. **/ From be4b92b38b40be0532986a4c97f3aef66b38c388 Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 20/26] cenums are dumb --- pkg/noun/version.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/pkg/noun/version.h b/pkg/noun/version.h index 9c55b8b06e..f64d0a398e 100644 --- a/pkg/noun/version.h +++ b/pkg/noun/version.h @@ -4,19 +4,18 @@ /* VORTEX */ -typedef enum u3v_version { - U3V_VER1 = 1, - /* 1 -> 2: 1 bit pointer compression to enable 8G loom */ - U3V_VER2 = 2, - U3V_VERLAT = U3V_VER2, -} u3v_version; +typedef c3_w u3v_version; + +#define U3V_VER1 1 +#define U3V_VER2 2 +#define U3V_VERLAT U3V_VER2 /* EVENTS */ -typedef enum u3e_version { - U3E_VER1 = 1, - U3E_VERLAT = U3E_VER1, -} u3e_version; +typedef c3_w u3e_version; + +#define U3E_VER1 1 +#define U3E_VERLAT U3E_VER1 #endif /* ifndef U3_VERSION_H */ From 45217c3409921646b5085e1bff7b8a8a36cffa9d Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 21/26] factor out _me_align_(pad|dap) and all instances of alp_w This drastically simplifies the bizarre (ald_w, alp_w) alignment logic which also seems to have been the cause of issues with heap corruption originating in handling of internal 16 byte alignment by _ca_box_make_hat --- pkg/noun/allocate.c | 83 ++++++++++++++------------------------------- 1 file changed, 25 insertions(+), 58 deletions(-) diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index 2928bbb95a..783db38809 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -288,38 +288,10 @@ _box_free(u3a_box* box_u) } /* end south */ } -/* _me_align_pad(): pad to first point after pos_p aligned at (ald_w, alp_w). -*/ -static __inline__ c3_w -_me_align_pad(u3_post pos_p, c3_w ald_w, c3_w alp_w) -{ - c3_w adj_w = (ald_w - (alp_w + 1)); - c3_p off_p = (pos_p + adj_w); - c3_p orp_p = off_p &~ (ald_w - 1); - c3_p fin_p = orp_p + alp_w; - c3_w pad_w = (fin_p - pos_p); - - return pad_w; -} - -/* _me_align_dap(): pad to last point before pos_p aligned at (ald_w, alp_w). -*/ -static __inline__ c3_w -_me_align_dap(u3_post pos_p, c3_w ald_w, c3_w alp_w) -{ - c3_w adj_w = alp_w; - c3_p off_p = (pos_p - adj_w); - c3_p orp_p = (off_p &~ (ald_w - 1)); - c3_p fin_p = orp_p + alp_w; - c3_w pad_w = (pos_p - fin_p); - - return pad_w; -} - /* _ca_box_make_hat(): in u3R, allocate directly on the hat. */ static u3a_box* -_ca_box_make_hat(c3_w len_w, c3_w ald_w, c3_w alp_w, c3_w use_w) +_ca_box_make_hat(c3_w len_w, c3_w ald_w, c3_w use_w) { c3_w pad_w, siz_w; u3_post all_p; @@ -327,7 +299,7 @@ _ca_box_make_hat(c3_w len_w, c3_w ald_w, c3_w alp_w, c3_w use_w) if ( c3y == u3a_is_north(u3R) ) { all_p = u3R->hat_p; pad_w = c3_align(all_p, ald_w, ALHI) - all_p; - siz_w = c3_align(len_w + pad_w, u3C.walign_w, ALHI); + siz_w = c3_align(len_w + pad_w , u3C.walign_w, ALHI); // hand-inlined: siz_w >= u3a_open(u3R) // @@ -463,16 +435,22 @@ _ca_reclaim_half(void) #endif } -/* _ca_willoc(): u3a_walloc() internals. +/* _ca_willoc(): u3a_walloc() internals. void* guaranteed to be DWORD aligned. + + - len_w: requested size of allocation + + - ald_w: desired alignment. Note, _ca_willoc does NOT guarantee the void* + returned is aligned on ald_w, only that the allocated size is sufficient to + internally align on ald_w. Although this can be arbitrarily defined, when + not 1, it is typically 4, i.e. 16 bytes, so that u3a_malloc is POSIX malloc + compatible */ static void* -_ca_willoc(c3_w len_w, c3_w ald_w, c3_w alp_w) +_ca_willoc(c3_w len_w, c3_w ald_w) { c3_w siz_w = c3_max(u3a_minimum, u3a_boxed(len_w)); c3_w sel_w = _box_slot(siz_w); - alp_w = (alp_w + c3_wiseof(u3a_box)) % ald_w; - /* XX: this logic is totally bizarre, but preserve it. ** ** This means we use the next size bigger instead of the "correct" @@ -508,7 +486,7 @@ _ca_willoc(c3_w len_w, c3_w ald_w, c3_w alp_w) // memory nearly empty; reclaim; should not be needed // // if ( (u3a_open(u3R) + u3R->all.fre_w) < 65536 ) { _ca_reclaim_half(); } - box_u = _ca_box_make_hat(siz_w, ald_w, alp_w, 1); + box_u = _ca_box_make_hat(siz_w, ald_w, 1); /* Flush a bunch of cell cache, then try again. */ @@ -516,21 +494,20 @@ _ca_willoc(c3_w len_w, c3_w ald_w, c3_w alp_w) if ( u3R->all.cel_p ) { u3a_reflux(); - return _ca_willoc(len_w, ald_w, alp_w); + return _ca_willoc(len_w, ald_w); } else { _ca_reclaim_half(); - return _ca_willoc(len_w, ald_w, alp_w); + return _ca_willoc(len_w, ald_w); } } else return u3a_boxto(box_u); } } else { /* we got a non-null freelist */ - c3_w pad_w = _me_align_pad(*pfr_p, ald_w, alp_w); + c3_w pad_w = c3_align(*pfr_p, ald_w, ALHI) - *pfr_p; c3_w des_w = c3_align(siz_w + pad_w, u3C.walign_w, ALHI); - - if ( 1 == ald_w ) c3_assert(0 == pad_w); + c3_dessert((ald_w != 1) || (0 == pad_w)); if ( (des_w) > u3to(u3a_fbox, *pfr_p)->box_u.siz_w ) { /* This free block is too small. Continue searching. @@ -609,7 +586,7 @@ _ca_willoc(c3_w len_w, c3_w ald_w, c3_w alp_w) /* _ca_walloc(): u3a_walloc() internals. */ static void* -_ca_walloc(c3_w len_w, c3_w ald_w, c3_w alp_w) +_ca_walloc(c3_w len_w, c3_w ald_w) { void* ptr_v; c3_w req_w; /* allocation request length */ @@ -630,7 +607,7 @@ _ca_walloc(c3_w len_w, c3_w ald_w, c3_w alp_w) & ~(u3C.walign_w - 1) - (c3_wiseof(u3a_box) + 1); for (;;) { - ptr_v = _ca_willoc(req_w, ald_w, alp_w); + ptr_v = _ca_willoc(req_w, ald_w); if ( 0 != ptr_v ) { break; } @@ -647,7 +624,7 @@ u3a_walloc(c3_w len_w) { void* ptr_v; - ptr_v = _ca_walloc(len_w, 1, 0); + ptr_v = _ca_walloc(len_w, 1); #if 0 if ( (703 == u3_Code) && @@ -785,22 +762,12 @@ void* u3a_malloc(size_t len_i) { c3_w len_w = (c3_w)((len_i + 3) >> 2); - c3_w* ptr_w = _ca_walloc(len_w + 1, 4, 3); - u3_post ptr_p = u3a_outa(ptr_w); - c3_w pad_w = _me_align_pad(ptr_p, 4, 3); - c3_w* out_w = u3a_into(ptr_p + pad_w + 1); - -#if 0 - if ( u3a_botox(out_w) == (u3a_box*)(void *)0x3bdd1c80) { - static int xuc_i = 0; - - u3l_log("xuc_i %d", xuc_i); - // if ( 1 == xuc_i ) { abort(); } - xuc_i++; - } -#endif - out_w[-1] = pad_w; + c3_w* ptr_w = _ca_walloc(len_w + 1, 4); /* +1 for storing pad */ + c3_w* out_w = c3_align(ptr_w + 1, 16, ALHI); + c3_w pad_w = out_w - ptr_w; + c3_dessert(pad_w <= 4); + out_w[-1] = pad_w - 1; /* -1 for historical reasons */ return out_w; } From c71060be84035f8567d198166bc8c86caf9c603f Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 22/26] (ALLO, ALHI) -> (C3_ALGHI, C3_ALGLO) --- pkg/c3/defs.h | 8 ++++---- pkg/noun/allocate.c | 16 ++++++++-------- pkg/noun/manage.c | 14 +++++++------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/pkg/c3/defs.h b/pkg/c3/defs.h index 0a4948b484..81f7b61120 100644 --- a/pkg/c3/defs.h +++ b/pkg/c3/defs.h @@ -196,17 +196,17 @@ c3_d : c3_align_d, \ default : c3_align_p) \ (x, al, hilo) -typedef enum { ALHI=1, ALLO=0 } align_dir; +typedef enum { C3_ALGHI=1, C3_ALGLO=0 } align_dir; inline c3_w c3_align_w(c3_w x, c3_w al, align_dir hilo) { - c3_dessert(hilo <= ALHI && hilo >= ALLO); + c3_dessert(hilo <= C3_ALGHI && hilo >= C3_ALGLO); x += hilo * (al - 1); x &= ~(al - 1); return x; } inline c3_d c3_align_d(c3_d x, c3_d al, align_dir hilo) { - c3_dessert(hilo <= ALHI && hilo >= ALLO); + c3_dessert(hilo <= C3_ALGHI && hilo >= C3_ALGLO); x += hilo * (al - 1); x &= ~(al - 1); return x; @@ -214,7 +214,7 @@ c3_align_d(c3_d x, c3_d al, align_dir hilo) { inline void* c3_align_p(void const * p, size_t al, align_dir hilo) { uintptr_t x = (uintptr_t)p; - c3_dessert(hilo <= ALHI && hilo >= ALLO); + c3_dessert(hilo <= C3_ALGHI && hilo >= C3_ALGLO); x += hilo * (al - 1); x &= ~(al - 1); return (void*)x; diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index 783db38809..17a178af59 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -298,8 +298,8 @@ _ca_box_make_hat(c3_w len_w, c3_w ald_w, c3_w use_w) if ( c3y == u3a_is_north(u3R) ) { all_p = u3R->hat_p; - pad_w = c3_align(all_p, ald_w, ALHI) - all_p; - siz_w = c3_align(len_w + pad_w , u3C.walign_w, ALHI); + pad_w = c3_align(all_p, ald_w, C3_ALGHI) - all_p; + siz_w = c3_align(len_w + pad_w, u3C.walign_w, C3_ALGHI); // hand-inlined: siz_w >= u3a_open(u3R) // @@ -310,8 +310,8 @@ _ca_box_make_hat(c3_w len_w, c3_w ald_w, c3_w use_w) } else { all_p = u3R->hat_p - len_w; - pad_w = all_p - c3_align(all_p, ald_w, ALLO); - siz_w = c3_align(len_w + pad_w, u3C.walign_w, ALHI); + pad_w = all_p - c3_align(all_p, ald_w, C3_ALGLO); + siz_w = c3_align(len_w + pad_w, u3C.walign_w, C3_ALGHI); // hand-inlined: siz_w >= u3a_open(u3R) // @@ -505,8 +505,8 @@ _ca_willoc(c3_w len_w, c3_w ald_w) } } else { /* we got a non-null freelist */ - c3_w pad_w = c3_align(*pfr_p, ald_w, ALHI) - *pfr_p; - c3_w des_w = c3_align(siz_w + pad_w, u3C.walign_w, ALHI); + c3_w pad_w = c3_align(*pfr_p, ald_w, C3_ALGHI) - *pfr_p; + c3_w des_w = c3_align(siz_w + pad_w, u3C.walign_w, C3_ALGHI); c3_dessert((ald_w != 1) || (0 == pad_w)); if ( (des_w) > u3to(u3a_fbox, *pfr_p)->box_u.siz_w ) { @@ -723,7 +723,7 @@ u3a_wtrim(void* tox_v, c3_w old_w, c3_w len_w) c3_w* end_w = c3_align(nov_w + len_w + 1, /* +1 for trailing allocation size */ u3C.balign_d, - ALHI); + C3_ALGHI); c3_w asz_w = (end_w - box_w); /* total size in words of new allocation */ if (box_u->siz_w <= asz_w) return; @@ -763,7 +763,7 @@ u3a_malloc(size_t len_i) { c3_w len_w = (c3_w)((len_i + 3) >> 2); c3_w* ptr_w = _ca_walloc(len_w + 1, 4); /* +1 for storing pad */ - c3_w* out_w = c3_align(ptr_w + 1, 16, ALHI); + c3_w* out_w = c3_align(ptr_w + 1, 16, C3_ALGHI); c3_w pad_w = out_w - ptr_w; c3_dessert(pad_w <= 4); diff --git a/pkg/noun/manage.c b/pkg/noun/manage.c index beec6f6d92..bbad863fe3 100644 --- a/pkg/noun/manage.c +++ b/pkg/noun/manage.c @@ -529,8 +529,8 @@ _pave_north(c3_w* mem_w, c3_w siz_w, c3_w len_w) // 00~~~|R|---|H|######|C|+++|M|~~~FF // ^--u3R which _pave_road returns (u3H for home road) // - c3_w* mat_w = c3_align(mem_w + len_w - siz_w, u3C.balign_d, ALLO); - c3_w* rut_w = c3_align(mem_w, u3C.balign_d, ALHI); + c3_w* mat_w = c3_align(mem_w + len_w - siz_w, u3C.balign_d, C3_ALGLO); + c3_w* rut_w = c3_align(mem_w, u3C.balign_d, C3_ALGHI); c3_w* cap_w = mat_w; return _pave_road(rut_w, mat_w, cap_w, siz_w); @@ -555,8 +555,8 @@ _pave_south(c3_w* mem_w, c3_w siz_w, c3_w len_w) // // 00~~~|M|+++|C|######|H|---|R|~~~FFF // ^---u3R which _pave_road returns - c3_w* mat_w = c3_align(mem_w, u3C.balign_d, ALHI); - c3_w* rut_w = c3_align(mem_w + len_w, u3C.balign_d, ALLO); + c3_w* mat_w = c3_align(mem_w, u3C.balign_d, C3_ALGHI); + c3_w* rut_w = c3_align(mem_w + len_w, u3C.balign_d, C3_ALGLO); c3_w* cap_w = mat_w + siz_w; return _pave_road(rut_w, mat_w, cap_w, siz_w); @@ -597,7 +597,7 @@ _find_home(void) c3_w* mem_w = u3_Loom + u3C.walign_w; c3_w siz_w = c3_wiseof(u3v_home); c3_w len_w = u3C.wor_i - u3C.walign_w; - c3_w* mat_w = c3_align(mem_w + len_w - siz_w, u3C.balign_d, ALLO); + c3_w* mat_w = c3_align(mem_w + len_w - siz_w, u3C.balign_d, C3_ALGLO); u3H = (void *)mat_w; u3R = &u3H->rod_u; @@ -828,7 +828,7 @@ u3m_leap(c3_w pad_w) } pad_w += c3_wiseof(u3a_road); len_w = u3a_open(u3R) - pad_w; - c3_align(len_w, u3C.walign_w, ALHI); + c3_align(len_w, u3C.walign_w, C3_ALGHI); } /* Allocate a region on the cap. @@ -2045,7 +2045,7 @@ _migrate_seek(const u3a_road *rod_u) c3_assert(box_u->siz_w); c3_assert(box_u->use_w); box_w[box_u->siz_w - 1] = new_p; - new_p = c3_align(new_p + box_u->siz_w, 2, ALHI); + new_p = c3_align(new_p + box_u->siz_w, 2, C3_ALGHI); } } From 953b21ae8261ba3e18aef2f6134dc0a256a65bc1 Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 23/26] fix U3_MEMORY_DEBUG corruption. Minimize required padding pad malloc internal pad calculations were largely responsible for the corruption. It happened to be the case that without U3_MEMORY_DEBUG set (which doubles the size of a `u3a_box`), we overallocated just enough memory for the pad miscalculation to not effect us. This fixes both the overallocation and the pad miscalculation. --- pkg/noun/allocate.c | 124 ++++++++++++++++++++++++-------------------- 1 file changed, 67 insertions(+), 57 deletions(-) diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index 17a178af59..af94e35cbc 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -70,12 +70,12 @@ _box_count(c3_ws siz_ws) { } _box_count, (others?) should have perhaps its own header and certainly its own prefix. having to remind yourself that _box_count doesn't actually do anything unless U3_CPU_DEBUG is defined is annoying. */ -#define _box_vaal(box_u) \ - do { \ - c3_dessert(((uintptr_t)u3a_boxto(box_u) \ - & u3C.balign_d-1) == 0); \ - c3_dessert((((u3a_box*)(box_u))->siz_w \ - & u3C.walign_w-1) == 0); \ +#define _box_vaal(box_u) \ + do { \ + c3_dessert(((uintptr_t)u3a_boxto(box_u) \ + & u3C.balign_d-1) == 0); \ + c3_dessert((((u3a_box*)(box_u))->siz_w \ + & u3C.walign_w-1) == 0); \ } while(0) /* _box_slot(): select the right free list to search for a block. @@ -275,7 +275,7 @@ _box_free(u3a_box* box_u) u3R->hat_p = u3a_outa(box_w + box_u->siz_w); } else { - c3_w laz_w = *(box_w - 1); + c3_w laz_w = box_w[-1]; u3a_box* pox_u = (u3a_box*)(void *)(box_w - laz_w); if ( 0 == pox_u->use_w ) { @@ -291,14 +291,20 @@ _box_free(u3a_box* box_u) /* _ca_box_make_hat(): in u3R, allocate directly on the hat. */ static u3a_box* -_ca_box_make_hat(c3_w len_w, c3_w ald_w, c3_w use_w) +_ca_box_make_hat(c3_w len_w, c3_w ald_w, c3_w off_w, c3_w use_w) { - c3_w pad_w, siz_w; - u3_post all_p; + c3_w + pad_w, /* padding between returned pointer and box */ + siz_w; /* total size of allocation */ + u3_post + box_p, /* start of box */ + all_p; /* start of returned pointer */ if ( c3y == u3a_is_north(u3R) ) { - all_p = u3R->hat_p; - pad_w = c3_align(all_p, ald_w, C3_ALGHI) - all_p; + box_p = all_p = u3R->hat_p; + all_p += c3_wiseof(u3a_box) + off_w; + pad_w = c3_align(all_p, ald_w, C3_ALGHI) + - all_p; siz_w = c3_align(len_w + pad_w, u3C.walign_w, C3_ALGHI); // hand-inlined: siz_w >= u3a_open(u3R) @@ -309,8 +315,10 @@ _ca_box_make_hat(c3_w len_w, c3_w ald_w, c3_w use_w) u3R->hat_p += siz_w; } else { - all_p = u3R->hat_p - len_w; - pad_w = all_p - c3_align(all_p, ald_w, C3_ALGLO); + box_p = all_p = u3R->hat_p - len_w; + all_p += c3_wiseof(u3a_box) + off_w; + pad_w = all_p + - c3_align(all_p, ald_w, C3_ALGLO); siz_w = c3_align(len_w + pad_w, u3C.walign_w, C3_ALGHI); // hand-inlined: siz_w >= u3a_open(u3R) @@ -318,10 +326,12 @@ _ca_box_make_hat(c3_w len_w, c3_w ald_w, c3_w use_w) if ( siz_w >= (u3R->hat_p - u3R->cap_p) ) { return 0; } - all_p = u3R->hat_p -= siz_w; + box_p = u3R->hat_p -= siz_w; } + c3_dessert(!(ald_w <= 2 && off_w == 0) || (0 == pad_w)); + c3_dessert(pad_w <= 4); - return _box_make(u3a_into(all_p), siz_w, use_w); + return _box_make(u3a_into(box_p), siz_w, use_w); } #if 0 @@ -435,18 +445,10 @@ _ca_reclaim_half(void) #endif } -/* _ca_willoc(): u3a_walloc() internals. void* guaranteed to be DWORD aligned. - - - len_w: requested size of allocation - - - ald_w: desired alignment. Note, _ca_willoc does NOT guarantee the void* - returned is aligned on ald_w, only that the allocated size is sufficient to - internally align on ald_w. Although this can be arbitrarily defined, when - not 1, it is typically 4, i.e. 16 bytes, so that u3a_malloc is POSIX malloc - compatible +/* _ca_willoc(): u3a_walloc() internals. */ static void* -_ca_willoc(c3_w len_w, c3_w ald_w) +_ca_willoc(c3_w len_w, c3_w ald_w, c3_w off_w) { c3_w siz_w = c3_max(u3a_minimum, u3a_boxed(len_w)); c3_w sel_w = _box_slot(siz_w); @@ -486,7 +488,7 @@ _ca_willoc(c3_w len_w, c3_w ald_w) // memory nearly empty; reclaim; should not be needed // // if ( (u3a_open(u3R) + u3R->all.fre_w) < 65536 ) { _ca_reclaim_half(); } - box_u = _ca_box_make_hat(siz_w, ald_w, 1); + box_u = _ca_box_make_hat(siz_w, ald_w, off_w, 1); /* Flush a bunch of cell cache, then try again. */ @@ -494,20 +496,27 @@ _ca_willoc(c3_w len_w, c3_w ald_w) if ( u3R->all.cel_p ) { u3a_reflux(); - return _ca_willoc(len_w, ald_w); + return _ca_willoc(len_w, ald_w, off_w); } else { _ca_reclaim_half(); - return _ca_willoc(len_w, ald_w); + return _ca_willoc(len_w, ald_w, off_w); } } else return u3a_boxto(box_u); } } else { /* we got a non-null freelist */ - c3_w pad_w = c3_align(*pfr_p, ald_w, C3_ALGHI) - *pfr_p; + u3_post box_p, all_p; + box_p = all_p = *pfr_p; + all_p += c3_wiseof(u3a_box) + off_w; + c3_w pad_w = c3_align(all_p, ald_w, C3_ALGHI) - all_p; c3_w des_w = c3_align(siz_w + pad_w, u3C.walign_w, C3_ALGHI); - c3_dessert((ald_w != 1) || (0 == pad_w)); + + /* calls maximally requesting DWORD alignment of returned pointer + shouldn't require padding. */ + c3_dessert(!(ald_w <= 2 && off_w == 0) || (0 == pad_w)); + c3_dessert(pad_w <= 4); if ( (des_w) > u3to(u3a_fbox, *pfr_p)->box_u.siz_w ) { /* This free block is too small. Continue searching. @@ -557,7 +566,7 @@ _ca_willoc(c3_w len_w, c3_w ald_w) */ /* XXX: Despite the fact that we're making a box here, we don't - actually have to ensure it's aligned, since siz_w and all boxes + actually have to ensure it's aligned, since des_w and all boxes already on the loom /are/ aligned. A debug break here implies that you broke those conditions, not that this needs to handle alignment. abandon hope. */ @@ -584,30 +593,22 @@ _ca_willoc(c3_w len_w, c3_w ald_w) } /* _ca_walloc(): u3a_walloc() internals. + + - len_w: allocation length in words + - ald_w: desired alignment. N.B. the void * returned is not guaranteed to be + aligned on this value. But the allocation will be sized such that the + caller can independently align the value. + - off_w: alignment offset to use when sizing request. + + void * returned guaranteed to be DWORD (8-byte) aligned. */ static void* -_ca_walloc(c3_w len_w, c3_w ald_w) +_ca_walloc(c3_w len_w, c3_w ald_w, c3_w off_w) { void* ptr_v; - c3_w req_w; /* allocation request length */ - /* N.B: This odd looking logic is to generalize correct allocation lengths - requested from _ca_willoc to alignments other than DWORD. For DWORD (8 - byte) aligned references, this is eq to `req_w = len_w | 1`; - - ie we request an odd allocation length because c3_wiseof(u3a_box) + 1 is 3 - and 3 + {1,3,5,...} % 2 == 0 - - This works only because when we strip off mem from the hat or from a larger - fbox, we don't strip off any more than what was requested (+ padding) - */ - req_w = len_w - + (c3_wiseof(u3a_box) + 1) - + u3C.walign_w - & ~(u3C.walign_w - 1) - - (c3_wiseof(u3a_box) + 1); for (;;) { - ptr_v = _ca_willoc(req_w, ald_w); + ptr_v = _ca_willoc(len_w, ald_w, off_w); if ( 0 != ptr_v ) { break; } @@ -624,7 +625,7 @@ u3a_walloc(c3_w len_w) { void* ptr_v; - ptr_v = _ca_walloc(len_w, 1); + ptr_v = _ca_walloc(len_w, 1, 0); #if 0 if ( (703 == u3_Code) && @@ -757,17 +758,26 @@ u3a_calloc(size_t num_i, size_t len_i) } /* u3a_malloc(): aligned storage measured in bytes. + + Internally pads allocations to 16-byte alignment independent of DWORD + alignment ensured for word sized allocations. + */ void* u3a_malloc(size_t len_i) { - c3_w len_w = (c3_w)((len_i + 3) >> 2); - c3_w* ptr_w = _ca_walloc(len_w + 1, 4); /* +1 for storing pad */ - c3_w* out_w = c3_align(ptr_w + 1, 16, C3_ALGHI); - c3_w pad_w = out_w - ptr_w; - c3_dessert(pad_w <= 4); + c3_w len_w = (c3_w)((len_i + 3) >> 2); + c3_w *ptr_w = _ca_walloc(len_w +1, 4, 1); /* +1 for word storing pad size */ + c3_w *out_w = c3_align(ptr_w + 1, 16, C3_ALGHI); + c3_w pad_w = u3a_outa(out_w) - u3a_outa(ptr_w); + + out_w[-1] = pad_w - 1; /* the size of the pad doesn't include the word storing the size (-1) */ + + c3_dessert(&out_w[len_w] /* alloced space after alignment is sufficient */ + <= &((c3_w*)u3a_botox(ptr_w))[u3a_botox(ptr_w)->siz_w]); + c3_dessert(pad_w <= 4 && pad_w > 0); + c3_dessert(&out_w[-1] > ptr_w); - out_w[-1] = pad_w - 1; /* -1 for historical reasons */ return out_w; } From ba1b0f1e3d83f0e6ac928d069c0b28c0a86dc786 Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 24/26] refactor alignment functions --- pkg/c3/BUILD.bazel | 5 ++++- pkg/c3/defs.c | 5 +++++ pkg/c3/defs.h | 10 ++++++++-- pkg/noun/allocate.c | 3 --- 4 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 pkg/c3/defs.c diff --git a/pkg/c3/BUILD.bazel b/pkg/c3/BUILD.bazel index ced7cf8a30..45df2368db 100644 --- a/pkg/c3/BUILD.bazel +++ b/pkg/c3/BUILD.bazel @@ -5,7 +5,10 @@ cc_library( name = "c3", srcs = glob( - ["*.h"], + [ + "*.h", + "*.c", + ], exclude = [ "c3.h", "*_tests.c", diff --git a/pkg/c3/defs.c b/pkg/c3/defs.c new file mode 100644 index 0000000000..ce968cdab3 --- /dev/null +++ b/pkg/c3/defs.c @@ -0,0 +1,5 @@ +#include "defs.h" + +c3_w c3_align_w(c3_w x, c3_w al, align_dir hilo); +c3_d c3_align_d(c3_d x, c3_d al, align_dir hilo); +void *c3_align_p(void const * p, size_t al, align_dir hilo); diff --git a/pkg/c3/defs.h b/pkg/c3/defs.h index 81f7b61120..3a31f67239 100644 --- a/pkg/c3/defs.h +++ b/pkg/c3/defs.h @@ -186,10 +186,16 @@ # define c3_rename(a, b) ({ \ rename(a, b);}) -/* c3_align: hi or lo align x to al +/* c3_align( + x - the address/quantity to align, + al - the alignment, + hilo - [C3_ALGHI, C3_ALGLO] high or low align + ) + + hi or lo align x to al unless effective type of x is c3_w or c3_d, assumes x is a pointer. - */ +*/ #define c3_align(x, al, hilo) \ _Generic((x), \ c3_w : c3_align_w, \ diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index af94e35cbc..b469094f1d 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -20,9 +20,6 @@ c3_w u3_Code; // void u3a_config_loom(c3_w ver_w); -c3_w c3_align_w(c3_w x, c3_w al, align_dir hilo); /* ;;: after rebasing on /vere, these should be declared somewhere else (the align functions) */ -c3_d c3_align_d(c3_d x, c3_d al, align_dir hilo); -void *c3_align_p(void const * p, size_t al, align_dir hilo); void *u3a_into(c3_w x); c3_w u3a_outa(void *p); c3_w u3a_to_off(c3_w som); From 65328d762aacad87ae34b7eb79d0af3bff54afd6 Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 17 Feb 2023 14:43:32 -0500 Subject: [PATCH 25/26] misc. --- pkg/noun/allocate.c | 18 +++--------------- pkg/noun/manage.c | 2 +- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index b469094f1d..7ddbe94571 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -647,24 +647,15 @@ u3a_walloc(c3_w len_w) void* u3a_wealloc(void* lag_v, c3_w len_w) { - c3_w req_w; /* allocation request length */ - - /* N.B: see related note in _ca_walloc */ - req_w = len_w - + (c3_wiseof(u3a_box) + 1) - + u3C.walign_w - & ~(u3C.walign_w - 1) - - (c3_wiseof(u3a_box) + 1); - if ( !lag_v ) { - return u3a_malloc(req_w); + return u3a_walloc(len_w); } else { u3a_box* box_u = u3a_botox(lag_v); c3_w* old_w = lag_v; - c3_w tiz_w = c3_min(box_u->siz_w, req_w); + c3_w tiz_w = c3_min(box_u->siz_w, len_w); { - c3_w* new_w = u3a_walloc(req_w); + c3_w* new_w = u3a_walloc(len_w); c3_w i_w; for ( i_w = 0; i_w < tiz_w; i_w++ ) { @@ -958,9 +949,6 @@ u3a_realloc(void* lag_v, size_t len_i) return new_w; } } - c3_w len_w = (c3_w)len_i; - - return u3a_wealloc(lag_v, (len_w + 3) >> 2); } /* u3a_free(): free for aligned malloc. diff --git a/pkg/noun/manage.c b/pkg/noun/manage.c index bbad863fe3..e45202e938 100644 --- a/pkg/noun/manage.c +++ b/pkg/noun/manage.c @@ -806,7 +806,7 @@ u3m_error(c3_c* str_c) void u3m_leap(c3_w pad_w) { - c3_w len_w; /* the length of the new road (avail - (pad [4M] + wiseof(u3a_road))) */ + c3_w len_w; /* the length of the new road (avail - (pad + wiseof(u3a_road))) */ u3_road* rod_u; _rod_vaal(u3R); From c08ada2524e58391a50a9c76c9cb9382aeba88cc Mon Sep 17 00:00:00 2001 From: barter-simsum Date: Fri, 24 Feb 2023 11:18:49 -0500 Subject: [PATCH 26/26] u3a_loom_sane() --- pkg/noun/allocate.c | 31 +++++++++++++++++++++++++++++++ pkg/noun/allocate.h | 5 +++++ pkg/noun/events.c | 3 +++ pkg/noun/manage.c | 5 +++++ 4 files changed, 44 insertions(+) diff --git a/pkg/noun/allocate.c b/pkg/noun/allocate.c index 7ddbe94571..2deb2f6e7d 100644 --- a/pkg/noun/allocate.c +++ b/pkg/noun/allocate.c @@ -2711,3 +2711,34 @@ u3a_string(u3_atom a) str_c[met_w] = 0; return str_c; } + +/* u3a_loom_sane(): sanity checks the state of the loom for obvious corruption + */ +void +u3a_loom_sane() +{ + /* + Only checking validity of freelists for now. Other checks could be added, + e.g. noun HAMT traversal, boxwise traversal of loom validating `siz_w`s, + `use_w`s, no empty space, etc. If added, some of that may need to be guarded + behind C3DBG flags. Freelist traversal is probably fine to always do though. + */ + for (c3_w i_w = 0; i_w < u3a_fbox_no; i_w++) { + u3p(u3a_fbox) this_p = u3R->all.fre_p[i_w]; + u3a_fbox *this_u = u3to(u3a_fbox, this_p); + for (; this_p + ; this_p = this_u->nex_p + , this_u = u3to(u3a_fbox, this_p)) { + u3p(u3a_fbox) pre_p = this_u->pre_p + , nex_p = this_u->nex_p; + u3a_fbox *pre_u = u3to(u3a_fbox, this_u->pre_p) + , *nex_u = u3to(u3a_fbox, this_u->nex_p); + + if (nex_p && nex_u->pre_p != this_p) c3_assert(!"loom: wack"); + if (pre_p && pre_u->nex_p != this_p) c3_assert(!"loom: wack"); + if (!pre_p /* this must be the head of a freelist */ + && u3R->all.fre_p[_box_slot(this_u->box_u.siz_w)] != this_p) + c3_assert(!"loom: wack"); + } + } +} diff --git a/pkg/noun/allocate.h b/pkg/noun/allocate.h index 6db6ae93a0..a42a596c7d 100644 --- a/pkg/noun/allocate.h +++ b/pkg/noun/allocate.h @@ -748,4 +748,9 @@ c3_c* u3a_string(u3_atom a); + /* u3a_loom_sane(): sanity checks the state of the loom for obvious corruption + */ + void + u3a_loom_sane(); + #endif /* ifndef U3_ALLOCATE_H */ diff --git a/pkg/noun/events.c b/pkg/noun/events.c index cfd18c092f..25dbfe3c3c 100644 --- a/pkg/noun/events.c +++ b/pkg/noun/events.c @@ -1078,6 +1078,9 @@ u3e_save(void) return; } + /* attempt to avoid propagating anything insane to disk */ + u3a_loom_sane(); + // u3a_print_memory(stderr, "sync: save", 4096 * pat_u->con_u->pgs_w); _ce_patch_sync(pat_u); diff --git a/pkg/noun/manage.c b/pkg/noun/manage.c index e45202e938..4548052db2 100644 --- a/pkg/noun/manage.c +++ b/pkg/noun/manage.c @@ -605,6 +605,9 @@ _find_home(void) // this looks risky, but there are no legitimate scenarios where it's wrong u3R->cap_p = u3R->mat_p = u3C.wor_i - c3_wiseof(*u3H); + /* As a further guard against any sneaky loom corruption */ + u3a_loom_sane(); + if (U3V_VERLAT > ver_w) { u3m_migrate(U3V_VERLAT); u3a_config_loom(U3V_VERLAT); @@ -2162,5 +2165,7 @@ u3m_migrate(u3v_version ver_w) /* finally update the version and commit to disk */ u3H->ver_w = ver_w; + /* extra assurance we haven't corrupted the loom before writing to disk */ + u3a_loom_sane(); u3e_save(); }