mirror of
https://github.com/urbit/shrub.git
synced 2024-11-24 13:06:09 +03:00
Various fixes and documentations.
This commit is contained in:
parent
c6d53985d6
commit
80d6f74886
387
Spec/u3.md
387
Spec/u3.md
@ -563,6 +563,27 @@ remote node, render the stacktrace as a consequence of the user's
|
||||
action - even if its its direct cause was (for instance) a Unix
|
||||
SIGINT or SIGALRM.
|
||||
|
||||
### u3: C structures on the loom
|
||||
|
||||
Normally, all data on the loom is nouns. Sometimes we break this
|
||||
rule just a little, though - eg, in the `u3h` hashtables.
|
||||
|
||||
To point to non-noun C structs on the loom, we use a `u3_post`,
|
||||
which is just a loom word offset. A macro lets us declare this
|
||||
as if it was a pointer:
|
||||
|
||||
typedef c3_w u3_post;
|
||||
#define u3p(type) u3_post
|
||||
|
||||
Some may regard this as clever, others as pointless. Anyway, use
|
||||
`u3to()` and `u3of()` to convert to and from pointers.
|
||||
|
||||
When using C structs on the loom - generally a bad idea - make
|
||||
sure anything which could be on the surface road is structurally
|
||||
portable, eg, won't change size when the pointer size changes.
|
||||
(Note also: we consider little-endian, rightly or wrongly, to
|
||||
have won the endian wars.)
|
||||
|
||||
## u3: API overview by prefix
|
||||
|
||||
Let's run through the `u3` modules one by one. All public
|
||||
@ -623,7 +644,6 @@ For descending into a subroad *without* Nock virtualization,
|
||||
use `u3m_hate()` and `u3m_love` respectively. Hating enters
|
||||
a subroad; loving leaves it, copying out a product noun.
|
||||
|
||||
|
||||
Other miscellaneous tools in `u3m`: `u3m_file()` loads a Unix
|
||||
file as a Nock atom; `u3m_water()` measures the boundaries of
|
||||
the loom in current use (ie, watermarks); and a variety of
|
||||
@ -631,6 +651,10 @@ prettyprinting routines, none perfect, are available, mainly for
|
||||
debugging printfs: `u3m_pretty()`, `u3m_p()`, `u3m_tape()` and
|
||||
`u3m_wall()`.
|
||||
|
||||
It's sometimes nice to run a mark-and-sweep garbage collector,
|
||||
`u3m_grab()`, which collects the world from a list of roots,
|
||||
and asserts if it finds any leaks or incorrect refcounts.
|
||||
|
||||
### u3j: jets
|
||||
|
||||
The jet system, `u3j`, is what makes `u3` and `nock` in any sense
|
||||
@ -726,8 +750,7 @@ Cold state is associated with the logical execution history of
|
||||
the pier. It consists entirely of nouns and ignores restarts.
|
||||
|
||||
Warm state contains all dependencies between cold and hot
|
||||
state. It consists of C structures allocated on the loom (with
|
||||
`u3_post`, ie, a word pointer relative to the loom).
|
||||
state. It consists of C structures allocated on the loom.
|
||||
|
||||
Warm state is purely a function of cold and hot states, and
|
||||
we can wipe and regenerate it at any time. On any restart where
|
||||
@ -1080,8 +1103,8 @@ transfer both arguments and results.
|
||||
|
||||
### u3a: allocation functions
|
||||
|
||||
`u3a` allocates on the current road (u3R). Its internal structures
|
||||
are entirely uninteresting and typical of a naive allocator.
|
||||
`u3a` allocates on the current road (u3R). Its internal
|
||||
structures are uninteresting and typical of a naive allocator.
|
||||
|
||||
The two most-used `u3a` functions are `u3a_gain()` to add a
|
||||
reference count, and `u3a_lose()` to release one (and free the
|
||||
@ -1148,7 +1171,359 @@ atoms. When building atoms, please remember that it's incorrect
|
||||
to have a high 0 word - the word length in the atom structure
|
||||
must be strictly correct.
|
||||
|
||||
Of course, we don't always know how large our atom will be.
|
||||
Therefore, the standard way of building large atoms is to
|
||||
allocate a block of raw space with `u3a_slab()`, then chop off
|
||||
the end with `u3a_malt()` (which does the measuring itself)
|
||||
or `u3a_mint()` in case you've measured it yourself.
|
||||
|
||||
Once again, *do not call `malloc()`* (or C++ `new`) within any
|
||||
code that may be run within a jet. This will cause rare sporadic
|
||||
corruption when we interrupt execution within a `malloc()`. We'd
|
||||
just override the symbol, but `libuv` uses `malloc()` across
|
||||
threads within its own synchronization primitives - for this to
|
||||
work with `u3a_malloc()`, we'd have to introduce our own locks on
|
||||
the surface-level road (which might be a viable solution).
|
||||
|
||||
### u3n: nock execution
|
||||
|
||||
The `u3n` routines execute Nock itself. On the inside, they have
|
||||
a surprising resemblance to the spec proper (the only interesting
|
||||
detail is how we handle tail-call elimination) and are, as one
|
||||
would expect, quite slow. (There is no such thing as a fast tree
|
||||
interpreter.)
|
||||
|
||||
There is only one Nock, but there are lots of ways to call it.
|
||||
(Remember that all `u3n` functions *transfer* C arguments and
|
||||
returns.)
|
||||
|
||||
The simplest interpreter, `u3n_nock_on(u3_noun bus, u3_noun fol)`
|
||||
invokes Nock on `bus` (the subject) and `fol` (the formula).
|
||||
(Why is it`[subject formula]`, not `[formula subject]`? The same
|
||||
reason `0` is true and `1` is false.)
|
||||
|
||||
A close relative is `u3n_slam_on(u3_noun gat, u3_noun sam)`,
|
||||
which slams a *gate* (`gat`) on a sample (`sam`). (In a normal
|
||||
programming language which didn't talk funny and was retarded,
|
||||
`u3n_slam_on()` would call a function on an argument.) We could
|
||||
write it most simply as:
|
||||
|
||||
u3_noun
|
||||
u3n_slam_on(u3_noun gat, u3_noun sam)
|
||||
{
|
||||
u3_noun pro = u3n_nock_on
|
||||
(u3nc(u3k(u3h(gat)),
|
||||
u3nc(sam, u3k(u3t(u3t(gat))))),
|
||||
u3k(u3h(gat)));
|
||||
u3z(gat);
|
||||
return pro;
|
||||
}
|
||||
|
||||
Simpler is `u3n_kick_on(u3_noun gat)`, which slams a gate (or,
|
||||
more generally, a *trap* - because sample structure is not even
|
||||
needed here) without changing its sample:
|
||||
|
||||
u3_noun
|
||||
u3n_kick_on(u3_noun gat, u3_noun sam)
|
||||
{
|
||||
return u3n_nock_on(gat, u3k(u3h(gat)));
|
||||
}
|
||||
|
||||
The `_on` functions in `u3n` are all defined as pure Nock. But
|
||||
actually, even though we say we don't extend Nock, we do. But we
|
||||
don't. But we do.
|
||||
|
||||
Note that `u3` has a well-developed error handling system -
|
||||
`u3m_bail()` to throw an exception, `u3m_soft_*` to catch one.
|
||||
But Nock has no exception model at all. That's okay - all it
|
||||
means if that if an `_on` function bails, the exception is an
|
||||
exception in the caller.
|
||||
|
||||
However, `u3`'s exception handling happens to match a convenient
|
||||
virtual super-Nock in `hoon.hoon`, the infamous `++mock`. Of
|
||||
course, Nock is slow, and `mock` is Nock in Nock, so it is
|
||||
(logically) super-slow. Then again, so is decrement.
|
||||
|
||||
With the power of `u3`, we nest arbitrary layers of `mock`
|
||||
without any particular performance cost. Moreover, we simply
|
||||
treat Nock proper as a special case of `mock`. (More precisely,
|
||||
the internal VM loop is `++mink` and the error compiler is
|
||||
`++mook`. But we call the whole sandbox system `mock`.)
|
||||
|
||||
The nice thing about `mock` functions is that (by executing
|
||||
within `u3m_soft_run()`, which as you may recall uses a nested
|
||||
road) they provide both exceptions and the namespace operator -
|
||||
`.^` in Hoon, which becomes operator `11` in `mock`.
|
||||
|
||||
`11` requires a namespace function, or `fly`, which produces a
|
||||
`++unit` - `~` (`0`) for no binding, or `[0 value]`. The sample
|
||||
to a `fly` is a `++path`, just a list of text `span`.
|
||||
|
||||
`mock` functions produce a `++toon`. Fully elaborated:
|
||||
|
||||
++ noun ,* :: any noun
|
||||
++ path (list ,@ta) :: namespace path
|
||||
++ span ,@ta :: text-atom (ASCII)
|
||||
++ toon $% [%0 p=noun] :: success
|
||||
[%1 p=(list path)] :: blocking paths
|
||||
[%2 p=(list tank)] :: stack trace
|
||||
== ::
|
||||
++ tank :: printable
|
||||
$% [%leaf p=tape] :: flat text
|
||||
$: %palm :: backstep list
|
||||
p=[p=tape q=tape r=tape s=tape] :: mid cap open close
|
||||
q=(list tank) :: contents
|
||||
== ::
|
||||
$: %rose :: straight list
|
||||
p=[p=tape q=tape r=tape] :: mid open close
|
||||
q=(list tank) :: contents
|
||||
== ::
|
||||
==
|
||||
|
||||
(Note that `tank` is overdesigned and due for replacement.)
|
||||
|
||||
What does a `toon` mean? Either your computation succeded (`[0
|
||||
noun]`, or could not finish because it blocked on one or more
|
||||
global paths (`[1 (list path)]`), or it exited with a stack trace
|
||||
(`[2 (list tank)]`).
|
||||
|
||||
Note that of all the `u3` exceptions, only `%exit` is produced
|
||||
deterministically by the Nock definition. Therefore, only
|
||||
`%exit` produces a `2` result. Any other argument to
|
||||
`u3m_bail()` will unwind the virtualization stack all the way to
|
||||
the top - or to be more exact, to `u3m_soft_top()`.
|
||||
|
||||
In any case, the simplest `mock` functions are `u3n_nock_un()`
|
||||
and `u3n_slam_un()`. These provide exception control without
|
||||
any namespace change, as you can see by the code:
|
||||
|
||||
/* u3n_nock_un(): produce .*(bus fol), as ++toon.
|
||||
*/
|
||||
u3_noun
|
||||
u3n_nock_un(u3_noun bus, u3_noun fol)
|
||||
{
|
||||
u3_noun fly = u3nt(u3nt(11, 0, 6), 0, 0); // |=(a=* .^(a))
|
||||
|
||||
return u3n_nock_in(fly, bus, fol);
|
||||
}
|
||||
|
||||
/* u3n_slam_un(): produce (gat sam), as ++toon.
|
||||
*/
|
||||
u3_noun
|
||||
u3n_slam_un(u3_noun gat, u3_noun sam)
|
||||
{
|
||||
u3_noun fly = u3nt(u3nt(11, 0, 6), 0, 0); // |=(a=* .^(a))
|
||||
|
||||
return u3n_slam_in(fly, gat, sam);
|
||||
}
|
||||
|
||||
The `fly` is added as the first argument to `u3n_nock_in()` and
|
||||
`u3n_slam_in()`. Of course, logically, `fly` executes in the
|
||||
caller's exception layer. (Maintaining this illusion is slightly
|
||||
nontrivial.) Finally, `u3n_nock_an()` is a sandbox with a null
|
||||
namespace.
|
||||
|
||||
### u3e: persistence
|
||||
|
||||
The only `u3e` function you should need to call is `u3e_save()`,
|
||||
which saves the loom. As it can be restored on any platform,
|
||||
please make sure you don't have any state in the loom that is
|
||||
bound to your process or architecture - except for exceptions
|
||||
like the warm jet state, which is actively purged on reboot.
|
||||
|
||||
### u3r: reading nouns (weak)
|
||||
|
||||
As befits accessors they don't make anything, `u3r` noun reading
|
||||
functions always retain their arguments and their returns. They
|
||||
never bail; rather, when they don't work, they return a `u3_weak`
|
||||
result.
|
||||
|
||||
Most of these functions are straightforward and do only what
|
||||
their comments say. A few are interesting enough to discuss.
|
||||
|
||||
`u3r_at()` is the familiar tree fragment function, `/` from the
|
||||
Nock spec. For taking complex nouns apart, `u3r_mean()` is a
|
||||
relatively funky way of deconstructing nouns with a varargs list
|
||||
of `axis`, `u3_noun *`. For cells, triples, etc, decompose with
|
||||
`u3r_cell()`, `u3r_trel()`, etc. For the tagged equivalents, use
|
||||
`u3r_pq()` and friends.
|
||||
|
||||
`u3r_sing(u3_noun a, u3_noun b)` (true if `a` and `b` are a
|
||||
*single* noun) are interesting because it uses mugs to help it
|
||||
out. Clearly, different nouns may have the same mug, but the
|
||||
same nouns cannot have a different mug. It's important to
|
||||
understand the performance characteristics of `u3r_sing()`:
|
||||
the worst possible case is a comparison of duplicate nouns,
|
||||
which have the same value but were created separately. In this
|
||||
case, the tree is traversed
|
||||
|
||||
`u3r_sung()` is a deeply funky and frightening version of
|
||||
`u3r_sing()` that unifies pointers to the duplicate nouns it
|
||||
finds, freeing the second copy. Obviously, do not use
|
||||
`u3r_sung()` when you have live, but not reference counted, noun
|
||||
references from C - if they match a noun with a refcount of 1
|
||||
that gets freed, bad things happen.
|
||||
|
||||
It's important to remember that `u3r_mug()`, which produces a
|
||||
31-bit, nonzero insecure hash, uses the `mug_w` slot in any boxed
|
||||
noun as a lazy cache. There are a number of variants of
|
||||
`u3r_mug()` that can get you out of building unneeded nouns.
|
||||
|
||||
### u3x: reading nouns (bail)
|
||||
|
||||
`u3x` functions are like `u3r` functions, but instead of
|
||||
returning `u3_none` when (for instance) we try to take the head
|
||||
of an atom, they bail with `%exit`. In other words, they do what
|
||||
the same operation would do in Nock.
|
||||
|
||||
### u3h: hash tables.
|
||||
|
||||
We can of course use the Hoon `map` structure as an associative
|
||||
array. This is a balanced treap and reasonably fast. However,
|
||||
it's considerably inferior to a custom structure like an HAMT
|
||||
(hash array-mapped trie). We use `u3_post` to allocate HAMT
|
||||
structures on the loom.
|
||||
|
||||
(Our HAMT implements the classic Bagwell algorithm which depends
|
||||
on the `gcc` standard directive `__builtin_popcount()`. On a CPU
|
||||
which doesn't support popcount or an equivalent instruction, some
|
||||
other design would probably be preferable.)
|
||||
|
||||
There's no particular rocket science in the API. `u3h_new()`
|
||||
creates a hashtable; `u3h_free()` destroys one; `u3h_put()`
|
||||
inserts, `u3h_get()` retrieves. You can transform values in a
|
||||
hashtable with `u3h_walk()`.
|
||||
|
||||
The only funky function is `u3h_gut()`, which unifies keys with
|
||||
`u3r_sung()`. As with all cases of `u3r_sung()`, this must be
|
||||
used with extreme caution.
|
||||
|
||||
### u3z: memoization
|
||||
|
||||
Connected to the `~+` rune in Hoon, via the Nock `%memo` hint,
|
||||
the memoization facility is a general-purpose cache.
|
||||
|
||||
(It's also used for partial memoization - a feature that'll
|
||||
probably be removed, in which conservative worklist algorithms
|
||||
(which would otherwise be exponential) memoize everything in the
|
||||
subject *except* the worklist. This is used heavily in the Hoon
|
||||
compiler jets (j/f/*.c). Unfortunately, it's probably not
|
||||
possible to make this work perfectly in that it can't be abused
|
||||
to violate Nock, so we'll probably remove it at a later date,
|
||||
instead making `++ut` keep its own monadic cache.)
|
||||
|
||||
Each `u3z` function comes with a `c3_m` mote which disambiguates
|
||||
the function mapping key to value. For Nock itself, use 0. For
|
||||
extra speed, small tuples are split out in C; thus, find with
|
||||
|
||||
u3_weak u3z_find(c3_m, u3_noun);
|
||||
u3_weak u3z_find_2(c3_m, u3_noun, u3_noun);
|
||||
u3_weak u3z_find_3(c3_m, u3_noun, u3_noun, u3_noun);
|
||||
u3_weak u3z_find_4(c3_m, u3_noun, u3_noun, u3_noun, u3_noun);
|
||||
|
||||
and save with
|
||||
|
||||
u3_noun u3z_save(c3_m, u3_noun, u3_noun);
|
||||
u3_noun u3z_save_2(c3_m, u3_noun, u3_noun, u3_noun);
|
||||
u3_noun u3z_save_3(c3_m, u3_noun, u3_noun, u3_noun, u3_noun);
|
||||
u3_noun u3z_save_4(c3_m, u3_noun, u3_noun, u3_noun, u3_noun, u3_noun);
|
||||
|
||||
where the value is the last argument. To eliminate duplicate
|
||||
nouns, there is also
|
||||
|
||||
u3_noun
|
||||
u3z_uniq(u3_noun);
|
||||
|
||||
`u3z` functions retain keys and transfer values.
|
||||
|
||||
The `u3z` cache, built on `u3h` hashes, is part of the current
|
||||
road, and goes away when it goes away. (In future, we may wish
|
||||
to promote keys/values which outlive the road, as we do with jet
|
||||
state.) There is no cache reclamation at present, so be careful.
|
||||
|
||||
### u3t: tracing and profiling.
|
||||
|
||||
TBD.
|
||||
|
||||
### u3v: the Arvo kernel
|
||||
|
||||
An Arvo kernel - or at least, a core that compiles with the Arvo
|
||||
interface - is part of the global `u3` state. What is an Arvo
|
||||
core? Slightly pseudocoded:
|
||||
|
||||
++ arvo
|
||||
|%
|
||||
++ come |= [yen=@ ova=(list ovum) nyf=pone] :: 11
|
||||
^- [(list ovum) _+>]
|
||||
!!
|
||||
++ keep |= [now=@da hap=path] :: 4
|
||||
^- (unit ,@da)
|
||||
!!
|
||||
++ load |= [yen=@ ova=(list ovum) nyf=pane] :: 86
|
||||
^- [(list ovum) _+>]
|
||||
!!
|
||||
++ peek |= [now=@da path] :: 87
|
||||
^- (unit)
|
||||
!!
|
||||
++ poke |= [now=@da ovo=ovum] :: 42
|
||||
^- [(list ovum) _+>]
|
||||
!!
|
||||
++ wish |= txt=@ta :: 20
|
||||
^- *
|
||||
!!
|
||||
--
|
||||
++ card ,[p=@tas q=*] :: typeless card
|
||||
++ ovum ,[p=wire q=card] :: Arvo event
|
||||
++ wire path :: event cause
|
||||
|
||||
This is the Arvo ABI in a very real sense. Arvo is a core with
|
||||
these six arms. To use these arms, we hardcode the axis of the
|
||||
formula (`11`, `4`, `86`, etc) into the C code that calls Arvo,
|
||||
because otherwise we'd need type metadata - which we can get, by
|
||||
calling Arvo.
|
||||
|
||||
It's important to understand the Arvo event/action structure, or
|
||||
`++ovum`. An `ovum` is a `card`, which is any `[term noun]`
|
||||
cell, and a `++wire`, a `path` which indicates the location of
|
||||
the event. At the Unix level, the `wire` corresponds to a system
|
||||
module or context. For input events, this is the module that
|
||||
caused the event; for output actions, it's the module that
|
||||
performs the action.
|
||||
|
||||
`++poke` sends Arvo an event `ovum`, producing a cell of action
|
||||
ova and a new Arvo core.
|
||||
|
||||
`++peek` dereferences the Arvo namespace. It takes a date and a
|
||||
key, and produces `~` (`0`) or `[~ value]`.
|
||||
|
||||
`++keep` asks Arvo the next time it wants to be woken up, for the
|
||||
given `wire`. (This input will probably be eliminated in favor
|
||||
of a single global timer.)
|
||||
|
||||
`++wish` compiles a string of Hoon source. While just a
|
||||
convenience, it's a very convenient convenience.
|
||||
|
||||
`++come` and `++load` are used by Arvo to reset itself (more
|
||||
precisely, to shift the Arvo state from an old kernel to a new
|
||||
one); there is no need to call them from C.
|
||||
|
||||
Now that we understand the Arvo kernel interface, let's look at
|
||||
the `u3v` API. As usual, all the functions in `u3v` are
|
||||
commented, but unfortunately it's hard to describe this API as
|
||||
clean at present. The problem is that `u3v` remains design
|
||||
coupled to the old `vere` event handling code written for `u2`.
|
||||
But let's describe the functions you should be calling, assuming
|
||||
you're not writing the next event system. There are only two.
|
||||
|
||||
`u3v_wish(str_c)` wraps the `++wish` functionality in a cache
|
||||
(which is read-only unless you're on the surface road).
|
||||
|
||||
`u3v_do()` uses `wish` to provide a convenient interface for
|
||||
calling Hoon kernel functions by name. Even more conveniently,
|
||||
we tend to call `u3v_do()` with these convenient aliases:
|
||||
|
||||
#define u3do(txt_c, arg) u3v_do(txt_c, arg)
|
||||
#define u3dc(txt_c, a, b) u3v_do(txt_c, u3nc(a, b))
|
||||
#define u3dt(txt_c, a, b, c) u3v_do(txt_c, u3nt(a, b, c))
|
||||
#define u3dq(txt_c, a, b, c, d) u3v_do(txt_c, u3nt(a, b, c, d))
|
||||
|
||||
###
|
||||
|
7
i/n/a.h
7
i/n/a.h
@ -207,9 +207,6 @@
|
||||
# define u3a_into(x) ((void *)(u3_Loom + (x)))
|
||||
# define u3a_outa(p) (((c3_w*)(void*)(p)) - u3_Loom)
|
||||
|
||||
# define u3to(type, x) ((type *) u3a_into(x))
|
||||
# define u3of(type, x) (u3a_outa((type *)x))
|
||||
|
||||
# define u3a_is_north(r) __(r->cap_p > r->hat_p)
|
||||
# define u3a_is_south(r) !u3a_is_north(r)
|
||||
|
||||
@ -369,7 +366,7 @@
|
||||
/* u3a_sweep(): sweep a fully marked road.
|
||||
*/
|
||||
void
|
||||
u3a_sweep(c3_c* cap_c);
|
||||
u3a_sweep(void);
|
||||
|
||||
/* u3a_sane(): check allocator sanity.
|
||||
*/
|
||||
@ -398,7 +395,7 @@
|
||||
c3_w*
|
||||
u3a_slab(c3_w len_w);
|
||||
|
||||
/* u3a_slaq(): u3a_slaq() with a defined blocksize.
|
||||
/* u3a_slaq(): u3a_slab() with a defined blocksize.
|
||||
*/
|
||||
c3_w*
|
||||
u3a_slaq(c3_g met_g, c3_w len_w);
|
||||
|
15
i/n/e.h
15
i/n/e.h
@ -73,21 +73,6 @@
|
||||
c3_o
|
||||
u3e_live(c3_o nuu_o, c3_c* dir_c);
|
||||
|
||||
/* u3e_boot(): start the u3 system.
|
||||
*/
|
||||
void
|
||||
u3e_boot(c3_o nuu_o, c3_o bug_o, c3_c* dir_c);
|
||||
|
||||
/* u3e_init(): start the environment, with/without checkpointing.
|
||||
*/
|
||||
void
|
||||
u3e_init(c3_o chk_o);
|
||||
|
||||
/* u3e_grab(): garbage-collect the world, plus extra roots.
|
||||
*/
|
||||
void
|
||||
u3e_grab(c3_c* cap_c, u3_noun som, ...); // terminate with u3_none
|
||||
|
||||
/* u3e_dirty(): count dirty pages.
|
||||
*/
|
||||
c3_w
|
||||
|
5
i/n/m.h
5
i/n/m.h
@ -81,6 +81,11 @@
|
||||
u3_noun
|
||||
u3m_soft_esc(u3_noun sam);
|
||||
|
||||
/* u3m_grab(): garbage-collect the world, plus extra roots.
|
||||
*/
|
||||
void
|
||||
u3m_grab(u3_noun som, ...); // terminate with u3_none
|
||||
|
||||
/* u3m_water(): produce high and low watermarks. Asserts u3R == u3H.
|
||||
*/
|
||||
void
|
||||
|
174
i/n/r.h
174
i/n/r.h
@ -22,8 +22,7 @@
|
||||
/* u3r_at(): fragment `a` of `b`, or u3_none.
|
||||
*/
|
||||
u3_weak
|
||||
u3r_at(u3_atom a,
|
||||
u3_weak b);
|
||||
u3r_at(u3_atom a, u3_weak b);
|
||||
|
||||
/* u3r_mean():
|
||||
**
|
||||
@ -31,8 +30,7 @@
|
||||
** Axes must be sorted in tree order.
|
||||
*/
|
||||
c3_o
|
||||
u3r_mean(u3_noun a,
|
||||
...);
|
||||
u3r_mean(u3_noun a, ...);
|
||||
|
||||
/* u3r_mug():
|
||||
**
|
||||
@ -54,7 +52,7 @@
|
||||
*/
|
||||
c3_w
|
||||
u3r_mug_words(const c3_w *buf_w,
|
||||
c3_w len_w);
|
||||
c3_w len_w);
|
||||
|
||||
/* u3r_mug_cell():
|
||||
**
|
||||
@ -62,7 +60,7 @@
|
||||
*/
|
||||
c3_w
|
||||
u3r_mug_cell(u3_noun a,
|
||||
u3_noun b);
|
||||
u3_noun b);
|
||||
|
||||
/* u3r_mug_trel():
|
||||
**
|
||||
@ -70,8 +68,8 @@
|
||||
*/
|
||||
c3_w
|
||||
u3r_mug_trel(u3_noun a,
|
||||
u3_noun b,
|
||||
u3_noun c);
|
||||
u3_noun b,
|
||||
u3_noun c);
|
||||
|
||||
/* u3r_mug_qual():
|
||||
**
|
||||
@ -79,9 +77,9 @@
|
||||
*/
|
||||
c3_w
|
||||
u3r_mug_qual(u3_noun a,
|
||||
u3_noun b,
|
||||
u3_noun c,
|
||||
u3_noun d);
|
||||
u3_noun b,
|
||||
u3_noun c,
|
||||
u3_noun d);
|
||||
|
||||
/* u3r_mug_both():
|
||||
**
|
||||
@ -98,7 +96,7 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_fing(u3_noun a,
|
||||
u3_noun b);
|
||||
u3_noun b);
|
||||
|
||||
/* u3r_fing_cell():
|
||||
**
|
||||
@ -106,8 +104,8 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_fing_cell(u3_noun p,
|
||||
u3_noun q,
|
||||
u3_noun b);
|
||||
u3_noun q,
|
||||
u3_noun b);
|
||||
|
||||
/* u3r_fing_mixt():
|
||||
**
|
||||
@ -115,8 +113,8 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_fing_mixt(const c3_c* p_c,
|
||||
u3_noun q,
|
||||
u3_noun b);
|
||||
u3_noun q,
|
||||
u3_noun b);
|
||||
|
||||
/* u3r_fing_trel():
|
||||
**
|
||||
@ -124,9 +122,9 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_fing_trel(u3_noun p,
|
||||
u3_noun q,
|
||||
u3_noun r,
|
||||
u3_noun b);
|
||||
u3_noun q,
|
||||
u3_noun r,
|
||||
u3_noun b);
|
||||
|
||||
/* u3r_fing_qual():
|
||||
**
|
||||
@ -134,18 +132,17 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_fing_qual(u3_noun p,
|
||||
u3_noun q,
|
||||
u3_noun r,
|
||||
u3_noun s,
|
||||
u3_noun b);
|
||||
u3_noun q,
|
||||
u3_noun r,
|
||||
u3_noun s,
|
||||
u3_noun b);
|
||||
|
||||
/* u3r_sing():
|
||||
**
|
||||
** Yes iff (a) and (b) are the same noun.
|
||||
*/
|
||||
c3_o
|
||||
u3r_sing(u3_noun a,
|
||||
u3_noun b);
|
||||
u3r_sing(u3_noun a, u3_noun b);
|
||||
|
||||
/* u3r_sung(): yes iff (a) and (b) are the same noun, unifying equals.
|
||||
**
|
||||
@ -153,8 +150,7 @@
|
||||
** within (a) or (b)!
|
||||
*/
|
||||
c3_o
|
||||
u3r_sung(u3_noun a,
|
||||
u3_noun b);
|
||||
u3r_sung(u3_noun a, u3_noun b);
|
||||
|
||||
/* u3r_sing_c):
|
||||
**
|
||||
@ -162,7 +158,7 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_sing_c(const c3_c* a_c,
|
||||
u3_noun b);
|
||||
u3_noun b);
|
||||
|
||||
/* u3r_sing_cell():
|
||||
**
|
||||
@ -170,8 +166,8 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_sing_cell(u3_noun p,
|
||||
u3_noun q,
|
||||
u3_noun b);
|
||||
u3_noun q,
|
||||
u3_noun b);
|
||||
|
||||
/* u3r_sing_mixt():
|
||||
**
|
||||
@ -179,8 +175,8 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_sing_mixt(const c3_c* p_c,
|
||||
u3_noun q,
|
||||
u3_noun b);
|
||||
u3_noun q,
|
||||
u3_noun b);
|
||||
|
||||
/* u3r_sing_trel():
|
||||
**
|
||||
@ -188,9 +184,9 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_sing_trel(u3_noun p,
|
||||
u3_noun q,
|
||||
u3_noun r,
|
||||
u3_noun b);
|
||||
u3_noun q,
|
||||
u3_noun r,
|
||||
u3_noun b);
|
||||
|
||||
/* u3r_sing_qual():
|
||||
**
|
||||
@ -198,10 +194,10 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_sing_qual(u3_noun p,
|
||||
u3_noun q,
|
||||
u3_noun r,
|
||||
u3_noun s,
|
||||
u3_noun b);
|
||||
u3_noun q,
|
||||
u3_noun r,
|
||||
u3_noun s,
|
||||
u3_noun b);
|
||||
|
||||
/* u3r_nord():
|
||||
**
|
||||
@ -209,7 +205,7 @@
|
||||
*/
|
||||
u3_atom
|
||||
u3r_nord(u3_noun a,
|
||||
u3_noun b);
|
||||
u3_noun b);
|
||||
|
||||
/* u3r_mold():
|
||||
**
|
||||
@ -217,8 +213,8 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_mold(u3_noun a,
|
||||
u3_noun* b,
|
||||
u3_noun* c);
|
||||
u3_noun* b,
|
||||
u3_noun* c);
|
||||
|
||||
/* u3r_cell():
|
||||
**
|
||||
@ -226,8 +222,8 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_cell(u3_noun a,
|
||||
u3_noun* b,
|
||||
u3_noun* c);
|
||||
u3_noun* b,
|
||||
u3_noun* c);
|
||||
|
||||
/* u3r_trel():
|
||||
**
|
||||
@ -235,9 +231,9 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_trel(u3_noun a,
|
||||
u3_noun* b,
|
||||
u3_noun* c,
|
||||
u3_noun* d);
|
||||
u3_noun* b,
|
||||
u3_noun* c,
|
||||
u3_noun* d);
|
||||
|
||||
/* u3r_qual():
|
||||
**
|
||||
@ -245,10 +241,10 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_qual(u3_noun a,
|
||||
u3_noun* b,
|
||||
u3_noun* c,
|
||||
u3_noun* d,
|
||||
u3_noun* e);
|
||||
u3_noun* b,
|
||||
u3_noun* c,
|
||||
u3_noun* d,
|
||||
u3_noun* e);
|
||||
|
||||
/* u3r_quil():
|
||||
**
|
||||
@ -256,11 +252,11 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_quil(u3_noun a,
|
||||
u3_noun* b,
|
||||
u3_noun* c,
|
||||
u3_noun* d,
|
||||
u3_noun* e,
|
||||
u3_noun* f);
|
||||
u3_noun* b,
|
||||
u3_noun* c,
|
||||
u3_noun* d,
|
||||
u3_noun* e,
|
||||
u3_noun* f);
|
||||
|
||||
/* u3r_p():
|
||||
**
|
||||
@ -268,8 +264,8 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_p(u3_noun a,
|
||||
u3_noun b,
|
||||
u3_noun* c);
|
||||
u3_noun b,
|
||||
u3_noun* c);
|
||||
|
||||
/* u3r_bush():
|
||||
**
|
||||
@ -277,8 +273,8 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_bush(u3_noun a,
|
||||
u3_noun* b,
|
||||
u3_noun* c);
|
||||
u3_noun* b,
|
||||
u3_noun* c);
|
||||
|
||||
/* u3r_pq():
|
||||
**
|
||||
@ -286,9 +282,9 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_pq(u3_noun a,
|
||||
u3_noun b,
|
||||
u3_noun* c,
|
||||
u3_noun* d);
|
||||
u3_noun b,
|
||||
u3_noun* c,
|
||||
u3_noun* d);
|
||||
|
||||
/* u3r_pqr():
|
||||
**
|
||||
@ -296,10 +292,10 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_pqr(u3_noun a,
|
||||
u3_noun b,
|
||||
u3_noun* c,
|
||||
u3_noun* d,
|
||||
u3_noun* e);
|
||||
u3_noun b,
|
||||
u3_noun* c,
|
||||
u3_noun* d,
|
||||
u3_noun* e);
|
||||
|
||||
/* u3r_pqrs():
|
||||
**
|
||||
@ -307,11 +303,11 @@
|
||||
*/
|
||||
c3_o
|
||||
u3r_pqrs(u3_noun a,
|
||||
u3_noun b,
|
||||
u3_noun* c,
|
||||
u3_noun* d,
|
||||
u3_noun* e,
|
||||
u3_noun* f);
|
||||
u3_noun b,
|
||||
u3_noun* c,
|
||||
u3_noun* d,
|
||||
u3_noun* e,
|
||||
u3_noun* f);
|
||||
|
||||
/* u3r_met():
|
||||
**
|
||||
@ -322,7 +318,7 @@
|
||||
*/
|
||||
c3_w
|
||||
u3r_met(c3_y a_y,
|
||||
u3_atom b);
|
||||
u3_atom b);
|
||||
|
||||
/* u3r_bit():
|
||||
**
|
||||
@ -330,7 +326,7 @@
|
||||
*/
|
||||
c3_b
|
||||
u3r_bit(c3_w a_w,
|
||||
u3_atom b);
|
||||
u3_atom b);
|
||||
|
||||
/* u3r_byte():
|
||||
**
|
||||
@ -338,7 +334,7 @@
|
||||
*/
|
||||
c3_y
|
||||
u3r_byte(c3_w a_w,
|
||||
u3_atom b);
|
||||
u3_atom b);
|
||||
|
||||
/* u3r_bytes():
|
||||
**
|
||||
@ -346,9 +342,9 @@
|
||||
*/
|
||||
void
|
||||
u3r_bytes(c3_w a_w,
|
||||
c3_w b_w,
|
||||
c3_y* c_y,
|
||||
u3_atom d);
|
||||
c3_w b_w,
|
||||
c3_y* c_y,
|
||||
u3_atom d);
|
||||
|
||||
/* u3r_chop():
|
||||
**
|
||||
@ -358,11 +354,11 @@
|
||||
*/
|
||||
void
|
||||
u3r_chop(c3_g met_g,
|
||||
c3_w fum_w,
|
||||
c3_w wid_w,
|
||||
c3_w tou_w,
|
||||
c3_w* dst_w,
|
||||
u3_atom src);
|
||||
c3_w fum_w,
|
||||
c3_w wid_w,
|
||||
c3_w tou_w,
|
||||
c3_w* dst_w,
|
||||
u3_atom src);
|
||||
|
||||
/* u3r_mp():
|
||||
**
|
||||
@ -370,7 +366,7 @@
|
||||
*/
|
||||
void
|
||||
u3r_mp(mpz_t a_mp,
|
||||
u3_atom b);
|
||||
u3_atom b);
|
||||
|
||||
/* u3r_word():
|
||||
**
|
||||
@ -378,7 +374,7 @@
|
||||
*/
|
||||
c3_w
|
||||
u3r_word(c3_w a_w,
|
||||
u3_atom b);
|
||||
u3_atom b);
|
||||
|
||||
/* u3r_chub():
|
||||
**
|
||||
@ -386,7 +382,7 @@
|
||||
*/
|
||||
c3_d
|
||||
u3r_chub(c3_w a_w,
|
||||
u3_atom b);
|
||||
u3_atom b);
|
||||
|
||||
/* u3r_words():
|
||||
**
|
||||
@ -394,9 +390,9 @@
|
||||
*/
|
||||
void
|
||||
u3r_words(c3_w a_w,
|
||||
c3_w b_w,
|
||||
c3_w* c_w,
|
||||
u3_atom d);
|
||||
c3_w b_w,
|
||||
c3_w* c_w,
|
||||
u3_atom d);
|
||||
|
||||
/* u3r_string(): `a`, a text atom, as malloced C string.
|
||||
*/
|
||||
|
6
i/n/u.h
6
i/n/u.h
@ -100,3 +100,9 @@
|
||||
# define u3dc(txt_c, a, b) u3v_do(txt_c, u3nc(a, b))
|
||||
# define u3dt(txt_c, a, b, c) u3v_do(txt_c, u3nt(a, b, c))
|
||||
# define u3dq(txt_c, a, b, c, d) u3v_do(txt_c, u3nt(a, b, c, d))
|
||||
|
||||
/* u3to(), u3of(): offset/pointer conversion.
|
||||
*/
|
||||
# define u3to(type, x) ((type *) u3a_into(x))
|
||||
# define u3of(type, x) (u3a_outa((type *)x))
|
||||
|
||||
|
12
i/n/v.h
12
i/n/v.h
@ -9,10 +9,10 @@
|
||||
struct _u3v_arvo;
|
||||
|
||||
typedef struct _u3v_cart {
|
||||
u3_noun vir; // effects of ovum
|
||||
c3_o did; // cart considered for commit?
|
||||
c3_o cit; // cart committed?
|
||||
c3_d ent_d; // entry in raft queue?
|
||||
u3_noun vir; // effects of ovum
|
||||
c3_o did; // cart considered for commit?
|
||||
c3_o cit; // cart committed?
|
||||
c3_d ent_d; // event number
|
||||
u3p(struct _u3v_cart) nex_p;
|
||||
} u3v_cart;
|
||||
|
||||
@ -34,8 +34,8 @@
|
||||
u3_noun roc; // kernel core
|
||||
|
||||
struct { // ova waiting to process
|
||||
u3p(u3v_cart) egg_p; // exit of ovum queue
|
||||
u3p(u3v_cart) geg_p; // entry of ovum queue
|
||||
u3p(u3v_cart) egg_p; // exit of ovum queue
|
||||
u3p(u3v_cart) geg_p; // entry of ovum queue
|
||||
} ova;
|
||||
} u3v_arvo;
|
||||
|
||||
|
8
n/a.c
8
n/a.c
@ -1325,7 +1325,7 @@ u3a_print_memory(c3_c* cap_c, c3_w wor_w)
|
||||
/* u3a_sweep(): sweep a fully marked road.
|
||||
*/
|
||||
void
|
||||
u3a_sweep(c3_c* cap_c)
|
||||
u3a_sweep(void)
|
||||
{
|
||||
c3_w neg_w, pos_w, leq_w, weq_w, tot_w, caf_w;
|
||||
|
||||
@ -1493,10 +1493,10 @@ u3a_malt(c3_w* sal_w)
|
||||
u3_noun
|
||||
u3a_moot(c3_w* sal_w)
|
||||
{
|
||||
c3_w* nov_w = (sal_w - c3_wiseof(u3a_atom));
|
||||
c3_w* nov_w = (sal_w - c3_wiseof(u3a_atom));
|
||||
u3a_atom* nov_u = (void*)nov_w;
|
||||
c3_w len_w = nov_u->len_w;
|
||||
c3_w las_w = nov_u->buf_w[len_w - 1];
|
||||
c3_w len_w = nov_u->len_w;
|
||||
c3_w las_w = nov_u->buf_w[len_w - 1];
|
||||
|
||||
c3_assert(0 != len_w);
|
||||
c3_assert(0 != las_w);
|
||||
|
60
n/m.c
60
n/m.c
@ -827,7 +827,7 @@ u3m_soft_top(c3_w sec_w, // timer seconds
|
||||
/* Make sure the inner routine did not create garbage.
|
||||
*/
|
||||
if ( u3R->how.fag_w & u3a_flag_debug ) {
|
||||
u3e_grab("top", pro, u3_none);
|
||||
u3m_grab(pro, u3_none);
|
||||
}
|
||||
|
||||
/* Revert to external signal regime.
|
||||
@ -917,7 +917,7 @@ u3m_soft_run(u3_noun fly,
|
||||
pro = fun_f(aga, agb);
|
||||
|
||||
if ( u3R->how.fag_w & u3a_flag_debug ) {
|
||||
u3e_grab("top", pro, u3_none);
|
||||
u3m_grab(pro, u3_none);
|
||||
}
|
||||
|
||||
/* Produce success, on the old road.
|
||||
@ -1024,6 +1024,34 @@ u3m_soft_esc(u3_noun sam)
|
||||
return pro;
|
||||
}
|
||||
|
||||
/* u3m_grab(): garbage-collect the world, plus extra roots.
|
||||
*/
|
||||
void
|
||||
u3m_grab(u3_noun som, ...) // terminate with u3_none
|
||||
{
|
||||
// u3h_free(u3R->cax.har_p);
|
||||
// u3R->cax.har_p = u3h_new();
|
||||
|
||||
u3v_mark();
|
||||
u3m_mark();
|
||||
{
|
||||
va_list vap;
|
||||
u3_noun tur;
|
||||
|
||||
va_start(vap, som);
|
||||
|
||||
if ( som != u3_none ) {
|
||||
u3a_mark_noun(som);
|
||||
|
||||
while ( u3_none != (tur = va_arg(vap, u3_noun)) ) {
|
||||
u3a_mark_noun(tur);
|
||||
}
|
||||
}
|
||||
va_end(vap);
|
||||
}
|
||||
u3a_sweep();
|
||||
}
|
||||
|
||||
/* u3m_soft(): top-level wrapper.
|
||||
**
|
||||
** Produces [0 product] or [%error (list tank)], top last.
|
||||
@ -1372,34 +1400,6 @@ _cm_init(c3_o chk_o)
|
||||
}
|
||||
}
|
||||
|
||||
/* u3e_grab(): garbage-collect the world, plus extra roots, then
|
||||
*/
|
||||
void
|
||||
u3e_grab(c3_c* cap_c, u3_noun som, ...) // terminate with u3_none
|
||||
{
|
||||
// u3h_free(u3R->cax.har_p);
|
||||
// u3R->cax.har_p = u3h_new();
|
||||
|
||||
u3v_mark();
|
||||
u3m_mark();
|
||||
{
|
||||
va_list vap;
|
||||
u3_noun tur;
|
||||
|
||||
va_start(vap, som);
|
||||
|
||||
if ( som != u3_none ) {
|
||||
u3a_mark_noun(som);
|
||||
|
||||
while ( u3_none != (tur = va_arg(vap, u3_noun)) ) {
|
||||
u3a_mark_noun(tur);
|
||||
}
|
||||
}
|
||||
va_end(vap);
|
||||
}
|
||||
u3a_sweep(cap_c);
|
||||
}
|
||||
|
||||
/* u3m_boot(): start the u3 system.
|
||||
*/
|
||||
void
|
||||
|
4
v/loop.c
4
v/loop.c
@ -420,7 +420,7 @@ u3_lo_open(void)
|
||||
if ( (u3H->rod_u.how.fag_w & u3a_flag_gc) ||
|
||||
(u3H->rod_u.how.fag_w & u3a_flag_debug) )
|
||||
{
|
||||
u3e_grab("lo_open", u3_none);
|
||||
u3m_grab(u3_none);
|
||||
}
|
||||
_lo_time();
|
||||
}
|
||||
@ -430,7 +430,7 @@ u3_lo_open(void)
|
||||
void
|
||||
u3_lo_shut(c3_o inn)
|
||||
{
|
||||
// u3e_grab("lo_shut a", u3_none);
|
||||
// u3m_grab(u3_none);
|
||||
|
||||
// process actions
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user