Skip to content

Instantly share code, notes, and snippets.

@Fang-
Created July 13, 2018 13:48
Show Gist options
  • Save Fang-/0149b5b5558847f8b9d8342756e994ea to your computer and use it in GitHub Desktop.
Save Fang-/0149b5b5558847f8b9d8342756e994ea to your computer and use it in GitHub Desktop.
Explained by a vere noob.

First off, general u3/vere docs are here. They feel pretty opaque, and Paul/~fodwyt, an experienced vere dev, has admitted to reading them every so often and still bringing back new understanding of the doc each time. I suggest to skim it, most of it isn't exactly relevant, but do read the sections on reference counts and reference protocols.

For a quick overview on what goes into adding a jet, see this commit as an example. (Matching Hoon change is here though only the use of ~% and ~/ is of interest.)

Jet registration

To get your jet called whenever the matching Hoon code is called, that code needs to be hinted. Use ~/ and sometimes ~% for this. hoon.hoon and zuse.hoon contain plenty examples on how to do this. Generally, for core jets, do whatever your neighboring arms are doing. Then, for gate jets, do whatever similar-looking cores are doing. ~/ is usually fine for the gates themselves.

Jets are registered in /jets/tree.c. The general patter you'll observe is that a u3j_harm is created for each jetted arm, and that those are then collected in a u3j_core which matches the (jetted) core they're in in the Hoon code.
".2" says what we're jetting lives at axis 2 (of what was hinted?). This is followed by the w version of the jet (see below). Optionally, also put c3n behind the function to indicate the jet needs to be tested. When this is done, the Hoon code will be run alongside the jet, and vere will crash if the results don't match. Turn this off before committing.

Reference counting, jet variants

Remember how I mentioned reading up on reference counting above? When writing jet code, that comes into play.
To increment the reference count, we "keep" a u3_noun or u3_atom using u3k(the_thing).
To decrement the reference count, we "lose" a u3_noun or u3_atom using u3z(the_thing).

There's three versions of your jet functions you can write:

  • q: These are gonna be the meat of your jet. Their function signature often closely resembles that of the Hoon code, and the logic performed within should produce an identical result. You should not lose any references to your arguments, but you should make sure to lose all nouns/atoms you create during the logic, except for the one you're returning. This also holds true for nouns you're not explicitly storing in a variable, but just pass directly into a function. The difference between q and k comes into play here.
  • k: These have the same function signature as q, except they promise to lose a reference to all the arguments. These are implemented by calling the q version, storing the result in a u3_noun, calling u3z() on all arguments, and then returning the stored result.
  • w: These take a single argument, u3_noun cor, and are tasked with unpacking that noun into individual arguments, using which it will call q. For this, use u3r_mean() for unpacking multiple values at once, or u3x_at() for an individual value. xtract.h might be useful in some cases, though it seems u3r_mean() is most common. For each version of the jet you write, be sure to add it to /include/jets/x.c where x is the version you wrote. You will always be writing w and q versions. k is entirely optional, and generally best to only add when it turns out you need it somewhere (for ref-counting convenience).

u3-style C code

When dealing with u3_atoms, they can either be pointers (in the case of bignums) or direct values (aka "cat"s, in the case of ints that fit in 31 bits). You may want to c3_assert(_(u3a_is_cat(my_atom))) in cases where larger values are not expected and doing C-style arithmatic on the value would be easier. Don't even think about doing C-style addition etc on non-cat atoms.

For dealing with non-cat atoms, it's useful to know that you're free to call other jets from within yours. For example, to add two atoms, just call u3qa_add(a1, a2) (or the k version, depending).

To do printfs, use fprintf(stderr, "hello world").

Testing

When you think you're done, there's a couple things you can do to test for correctness. This is in addition to running your jet registered with c3n as described above.

Before proceeding with the below, we need to make sure the jet runs under conditions that actually trigger the memory checker. In zuse.hoon, find ++ sein. Directly under the |=, add a (or multiple) ~& printf that calls the function you jetted. Put this modified zuse.hoon into a ship's base desk, and run .pill +solid from dojo to start compiling the system files into a pill. Shut the ship down, copy out ship/.urb/put.pill and save it somewhere easy.

Next, to actually find out whether you're leaking memory or not, define U3_CPU_DEBUG in trace.h, define U3_MEMORY_DEBUG in allocate.h, and boot a new ship with the -g flag set, using -B to point to the special pill you just created.
If you're leaking memory, it will print the identified leaks for you and crash. If this information is too vague and you want to see the data that you're leaking, uncomment the u3m_p call on line 1736 of allocate.c. To test whether it's actually working, add a u3nc(0,0); into your jet. This should be picked up as a memory leak.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment