even faster wota encoding and decoding

This commit is contained in:
2025-06-08 10:34:12 -05:00
parent c1d341eecd
commit 8a5f8a4d74
4 changed files with 45 additions and 29 deletions

View File

@@ -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()
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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
================================================================ */