From 8a5f8a4d74af244dace3eab803e56ef710483273 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Sun, 8 Jun 2025 10:34:12 -0500 Subject: [PATCH] even faster wota encoding and decoding --- scripts/engine.cm | 3 ++- source/cell.c | 2 +- source/qjs_wota.c | 55 ++++++++++++++++++++++++++--------------------- source/wota.h | 14 ++++++++++-- 4 files changed, 45 insertions(+), 29 deletions(-) diff --git a/scripts/engine.cm b/scripts/engine.cm index e4933104..cb06202e 100644 --- a/scripts/engine.cm +++ b/scripts/engine.cm @@ -660,7 +660,8 @@ $_[ACTORDATA].id = cell.id // Actor's timeslice for processing a single message function turn(msg) { - handle_message(msg) + var decoded = wota.decode(msg) + handle_message(decoded) send_messages() } diff --git a/source/cell.c b/source/cell.c index ad218d6e..0189b30f 100644 --- a/source/cell.c +++ b/source/cell.c @@ -530,7 +530,7 @@ void actor_turn(cell_rt *actor) arrdel(actor->letters, 0); SDL_UnlockMutex(actor->msg_mutex); - if (l.type == LETTER_WOTA) { + if (l.type == LETTER_WOTA) { JSValue arg = wota2value(actor->context, l.wota_data); free(l.wota_data); result = JS_Call(actor->context, actor->message_handle, JS_UNDEFINED, 1, &arg); diff --git a/source/qjs_wota.c b/source/qjs_wota.c index c06db959..33d439f2 100644 --- a/source/qjs_wota.c +++ b/source/qjs_wota.c @@ -59,10 +59,11 @@ static void wota_stack_free(WotaEncodeContext *enc) } } -static JSValue apply_replacer(WotaEncodeContext *enc, JSValueConst holder, JSValueConst key, JSValueConst val) +static JSValue apply_replacer(WotaEncodeContext *enc, JSValueConst holder, JSAtom key, JSValueConst val) { if (JS_IsUndefined(enc->replacer)) return JS_DupValue(enc->ctx, val); - JSValue args[2] = { JS_DupValue(enc->ctx, key), JS_DupValue(enc->ctx, val) }; + JSValue key_val = (key == JS_ATOM_NULL) ? JS_UNDEFINED : JS_AtomToValue(enc->ctx, key); + JSValue args[2] = { key_val, JS_DupValue(enc->ctx, val) }; JSValue result = JS_Call(enc->ctx, enc->replacer, holder, 2, args); JS_FreeValue(enc->ctx, args[0]); JS_FreeValue(enc->ctx, args[1]); @@ -70,7 +71,7 @@ static JSValue apply_replacer(WotaEncodeContext *enc, JSValueConst holder, JSVal return result; } -static void wota_encode_value(WotaEncodeContext *enc, JSValueConst val, JSValueConst holder, JSValueConst key); +static void wota_encode_value(WotaEncodeContext *enc, JSValueConst val, JSValueConst holder, JSAtom key); static void encode_object_properties(WotaEncodeContext *enc, JSValueConst val, JSValueConst holder) { @@ -97,12 +98,10 @@ static void encode_object_properties(WotaEncodeContext *enc, JSValueConst val, J for (uint32_t i = 0; i < non_function_count; i++) { size_t plen; const char *prop_name = JS_AtomToCStringLen(ctx, &plen, atoms[i]); - JSValue prop_key = JS_AtomToValue(ctx, atoms[i]); JSValue prop_val = props[i]; wota_write_text_len(&enc->wb, prop_name, plen); - wota_encode_value(enc, prop_val, val, prop_key); + wota_encode_value(enc, prop_val, val, atoms[i]); JS_FreeCString(ctx, prop_name); - JS_FreeValue(ctx, prop_key); JS_FreeValue(ctx, prop_val); } @@ -112,11 +111,11 @@ static void encode_object_properties(WotaEncodeContext *enc, JSValueConst val, J js_free(ctx, ptab); } -static void wota_encode_value(WotaEncodeContext *enc, JSValueConst val, JSValueConst holder, JSValueConst key) +static void wota_encode_value(WotaEncodeContext *enc, JSValueConst val, JSValueConst holder, JSAtom key) { JSContext *ctx = enc->ctx; JSValue replaced; - if (!JS_IsUndefined(enc->replacer) && !JS_IsUndefined(key)) + if (!JS_IsUndefined(enc->replacer) && key != JS_ATOM_NULL) replaced = apply_replacer(enc, holder, key, val); else replaced = JS_DupValue(enc->ctx, val); @@ -171,10 +170,10 @@ static void wota_encode_value(WotaEncodeContext *enc, JSValueConst val, JSValueC wota_write_array(&enc->wb, arr_len); for (int64_t i = 0; i < arr_len; i++) { JSValue elem_val = JS_GetPropertyUint32(ctx, replaced, i); - JSValue elem_key = JS_NewInt32(ctx, i); - wota_encode_value(enc, elem_val, replaced, elem_key); + JSAtom idx_atom = JS_NewAtomUInt32(ctx, (uint32_t)i); + wota_encode_value(enc, elem_val, replaced, idx_atom); + JS_FreeAtom(ctx, idx_atom); JS_FreeValue(ctx, elem_val); - JS_FreeValue(ctx, elem_key); } wota_stack_pop(enc); break; @@ -183,7 +182,7 @@ static void wota_encode_value(WotaEncodeContext *enc, JSValueConst val, JSValueC JSValue adata = JS_GetProperty(ctx, replaced, crt->actor_sym); if (!JS_IsUndefined(adata)) { wota_write_sym(&enc->wb, WOTA_PRIVATE); - wota_encode_value(enc, adata, replaced, JS_UNDEFINED); + wota_encode_value(enc, adata, replaced, JS_ATOM_NULL); JS_FreeValue(ctx, adata); break; } @@ -217,7 +216,7 @@ static void wota_encode_value(WotaEncodeContext *enc, JSValueConst val, JSValueC JS_FreeValue(ctx, replaced); } -static char *decode_wota_value(JSContext *ctx, char *data_ptr, JSValue *out_val, JSValue holder, JSValue key, JSValue reviver) +static char *decode_wota_value(JSContext *ctx, char *data_ptr, JSValue *out_val, JSValue holder, JSAtom key, JSValue reviver) { uint64_t first_word = *(uint64_t *)data_ptr; int type = (int)(first_word & 0xffU); @@ -239,7 +238,7 @@ static char *decode_wota_value(JSContext *ctx, char *data_ptr, JSValue *out_val, data_ptr = wota_read_sym(&scode, data_ptr); if (scode == WOTA_PRIVATE) { JSValue inner = JS_UNDEFINED; - data_ptr = decode_wota_value(ctx, data_ptr, &inner, holder, JS_UNDEFINED, reviver); + data_ptr = decode_wota_value(ctx, data_ptr, &inner, holder, JS_ATOM_NULL, reviver); JSValue obj = JS_NewObject(ctx); cell_rt *crt = JS_GetContextOpaque(ctx); JS_SetProperty(ctx, obj, crt->actor_sym, inner); @@ -272,8 +271,10 @@ static char *decode_wota_value(JSContext *ctx, char *data_ptr, JSValue *out_val, JS_SetLength(ctx, arr, c); for (long long i = 0; i < c; i++) { JSValue elem_val = JS_UNDEFINED; - data_ptr = decode_wota_value(ctx, data_ptr, &elem_val, arr, JS_NewInt32(ctx, i), reviver); + JSAtom idx_atom = JS_NewAtomUInt32(ctx, (uint32_t)i); + data_ptr = decode_wota_value(ctx, data_ptr, &elem_val, arr, idx_atom, reviver); JS_SetPropertyUint32(ctx, arr, i, elem_val); + JS_FreeAtom(ctx, idx_atom); } *out_val = arr; break; @@ -284,14 +285,15 @@ static char *decode_wota_value(JSContext *ctx, char *data_ptr, JSValue *out_val, JSValue obj = JS_NewObject(ctx); for (long long i = 0; i < c; i++) { char *tkey = NULL; - data_ptr = wota_read_text(&tkey, data_ptr); - JSValue prop_key = tkey ? JS_NewString(ctx, tkey) : JS_UNDEFINED; + size_t key_len; + data_ptr = wota_read_text_len(&key_len, &tkey, data_ptr); + if (!tkey) continue; // invalid key + JSAtom prop_key = JS_NewAtomLen(ctx, tkey, key_len); JSValue sub_val = JS_UNDEFINED; data_ptr = decode_wota_value(ctx, data_ptr, &sub_val, obj, prop_key, reviver); - if (tkey) JS_SetPropertyStr(ctx, obj, tkey, sub_val); - else JS_FreeValue(ctx, sub_val); - JS_FreeValue(ctx, prop_key); - if (tkey) free(tkey); + JS_SetProperty(ctx, obj, prop_key, sub_val); + JS_FreeAtom(ctx, prop_key); + free(tkey); } *out_val = obj; break; @@ -302,7 +304,8 @@ static char *decode_wota_value(JSContext *ctx, char *data_ptr, JSValue *out_val, break; } if (!JS_IsUndefined(reviver)) { - JSValue args[2] = { JS_DupValue(ctx, key), JS_DupValue(ctx, *out_val) }; + JSValue key_val = (key == JS_ATOM_NULL) ? JS_UNDEFINED : JS_AtomToValue(ctx, key); + JSValue args[2] = { key_val, JS_DupValue(ctx, *out_val) }; JSValue revived = JS_Call(ctx, reviver, holder, 2, args); JS_FreeValue(ctx, args[0]); JS_FreeValue(ctx, args[1]); @@ -324,7 +327,7 @@ void *value2wota(JSContext *ctx, JSValue v, JSValue replacer, size_t *bytes) enc->cycle = 0; enc->replacer = replacer; wota_buffer_init(&enc->wb, 16); - wota_encode_value(enc, v, JS_UNDEFINED, JS_UNDEFINED); + wota_encode_value(enc, v, JS_UNDEFINED, JS_ATOM_NULL); if (enc->cycle) { wota_stack_free(enc); wota_buffer_free(&enc->wb); @@ -341,7 +344,7 @@ JSValue wota2value(JSContext *ctx, void *wota) { JSValue result = JS_UNDEFINED; JSValue holder = JS_NewObject(ctx); - decode_wota_value(ctx, wota, &result, holder, JS_UNDEFINED, JS_UNDEFINED); + decode_wota_value(ctx, wota, &result, holder, JS_ATOM_NULL, JS_UNDEFINED); JS_FreeValue(ctx, holder); return result; } @@ -366,7 +369,9 @@ static JSValue js_wota_decode(JSContext *ctx, JSValueConst this_val, int argc, J char *data_ptr = (char *)buf; JSValue result = JS_UNDEFINED; JSValue holder = JS_NewObject(ctx); - decode_wota_value(ctx, data_ptr, &result, holder, JS_NewString(ctx, ""), reviver); + JSAtom empty_atom = JS_NewAtom(ctx, ""); + decode_wota_value(ctx, data_ptr, &result, holder, empty_atom, reviver); + JS_FreeAtom(ctx, empty_atom); JS_FreeValue(ctx, holder); return result; } diff --git a/source/wota.h b/source/wota.h index f2197327..79f09422 100644 --- a/source/wota.h +++ b/source/wota.h @@ -48,6 +48,7 @@ static inline int wota_type(const uint64_t *w) { ---------------------------------------------------------------- */ char *wota_read_blob (long long *byte_len, char **blob, char *wota); char *wota_read_text (char **text_utf8, char *wota); +char *wota_read_text_len(size_t *byte_len, char **text_utf8, char *wota); char *wota_read_array (long long *count, char *wota); char *wota_read_record (long long *count, char *wota); char *wota_read_float (double *d, char *wota); @@ -401,7 +402,7 @@ char *wota_read_blob(long long *byte_len, char **blob, char *wota) then floor((nbytes + 7)/8) 64-bit words containing the UTF-8 bytes, packed 8 bytes per word */ -char *wota_read_text(char **text_utf8, char *wota) +char *wota_read_text_len(size_t *byte_len, char **text_utf8, char *wota) { if (!text_utf8) return wota_skip1(wota); @@ -415,11 +416,15 @@ char *wota_read_text(char **text_utf8, char *wota) uint64_t nbytes = (first >> 8); long long nwords = (long long)((nbytes + 7ULL) >> 3); + if (byte_len) { + *byte_len = (size_t)nbytes; + } + uint64_t *data_words = p + 1; char *out = (char *)malloc((size_t)(nbytes + 1)); if (!out) { - fprintf(stderr, "malloc failed in wota_read_text\n"); + fprintf(stderr, "malloc failed in wota_read_text_len\n"); abort(); } @@ -437,6 +442,11 @@ char *wota_read_text(char **text_utf8, char *wota) return (char *)(data_words + nwords); } +char *wota_read_text(char **text_utf8, char *wota) +{ + return wota_read_text_len(NULL, text_utf8, wota); +} + /* ================================================================ WRITING ================================================================ */