No copy stone blobs for wota messages #7
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
When sending messages locally, stone objects can just be passed by reference; this would work for a lot of things, but the first obvious target is the arraybuffers working, then we can concern ourselves with others. If a stone array is sent over the network via nota, it would not be stone on the other side, but arrays arriving via wota may be stone.
Add Stoneto Enhance stone to lower copyingBelow is a concrete recipe for adding “stone‐blob” sharing into your Wota messaging and actor teardown without ever having to round-trip through full JS decode. The key ideas are:
Treat stone-blobs as first-class, ref-counted handles, not raw bytes.
Extend Wota with a new “stone-blob” tag so your encoder/decoder can bump or consume refcounts without copying big buffers.
Hook into actor teardown to sweep any live stone-blob handles still queued and drop their counts in C—no JS decode needed.
// in qjs_blob.h
typedef struct blob {
uint8_t *data; // actual bytes, NULL for stone-only
size_t length_bits; // bit-length of data buffer
int refcount; // new
bool stone; // new: true if immutable & shareable
} blob;
// factory for a new mutable blob
blob *blob_new(size_t bits) {
blob *b = malloc(sizeof *b);
b->data = calloc((bits+7)/8,1);
b->length_bits = bits;
b->refcount = 1;
b->stone = false;
return b;
}
// factory for a stone blob handle, assume data already exists
blob *blob_wrap(uint8_t *data, size_t bits) {
blob *b = malloc(sizeof *b);
b->data = data;
b->length_bits = bits;
b->refcount = 1;
b->stone = true;
return b;
}
static inline void blob_incref(blob *b) {
if (b) atomic_fetch_add(&b->refcount,1);
}
static void blob_destroy(blob *b) {
if (!b) return;
if (atomic_fetch_sub(&b->refcount,1) > 1) {
// still live somewhere else
return;
}
// actually free once refcount hits zero
if (b->data && !b->stone) free(b->data);
free(b);
}
– now blob_destroy unconditionally does a ref-decrement, and only frees buffer+struct when count hits zero.
Modify your wota_encode_value when you see a JS-blob:
Here we encode a 0-length array as a special tag, then stick the raw blob* pointer in a 64-bit slot. We also blob_incref(b) so the actor’s mailbox owns a reference.
In decode_wota_value, catch that special case before the normal WOTA_BLOB branch:
And leave your usual WOTA_BLOB code below unchanged for real data-blobs.
Your existing actor_free already does:
for (int i = 0; i < arrlen(actor->letters); i++) {
if (actor->letters[i].type == LETTER_BLOB) {
blob_destroy(actor->letters[i].blob_data);
} else if (…) { … }
}
Because blob_destroy now decrements refcounts rather than forcibly freeing raw data, you don’t need to decode or touch JS at all: every stone-blob in the mailbox is simply dropped via its refcount--, and only truly freed if no other actor or wrapper holds it.
Wrappers in the bump arena
Your JS-side blob wrappers are still alloc’d in your bump arena, so they move on compaction—and when their refcount hits zero, your js_zone_free (no-op) just leaves a hole until the next semi-space GC.
Raw blob data stays separate
The actual large buffers remain out on the malloc heap (or a long-lived “blob_region”) and are freed only when the final blob_destroy sees refcount == 0.
No extra decode cost
You never run decode_wota_value on a big blob payload—stone-blobs skip the bit-copy entirely and just point at the existing data.
Summary
Tag stone blobs in your Wota encoder with a zero-length record + pointer.
Bump raw-blob refcount in the encoder, and again in the decoder, so the mailbox and the target actor both share ownership.
blob_destroy always decrefs; only frees when the count reaches zero.
Actor teardown already crawls actor->letters and calls blob_destroy on each—no JS-level decode needed.
This gives you zero-copy, ref-counted sharing of large stone-blobs across actors, full compatibility with your bump+copying GC for JS wrappers, and trivial mailbox cleanup in pure C.
Enhance stone to lower copyingto No copy stone blobs for wota messages