summaryrefslogtreecommitdiff
path: root/vere/pkg/noun/v2
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-10-06 01:01:41 +0700
committerpolwex <polwex@sortug.com>2025-10-06 01:01:41 +0700
commitc4b392a179048f936c062f5ffccc2bc25627e500 (patch)
tree09be0904be8ec4d7ea52992ef7580d42ed0c28c1 /vere/pkg/noun/v2
working
Diffstat (limited to 'vere/pkg/noun/v2')
-rw-r--r--vere/pkg/noun/v2/allocate.c73
-rw-r--r--vere/pkg/noun/v2/allocate.h134
-rw-r--r--vere/pkg/noun/v2/hashtable.c143
-rw-r--r--vere/pkg/noun/v2/hashtable.h42
-rw-r--r--vere/pkg/noun/v2/jets.c54
-rw-r--r--vere/pkg/noun/v2/jets.h35
-rw-r--r--vere/pkg/noun/v2/manage.c174
-rw-r--r--vere/pkg/noun/v2/manage.h13
-rw-r--r--vere/pkg/noun/v2/nock.c92
-rw-r--r--vere/pkg/noun/v2/nock.h64
-rw-r--r--vere/pkg/noun/v2/options.h14
-rw-r--r--vere/pkg/noun/v2/vortex.c25
-rw-r--r--vere/pkg/noun/v2/vortex.h40
13 files changed, 903 insertions, 0 deletions
diff --git a/vere/pkg/noun/v2/allocate.c b/vere/pkg/noun/v2/allocate.c
new file mode 100644
index 0000000..0476f8a
--- /dev/null
+++ b/vere/pkg/noun/v2/allocate.c
@@ -0,0 +1,73 @@
+/// @file
+
+#include "../allocate.h"
+#include "v1/allocate.h"
+#include "v2/allocate.h"
+
+#include "v2/hashtable.h"
+#include "log.h"
+#include "v2/manage.h"
+#include "options.h"
+#include "retrieve.h"
+#include "trace.h"
+#include "vortex.h"
+
+u3a_v2_road* u3a_v2_Road;
+
+u3_noun
+u3a_v2_rewritten_noun(u3_noun som)
+{
+ if ( c3y == u3a_v2_is_cat(som) ) {
+ return som;
+ }
+ u3_post som_p = u3a_v2_rewritten(u3a_v1_to_off(som));
+
+ if ( c3y == u3a_v2_is_pug(som) ) {
+ som_p = u3a_v2_to_pug(som_p);
+ }
+ else {
+ som_p = u3a_v2_to_pom(som_p);
+ }
+
+ return som_p;
+}
+
+/* u3a_v2_mig_rewrite_compact(): rewrite pointers in ad-hoc persistent road structures.
+*/
+void
+u3a_v2_mig_rewrite_compact(void)
+{
+ u3a_v2_rewrite_noun(u3R_v2->ski.gul);
+ u3a_v2_rewrite_noun(u3R_v2->bug.tax);
+ u3a_v2_rewrite_noun(u3R_v2->bug.mer);
+ u3a_v2_rewrite_noun(u3R_v2->pro.don);
+ u3a_v2_rewrite_noun(u3R_v2->pro.day);
+ u3a_v2_rewrite_noun(u3R_v2->pro.trace);
+ u3h_v2_rewrite(u3R_v2->cax.har_p);
+
+ u3R_v2->ski.gul = u3a_v2_rewritten_noun(u3R_v2->ski.gul);
+ u3R_v2->bug.tax = u3a_v2_rewritten_noun(u3R_v2->bug.tax);
+ u3R_v2->bug.mer = u3a_v2_rewritten_noun(u3R_v2->bug.mer);
+ u3R_v2->pro.don = u3a_v2_rewritten_noun(u3R_v2->pro.don);
+ u3R_v2->pro.day = u3a_v2_rewritten_noun(u3R_v2->pro.day);
+ u3R_v2->pro.trace = u3a_v2_rewritten_noun(u3R_v2->pro.trace);
+ u3R_v2->cax.har_p = u3a_v2_rewritten(u3R_v2->cax.har_p);
+}
+
+void
+u3a_v2_rewrite_noun(u3_noun som)
+{
+ if ( c3n == u3a_v2_is_cell(som) ) {
+ return;
+ }
+
+ if ( c3n == u3a_v2_rewrite_ptr(u3a_v1_to_ptr((som))) ) return;
+
+ u3a_v2_cell* cel = (u3a_v2_cell*) u3a_v1_to_ptr(som);
+
+ u3a_v2_rewrite_noun(cel->hed);
+ u3a_v2_rewrite_noun(cel->tel);
+
+ cel->hed = u3a_v2_rewritten_noun(cel->hed);
+ cel->tel = u3a_v2_rewritten_noun(cel->tel);
+}
diff --git a/vere/pkg/noun/v2/allocate.h b/vere/pkg/noun/v2/allocate.h
new file mode 100644
index 0000000..8832977
--- /dev/null
+++ b/vere/pkg/noun/v2/allocate.h
@@ -0,0 +1,134 @@
+#ifndef U3_ALLOCATE_V2_H
+#define U3_ALLOCATE_V2_H
+
+#include "../allocate.h"
+
+#include "v2/manage.h"
+#include "options.h"
+
+ /** Aliases.
+ **/
+# define u3a_v2_botox u3a_botox
+# define u3a_v2_box u3a_box
+# define u3a_v2_cell u3a_cell
+# define u3a_v2_fbox u3a_fbox
+# define u3a_v2_fbox_no u3a_fbox_no
+# define u3a_v2_free u3a_free
+# define u3a_v2_heap u3a_heap
+# define u3a_v2_into u3a_into
+# define u3a_v2_is_cat u3a_is_cat
+# define u3a_v2_is_cell u3a_is_cell
+# define u3a_v2_is_north u3a_is_north
+# define u3a_v2_is_pom u3a_is_pom
+# define u3a_v2_is_pug u3a_is_pug
+# define u3a_v2_lose u3a_lose
+# define u3a_v2_malloc u3a_malloc
+# define u3a_v2_minimum u3a_minimum
+# define u3a_v2_outa u3a_outa
+# define u3a_v2_pack_seek u3a_pack_seek
+# define u3a_v2_rewrite u3a_rewrite
+# define u3a_v2_rewrite_ptr u3a_rewrite_ptr
+# define u3a_v2_rewritten u3a_rewritten
+# define u3a_v2_to_off u3a_to_off
+# define u3a_v2_to_ptr u3a_to_ptr
+# define u3a_v2_to_wtr u3a_to_wtr
+# define u3a_v2_to_pug u3a_to_pug
+# define u3a_v2_to_pom u3a_to_pom
+# define u3a_v2_wfree u3a_wfree
+
+ /** Data structures.
+ **/
+ /* u3a_v2_road: contiguous allocation and execution context.
+ */
+ typedef struct _u3a_v2_road {
+ u3p(struct _u3a_v2_road) par_p; // parent road
+ u3p(struct _u3a_v2_road) kid_p; // child road list
+ u3p(struct _u3a_v2_road) nex_p; // sibling road
+
+ u3p(c3_w) cap_p; // top of transient region
+ u3p(c3_w) hat_p; // top of durable region
+ u3p(c3_w) mat_p; // bottom of transient region
+ u3p(c3_w) rut_p; // bottom of durable region
+ u3p(c3_w) ear_p; // original cap if kid is live
+
+ c3_w fut_w[32]; // futureproof buffer
+
+ struct { // escape buffer
+ union {
+ jmp_buf buf;
+ c3_w buf_w[256]; // futureproofing
+ };
+ } esc;
+
+ struct { // miscellaneous config
+ c3_w fag_w; // flag bits
+ } how; //
+
+ struct { // allocation pools
+ u3p(u3a_v2_fbox) fre_p[u3a_v2_fbox_no]; // heap by node size log
+ u3p(u3a_fbox) cel_p; // custom cell allocator
+ c3_w fre_w; // number of free words
+ c3_w max_w; // maximum allocated
+ } all;
+
+ u3a_jets jed; // jet dashboard
+
+ struct { // bytecode state
+ u3p(u3h_root) har_p; // formula->post of bytecode
+ } byc;
+
+ struct { // namespace
+ u3_noun gul; // (list $+(* (unit (unit)))) now
+ } ski;
+
+ struct { // trace stack
+ u3_noun tax; // (list ,*)
+ u3_noun mer; // emergency buffer to release
+ } bug;
+
+ struct { // profile stack
+ c3_d nox_d; // nock steps
+ c3_d cel_d; // cell allocations
+ u3_noun don; // (list batt)
+ u3_noun trace; // (list trace)
+ u3_noun day; // doss, only in u3H (moveme)
+ } pro;
+
+ struct { // memoization
+ u3p(u3h_root) har_p; // (map (pair term noun) noun)
+ } cax;
+ } u3a_v2_road;
+
+ /** Globals.
+ **/
+ /// Current road (thread-local).
+ extern u3a_v2_road* u3a_v2_Road;
+# define u3R_v2 u3a_v2_Road
+
+ /** Functions.
+ **/
+ /** Allocation.
+ **/
+ /* Reference and arena control.
+ */
+ /* u3a_v2_mig_rewrite_compact(): rewrite pointers in ad-hoc persistent road structures.
+ */
+ void
+ u3a_v2_mig_rewrite_compact(void);
+
+ /* u3a_v2_rewrite_noun(): rewrite a noun for compaction.
+ */
+ void
+ u3a_v2_rewrite_noun(u3_noun som);
+
+ /* u3a_v2_rewritten(): rewrite a pointer for compaction.
+ */
+ u3_post
+ u3a_v2_rewritten(u3_post som_p);
+
+ /* u3a_v2_rewritten(): rewritten noun pointer for compaction.
+ */
+ u3_noun
+ u3a_v2_rewritten_noun(u3_noun som);
+
+#endif /* ifndef U3_ALLOCATE_V2_H */
diff --git a/vere/pkg/noun/v2/hashtable.c b/vere/pkg/noun/v2/hashtable.c
new file mode 100644
index 0000000..a4f0291
--- /dev/null
+++ b/vere/pkg/noun/v2/hashtable.c
@@ -0,0 +1,143 @@
+/// @file
+
+#include "../hashtable.h"
+#include "v1/hashtable.h"
+#include "v2/hashtable.h"
+
+#include "../allocate.h"
+#include "v1/allocate.h"
+#include "v2/allocate.h"
+
+/* _ch_v2_popcount(): number of bits set in word. A standard intrinsic.
+** NB: copy of _ch_v2_popcount in pkg/noun/hashtable.c
+*/
+static c3_w
+_ch_v2_popcount(c3_w num_w)
+{
+ return __builtin_popcount(num_w);
+}
+
+/* _ch_v2_free_buck(): free bucket
+** NB: copy of _ch_v2_free_buck in pkg/noun/hashtable.c
+*/
+static void
+_ch_v2_free_buck(u3h_v2_buck* hab_u)
+{
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) {
+ u3z(u3h_v2_slot_to_noun(hab_u->sot_w[i_w]));
+ }
+ u3a_v2_wfree(hab_u);
+}
+
+/* _ch_v2_free_node(): free node.
+*/
+static void
+_ch_v2_free_node(u3h_v2_node* han_u, c3_w lef_w)
+{
+ c3_w len_w = _ch_v2_popcount(han_u->map_w);
+ c3_w i_w;
+
+ lef_w -= 5;
+
+ for ( i_w = 0; i_w < len_w; i_w++ ) {
+ c3_w sot_w = han_u->sot_w[i_w];
+
+ if ( _(u3h_v2_slot_is_noun(sot_w)) ) {
+ u3z(u3h_v2_slot_to_noun(sot_w));
+ }
+ else {
+ // NB: u3h_v2_slot_to_node()
+ void* hav_v = u3h_v2_slot_to_node(sot_w);
+
+ if ( 0 == lef_w ) {
+ _ch_v2_free_buck(hav_v);
+ } else {
+ _ch_v2_free_node(hav_v, lef_w);
+ }
+ }
+ }
+ u3a_v2_wfree(han_u);
+}
+
+/* _ch_v2_rewrite_buck(): rewrite buck for compaction.
+*/
+void
+_ch_v2_rewrite_buck(u3h_v2_buck* hab_u)
+{
+ if ( c3n == u3a_v2_rewrite_ptr(hab_u) ) return;
+ c3_w i_w;
+
+ for ( i_w = 0; i_w < hab_u->len_w; i_w++ ) {
+ u3_noun som = u3h_v2_slot_to_noun(hab_u->sot_w[i_w]);
+ hab_u->sot_w[i_w] = u3h_v2_noun_to_slot(u3a_v2_rewritten_noun(som));
+ u3a_v2_rewrite_noun(som);
+ }
+}
+
+/* _ch_v2_rewrite_node(): rewrite node for compaction.
+*/
+void
+_ch_v2_rewrite_node(u3h_v2_node* han_u, c3_w lef_w)
+{
+ if ( c3n == u3a_v2_rewrite_ptr(han_u) ) return;
+
+ c3_w len_w = _ch_v2_popcount(han_u->map_w);
+ c3_w i_w;
+
+ lef_w -= 5;
+
+ for ( i_w = 0; i_w < len_w; i_w++ ) {
+ c3_w sot_w = han_u->sot_w[i_w];
+
+ if ( _(u3h_v2_slot_is_noun(sot_w)) ) {
+ u3_noun kev = u3h_v2_slot_to_noun(sot_w);
+ han_u->sot_w[i_w] = u3h_v2_noun_to_slot(u3a_v2_rewritten_noun(kev));
+
+ u3a_v2_rewrite_noun(kev);
+ }
+ else {
+ void* hav_v = u3h_v1_slot_to_node(sot_w);
+ u3h_v2_node* nod_u = u3to(u3h_v2_node, u3a_v2_rewritten(u3of(u3h_v2_node,hav_v)));
+
+ han_u->sot_w[i_w] = u3h_v2_node_to_slot(nod_u);
+
+ if ( 0 == lef_w ) {
+ _ch_v2_rewrite_buck(hav_v);
+ } else {
+ _ch_v2_rewrite_node(hav_v, lef_w);
+ }
+ }
+ }
+}
+
+/* u3h_v2_rewrite(): rewrite pointers during compaction.
+*/
+void
+u3h_v2_rewrite(u3p(u3h_v2_root) har_p)
+{
+ u3h_v2_root* har_u = u3to(u3h_v2_root, har_p);
+ c3_w i_w;
+
+ if ( c3n == u3a_v2_rewrite_ptr(har_u) ) return;
+
+ for ( i_w = 0; i_w < 64; i_w++ ) {
+ c3_w sot_w = har_u->sot_w[i_w];
+
+ if ( _(u3h_v2_slot_is_noun(sot_w)) ) {
+ u3_noun kev = u3h_v2_slot_to_noun(sot_w);
+ har_u->sot_w[i_w] = u3h_v2_noun_to_slot(u3a_v2_rewritten_noun(kev));
+
+ u3a_v2_rewrite_noun(kev);
+ }
+ else if ( _(u3h_v2_slot_is_node(sot_w)) ) {
+ u3h_v2_node* han_u = (u3h_v2_node*) u3h_v1_slot_to_node(sot_w);
+ u3h_v2_node* nod_u = u3to(u3h_v2_node, u3a_v2_rewritten(u3of(u3h_v2_node,han_u)));
+
+ har_u->sot_w[i_w] = u3h_v2_node_to_slot(nod_u);
+
+ _ch_v2_rewrite_node(han_u, 25);
+ }
+ }
+}
diff --git a/vere/pkg/noun/v2/hashtable.h b/vere/pkg/noun/v2/hashtable.h
new file mode 100644
index 0000000..2278640
--- /dev/null
+++ b/vere/pkg/noun/v2/hashtable.h
@@ -0,0 +1,42 @@
+#ifndef U3_HASHTABLE_V2_H
+#define U3_HASHTABLE_V2_H
+
+#define u3h_v2_buck u3h_buck
+#define u3h_v2_free u3h_free
+#define u3h_v2_new u3h_new
+#define u3h_v2_node u3h_node
+#define u3h_v2_noun_to_slot u3h_noun_to_slot
+#define u3h_v2_root u3h_root
+#define u3h_v2_slot_is_node u3h_slot_is_node
+#define u3h_v2_slot_is_noun u3h_slot_is_noun
+#define u3h_v2_slot_to_noun u3h_slot_to_noun
+#define u3h_v2_walk u3h_walk
+#define u3h_v2_walk_with u3h_walk_with
+
+#include "../hashtable.h"
+
+#include "c3/c3.h"
+#include "types.h"
+
+ /** Data structures.
+ **/
+
+ /** HAMT macros.
+ ***
+ *** Coordinate with u3_noun definition!
+ **/
+ /* u3h_v2_slot_to_node(): slot to node pointer
+ ** u3h_v2_node_to_slot(): node pointer to slot
+ */
+# define u3h_v2_slot_to_node(sot) (u3a_v2_into(((sot) & 0x3fffffff) << u3a_vits))
+# define u3h_v2_node_to_slot(ptr) ((u3a_v2_outa((ptr)) >> u3a_vits) | 0x40000000)
+
+ /** Functions.
+ ***
+ **/
+ /* u3h_v2_rewrite(): rewrite hashtable for compaction.
+ */
+ void
+ u3h_v2_rewrite(u3p(u3h_root) har_p);
+
+#endif /* U3_HASHTABLE_V2_H */
diff --git a/vere/pkg/noun/v2/jets.c b/vere/pkg/noun/v2/jets.c
new file mode 100644
index 0000000..4d5fa0f
--- /dev/null
+++ b/vere/pkg/noun/v2/jets.c
@@ -0,0 +1,54 @@
+/// @file
+
+#include "../vortex.h"
+
+#include "../jets.h"
+#include "v2/jets.h"
+
+#include "v2/allocate.h"
+#include "v2/hashtable.h"
+#include "v2/vortex.h"
+
+#include "v3/hashtable.h"
+#include "v3/jets.h"
+
+/* u3j_v2_reclaim(): clear ad-hoc persistent caches to reclaim memory.
+*/
+void
+u3j_v2_reclaim(void)
+{
+ // set globals (required for aliased functions)
+ u3H = (u3v_home*) u3H_v2;
+ u3R = (u3a_road*) u3R_v2;
+
+ // clear the jet hank cache
+ //
+ u3h_v3_walk(u3R->jed.han_p, u3j_v3_free_hank);
+ u3h_v3_free(u3R->jed.han_p);
+ u3R->jed.han_p = u3h_v3_new();
+}
+
+/* u3j_v2_mig_rewrite_compact(): rewrite jet state for compaction.
+ *
+ * NB: u3R_v2->jed.han_p *must* be cleared (currently via u3j_v2_reclaim above)
+ * since it contains hanks which are not nouns but have loom pointers.
+ * Alternately, rewrite the entries with u3h_v2_walk, using u3j_v2_mark as a
+ * template for how to walk. There's an untested attempt at this in git
+ * history at e8a307a.
+*/
+void
+u3j_v2_mig_rewrite_compact(void)
+{
+ u3h_v2_rewrite(u3R_v2->jed.war_p);
+ u3h_v2_rewrite(u3R_v2->jed.cod_p);
+ u3h_v2_rewrite(u3R_v2->jed.han_p);
+ u3h_v2_rewrite(u3R_v2->jed.bas_p);
+
+ u3h_v2_rewrite(u3R_v2->jed.hot_p);
+ u3R_v2->jed.hot_p = u3a_v2_rewritten(u3R_v2->jed.hot_p);
+
+ u3R_v2->jed.war_p = u3a_v2_rewritten(u3R_v2->jed.war_p);
+ u3R_v2->jed.cod_p = u3a_v2_rewritten(u3R_v2->jed.cod_p);
+ u3R_v2->jed.han_p = u3a_v2_rewritten(u3R_v2->jed.han_p);
+ u3R_v2->jed.bas_p = u3a_v2_rewritten(u3R_v2->jed.bas_p);
+}
diff --git a/vere/pkg/noun/v2/jets.h b/vere/pkg/noun/v2/jets.h
new file mode 100644
index 0000000..33ac088
--- /dev/null
+++ b/vere/pkg/noun/v2/jets.h
@@ -0,0 +1,35 @@
+/// @file
+
+#ifndef U3_JETS_V2_H
+#define U3_JETS_V2_H
+
+#include "../allocate.h"
+#include "../jets.h"
+
+
+ /** Aliases.
+ **/
+# define u3j_v2_core u3j_core
+# define u3j_v2_fink u3j_fink
+# define u3j_v2_fist u3j_fist
+# define u3j_v2_hank u3j_hank
+# define u3j_v2_free_hank u3j_free_hank
+# define u3j_v2_harm u3j_harm
+# define u3j_v2_rite u3j_rite
+# define u3j_v2_site u3j_site
+# define u3j_v2_rite_lose u3j_rite_lose
+# define u3j_v2_site_lose u3j_site_lose
+
+ /** Functions.
+ **/
+ /* u3j_v2_reclaim(): clear ad-hoc persistent caches to reclaim memory.
+ */
+ void
+ u3j_v2_reclaim(void);
+
+ /* u3j_v2_mig_rewrite_compact(): rewrite jet state for compaction.
+ */
+ void
+ u3j_v2_mig_rewrite_compact(void);
+
+#endif /* ifndef U3_JETS_V2_H */
diff --git a/vere/pkg/noun/v2/manage.c b/vere/pkg/noun/v2/manage.c
new file mode 100644
index 0000000..16981d2
--- /dev/null
+++ b/vere/pkg/noun/v2/manage.c
@@ -0,0 +1,174 @@
+/// @file
+
+#include "v2/manage.h"
+
+#include "v1/allocate.h"
+#include "v2/allocate.h"
+#include "v2/hashtable.h"
+#include "v2/jets.h"
+#include "v2/nock.h"
+#include "v2/options.h"
+#include "../vortex.h"
+#include "v1/vortex.h"
+#include "v2/vortex.h"
+
+/* _cm_pack_rewrite(): trace through arena, rewriting pointers.
+*/
+static void
+_cm_pack_rewrite(void)
+{
+ u3v_v2_mig_rewrite_compact();
+ u3j_v2_mig_rewrite_compact();
+ u3n_v2_mig_rewrite_compact();
+ u3a_v2_mig_rewrite_compact();
+}
+
+static void
+_migrate_reclaim(void)
+{
+ // XX update this and similar printfs
+ fprintf(stderr, "loom: migration reclaim\r\n");
+ u3m_v1_reclaim();
+}
+
+static void
+_migrate_seek(const u3a_v2_road *rod_u)
+{
+ /*
+ very much like u3a_v2_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_v2_into(rod_u->rut_p);
+ c3_w * end_w = u3a_v2_into(rod_u->hat_p);
+ u3_post new_p = (rod_u->rut_p + 1 + c3_wiseof(u3a_v2_box));
+ u3a_v2_box * box_u = (void *)box_w;
+
+ fprintf(stderr, "loom: migration seek\r\n");
+
+ for (; box_w < end_w
+ ; box_w += box_u->siz_w
+ , box_u = (void*)box_w)
+ {
+ if (!box_u->use_w)
+ continue;
+ u3_assert(box_u->siz_w);
+ u3_assert(box_u->use_w);
+ box_w[box_u->siz_w - 1] = new_p;
+ new_p = c3_align(new_p + box_u->siz_w, 2, C3_ALGHI);
+ }
+}
+
+static void
+_migrate_rewrite(void)
+{
+ fprintf(stderr, "loom: migration rewrite\r\n");
+
+ _cm_pack_rewrite();
+}
+
+static void
+_migrate_move(u3a_v2_road *rod_u)
+{
+ fprintf(stderr, "loom: migration move\r\n");
+
+ c3_z hiz_z = u3a_v2_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_v1->rut_p migrates from 1 to 2 */
+ for (u3a_v2_box *box_u = u3a_v2_into(rod_u->rut_p)
+ ; (void *)box_u < u3a_v2_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_v2_into(u3H_v2->rod_u.rut_p + off_w),
+ u3a_v2_into(u3H_v2->rod_u.rut_p),
+ hiz_z);
+ /* manually zero the former rut */
+ *(c3_w *)u3a_v2_into(rod_u->rut_p) = 0;
+
+ /* relocate boxes to DWORD-aligned addresses stored in trailing size word */
+ c3_w *box_w = u3a_v2_into(rod_u->rut_p + off_w);
+ c3_w *end_w = u3a_v2_into(rod_u->hat_p + off_w);
+ u3a_v2_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_v2_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_v2_botox(u3a_v2_into(new_p));
+ u3_assert(box_w[siz_w - 1] == new_p);
+ u3_assert(new_w <= box_w);
+
+ c3_w i_w;
+ for (i_w = 0; i_w < siz_w - 1; i_w++)
+ new_w[i_w] = box_w[i_w];
+
+ if (siz_w & 1) {
+ new_w[i_w++] = 0; /* pad odd sized boxes */
+ new_w[i_w++] = siz_w + 1; /* restore trailing size word */
+ new_w[0] = siz_w + 1; /* and the leading size word */
+ }
+ else {
+ new_w[i_w++] = siz_w;
+ }
+
+ new_p += i_w;
+ }
+
+ /* restore proper heap state */
+ rod_u->rut_p = 2;
+ rod_u->hat_p = new_p - c3_wiseof(u3a_v2_box);
+
+ /* like |pack, clear the free lists and cell allocator */
+ for (c3_w i_w = 0; i_w < u3a_v2_fbox_no; i_w++)
+ u3R_v1->all.fre_p[i_w] = 0;
+
+ u3R_v1->all.fre_w = 0;
+ u3R_v1->all.cel_p = 0;
+}
+
+
+/* u3m_v2_migrate: perform loom migration if necessary.
+*/
+void
+u3m_v2_migrate(void)
+{
+ c3_w len_w = u3C_v2.wor_i - 1;
+ c3_w ver_w = *(u3_Loom + len_w);
+
+ u3_assert( U3V_VER1 == ver_w );
+
+ c3_w* mem_w = u3_Loom + 1;
+ c3_w siz_w = c3_wiseof(u3v_v1_home);
+ c3_w* mat_w = (mem_w + len_w) - siz_w;
+
+ u3H_v1 = (void *)mat_w;
+ u3R_v1 = &u3H_v1->rod_u;
+
+ u3R_v1->cap_p = u3R_v1->mat_p = u3a_v1_outa(u3H_v1);
+
+ fprintf(stderr, "loom: pointer compression migration running...\r\n");
+
+ /* perform the migration in a pattern similar to |pack */
+ _migrate_reclaim();
+ _migrate_seek(&u3H_v1->rod_u);
+ _migrate_rewrite();
+ _migrate_move(&u3H_v1->rod_u);
+
+ /* finally update the version and commit to disk */
+ u3H_v1->ver_w = U3V_VER2;
+
+ fprintf(stderr, "loom: pointer compression migration done\r\n");
+}
diff --git a/vere/pkg/noun/v2/manage.h b/vere/pkg/noun/v2/manage.h
new file mode 100644
index 0000000..623453e
--- /dev/null
+++ b/vere/pkg/noun/v2/manage.h
@@ -0,0 +1,13 @@
+/// @file
+
+#ifndef U3_MANAGE_V2_H
+#define U3_MANAGE_V2_H
+
+ /** System management.
+ **/
+ /* u3m_v2_migrate: perform pointer compression loom migration if necessary.
+ */
+ void
+ u3m_v2_migrate(void);
+
+#endif /* ifndef U3_MANAGE_V2_H */
diff --git a/vere/pkg/noun/v2/nock.c b/vere/pkg/noun/v2/nock.c
new file mode 100644
index 0000000..e42221a
--- /dev/null
+++ b/vere/pkg/noun/v2/nock.c
@@ -0,0 +1,92 @@
+/// @file
+
+#include "v2/nock.h"
+
+#include "../vortex.h"
+
+#include "v2/allocate.h"
+#include "v2/hashtable.h"
+#include "v2/vortex.h"
+
+#include "v3/hashtable.h"
+
+/* u3n_v2_reclaim(): clear ad-hoc persistent caches to reclaim memory.
+*/
+void
+u3n_v2_reclaim(void)
+{
+ // set globals (required for aliased functions)
+ u3H = (u3v_home*) u3H_v2;
+ u3R = (u3a_road*) u3R_v2;
+
+ // clear the bytecode cache
+ u3n_v2_free();
+ u3R->byc.har_p = u3h_v2_new();
+}
+
+/* _cn_v2_prog_free(): free memory retained by program pog_u
+*/
+static void
+_cn_v2_prog_free(u3n_v2_prog* pog_u)
+{
+ // fix up pointers for loom portability
+ pog_u->byc_u.ops_y = (c3_y*) ((void*) pog_u) + sizeof(u3n_v2_prog);
+ pog_u->lit_u.non = (u3_noun*) (pog_u->byc_u.ops_y + pog_u->byc_u.len_w);
+ pog_u->mem_u.sot_u = (u3n_v2_memo*) (pog_u->lit_u.non + pog_u->lit_u.len_w);
+ pog_u->cal_u.sit_u = (u3j_v2_site*) (pog_u->mem_u.sot_u + pog_u->mem_u.len_w);
+ pog_u->reg_u.rit_u = (u3j_v2_rite*) (pog_u->cal_u.sit_u + pog_u->cal_u.len_w);
+
+ c3_w dex_w;
+ for (dex_w = 0; dex_w < pog_u->lit_u.len_w; ++dex_w) {
+ u3a_v2_lose(pog_u->lit_u.non[dex_w]);
+ }
+ for (dex_w = 0; dex_w < pog_u->mem_u.len_w; ++dex_w) {
+ u3a_v2_lose(pog_u->mem_u.sot_u[dex_w].key);
+ }
+ for (dex_w = 0; dex_w < pog_u->cal_u.len_w; ++dex_w) {
+ u3j_v2_site_lose(&(pog_u->cal_u.sit_u[dex_w]));
+ }
+ for (dex_w = 0; dex_w < pog_u->reg_u.len_w; ++dex_w) {
+ u3j_v2_rite_lose(&(pog_u->reg_u.rit_u[dex_w]));
+ }
+ u3a_v2_free(pog_u);
+}
+
+/* _n_v2_feb(): u3h_v2_walk helper for u3n_v2_free
+ */
+static void
+_n_v2_feb(u3_noun kev)
+{
+ u3a_v2_cell *cel_u = (u3a_v2_cell*) u3a_v2_to_ptr(kev);
+ _cn_v2_prog_free(u3to(u3n_v2_prog, cel_u->tel));
+}
+
+/* u3n_v2_free(): free bytecode cache
+ */
+void
+u3n_v2_free(void)
+{
+ u3p(u3h_v2_root) har_p = u3R_v2->byc.har_p;
+ u3h_v2_walk(har_p, _n_v2_feb);
+ u3h_v2_free(har_p);
+}
+
+/* u3n_v2_mig_rewrite_compact(): rewrite the bytecode cache for compaction.
+ *
+ * NB: u3R_v2->byc.har_p *must* be cleared (currently via u3n_v2_reclaim above),
+ * since it contains things that look like nouns but aren't.
+ * Specifically, it contains "cells" where the tail is a
+ * pointer to a u3a_v2_malloc'ed block that contains loom pointers.
+ *
+ * You should be able to walk this with u3h_v2_walk and rewrite the
+ * pointers, but you need to be careful to handle that u3a_v2_malloc
+ * pointers can't be turned into a box by stepping back two words. You
+ * must step back one word to get the padding, step then step back that
+ * many more words (plus one?).
+ */
+void
+u3n_v2_mig_rewrite_compact(void)
+{
+ u3h_v2_rewrite(u3R_v2->byc.har_p);
+ u3R_v2->byc.har_p = u3a_v2_rewritten(u3R_v2->byc.har_p);
+}
diff --git a/vere/pkg/noun/v2/nock.h b/vere/pkg/noun/v2/nock.h
new file mode 100644
index 0000000..efb9121
--- /dev/null
+++ b/vere/pkg/noun/v2/nock.h
@@ -0,0 +1,64 @@
+/// @file
+
+#ifndef U3_NOCK_V2_H
+#define U3_NOCK_V2_H
+
+#include "v3/nock.h"
+
+#include "v2/jets.h"
+
+#include "types.h"
+
+ /** Data structures.
+ **/
+ /* u3n_memo: %memo hint space
+ */
+ typedef struct {
+ c3_l sip_l;
+ u3_noun key;
+ } u3n_v2_memo;
+
+ /* u3n_v2_prog: program compiled from nock
+ */
+ typedef struct _u3n_v2_prog {
+ struct {
+ c3_o own_o; // program owns ops_y?
+ c3_w len_w; // length of bytecode (bytes)
+ c3_y* ops_y; // actual array of bytes
+ } byc_u; // bytecode
+ struct {
+ c3_w len_w; // number of literals
+ u3_noun* non; // array of literals
+ } lit_u; // literals
+ struct {
+ c3_w len_w; // number of memo slots
+ u3n_v2_memo* sot_u; // array of memo slots
+ } mem_u; // memo slot data
+ struct {
+ c3_w len_w; // number of calls sites
+ u3j_v2_site* sit_u; // array of sites
+ } cal_u; // call site data
+ struct {
+ c3_w len_w; // number of registration sites
+ u3j_v2_rite* rit_u; // array of sites
+ } reg_u; // registration site data
+ } u3n_v2_prog;
+
+ /** Functions.
+ **/
+ /* u3n_v2_reclaim(): clear ad-hoc persistent caches to reclaim memory.
+ */
+ void
+ u3n_v2_reclaim(void);
+
+ /* u3n_v2_free(): free bytecode cache.
+ */
+ void
+ u3n_v2_free(void);
+
+ /* u3n_v2_mig_rewrite_compact(): rewrite bytecode cache for compaction.
+ */
+ void
+ u3n_v2_mig_rewrite_compact(void);
+
+#endif /* ifndef U3_NOCK_V2_H */
diff --git a/vere/pkg/noun/v2/options.h b/vere/pkg/noun/v2/options.h
new file mode 100644
index 0000000..079f766
--- /dev/null
+++ b/vere/pkg/noun/v2/options.h
@@ -0,0 +1,14 @@
+/// @file
+
+#ifndef U3_OPTIONS_V2_H
+#define U3_OPTIONS_V2_H
+
+#include "../options.h"
+
+ /** Globals.
+ **/
+ /* u3_Config / u3C: global memory control.
+ */
+# define u3C_v2 u3C
+
+#endif /* ifndef U3_OPTIONS_H */
diff --git a/vere/pkg/noun/v2/vortex.c b/vere/pkg/noun/v2/vortex.c
new file mode 100644
index 0000000..9b21d5c
--- /dev/null
+++ b/vere/pkg/noun/v2/vortex.c
@@ -0,0 +1,25 @@
+/// @file
+
+#include "../vortex.h"
+#include "v2/vortex.h"
+
+#include "v2/allocate.h"
+
+u3v_v2_home* u3v_v2_Home;
+
+/* u3v_v2_mig_rewrite_compact(): rewrite arvo kernel for compaction.
+*/
+void
+u3v_v2_mig_rewrite_compact(void)
+{
+ u3v_v2_arvo* arv_u = &(u3H_v2->arv_u);
+
+ u3a_v2_rewrite_noun(arv_u->roc);
+ u3a_v2_rewrite_noun(arv_u->now);
+ u3a_v2_rewrite_noun(arv_u->yot);
+
+ arv_u->roc = u3a_v2_rewritten_noun(arv_u->roc);
+ arv_u->now = u3a_v2_rewritten_noun(arv_u->now);
+ arv_u->yot = u3a_v2_rewritten_noun(arv_u->yot);
+}
+
diff --git a/vere/pkg/noun/v2/vortex.h b/vere/pkg/noun/v2/vortex.h
new file mode 100644
index 0000000..9e04832
--- /dev/null
+++ b/vere/pkg/noun/v2/vortex.h
@@ -0,0 +1,40 @@
+/// @file
+
+#ifndef U3_VORTEX_V2_H
+#define U3_VORTEX_V2_H
+
+#include "../vortex.h"
+
+#include "v2/allocate.h"
+#include "../version.h"
+
+ /** Aliases.
+ **/
+# define u3v_v2_arvo u3v_arvo
+
+ /** Data structures.
+ **/
+ /* u3v_v2_home: all internal (within image) state.
+ ** NB: version must be last for discriminability in north road
+ */
+ typedef struct _u3v_v2_home {
+ u3a_v2_road rod_u; // storage state
+ u3v_v2_arvo arv_u; // arvo state
+ u3v_version ver_w; // version number
+ } u3v_v2_home;
+
+ /** Globals.
+ **/
+ /// Arvo internal state.
+ extern u3v_v2_home* u3v_v2_Home;
+# define u3H_v2 u3v_v2_Home
+# define u3A_v2 (&(u3v_v2_Home->arv_u))
+
+ /** Functions.
+ **/
+ /* u3v_v2_mig_rewrite_compact(): rewrite arvo kernel for compaction.
+ */
+ void
+ u3v_v2_mig_rewrite_compact(void);
+
+#endif /* ifndef U3_VORTEX_V2_H */