diff --git a/internal/engine.cm b/internal/engine.cm index 13d62915..621e8cb2 100644 --- a/internal/engine.cm +++ b/internal/engine.cm @@ -231,17 +231,16 @@ function actor_die(err) //actor_mod.on_exception(actor_die) _cell.args = init != null ? init : {} -_cell.id = "newguy" function create_actor(desc) { var _desc = desc == null ? {id:guid()} : desc var actor = {} actor[ACTORDATA] = _desc + stone(actor) return actor } var $_ = {} -$_.self = create_actor() use_cache['core/json'] = json @@ -734,7 +733,7 @@ stone(send) if (!_cell.args.id) _cell.id = guid() else _cell.id = _cell.args.id -$_.self[ACTORDATA].id = _cell.id +$_.self = create_actor({id: _cell.id}) // Actor's timeslice for processing a single message function turn(msg) @@ -839,12 +838,8 @@ function handle_message(msg) { if (msg.type == "user") { letter = msg.data // what the sender really sent - _ObjectDefineProperty(letter, HEADER, { - value: msg, enumerable: false - }) - _ObjectDefineProperty(letter, ACTORDATA, { // this is so is_actor == true - value: { reply: msg.reply }, enumerable: false - }) + letter[HEADER] = msg + letter[ACTORDATA] = { reply: msg.reply } if (msg.return) { fn = replies[msg.return] diff --git a/source/cell.c b/source/cell.c index eb580006..57459d0c 100644 --- a/source/cell.c +++ b/source/cell.c @@ -284,6 +284,7 @@ void script_startup(cell_rt *prt) JS_SetPropertyStr(js, env_ref.val, "json", tmp); crt->actor_sym_ref.val = JS_NewObject(js); + JS_SetActorSym(js, JS_DupValue(js, crt->actor_sym_ref.val)); JS_SetPropertyStr(js, env_ref.val, "actorsym", JS_DupValue(js, crt->actor_sym_ref.val)); // Always set init (even if null) @@ -518,6 +519,7 @@ int cell_init(int argc, char **argv) cli_rt->message_handle_ref.val = JS_NULL; cli_rt->unneeded_ref.val = JS_NULL; cli_rt->actor_sym_ref.val = JS_NewObject(ctx); + JS_SetActorSym(ctx, JS_DupValue(ctx, cli_rt->actor_sym_ref.val)); root_cell = cli_rt; diff --git a/source/quickjs-internal.h b/source/quickjs-internal.h index a7123f92..c2a2f5b9 100644 --- a/source/quickjs-internal.h +++ b/source/quickjs-internal.h @@ -1147,6 +1147,9 @@ struct JSContext { JSValue current_exception; + /* Actor identity key — used by wota/nota PRIVATE serialization */ + JSValue actor_sym; + /* Stack overflow protection */ // todo: want this, but should be a simple increment/decrement counter while frames are pushed size_t stack_depth; diff --git a/source/quickjs.h b/source/quickjs.h index 3edf37ff..ec049139 100644 --- a/source/quickjs.h +++ b/source/quickjs.h @@ -324,6 +324,8 @@ JSContext *JS_NewContextWithHeapSize (JSRuntime *rt, size_t heap_size); void JS_FreeContext (JSContext *s); void *JS_GetContextOpaque (JSContext *ctx); void JS_SetContextOpaque (JSContext *ctx, void *opaque); +void JS_SetActorSym (JSContext *ctx, JSValue sym); +JSValue JS_GetActorSym (JSContext *ctx); JSRuntime *JS_GetRuntime (JSContext *ctx); /* use 0 to disable maximum stack size check */ void JS_SetMaxStackSize (JSContext *ctx, size_t stack_size); diff --git a/source/runtime.c b/source/runtime.c index e9773110..2aba02e9 100644 --- a/source/runtime.c +++ b/source/runtime.c @@ -1619,6 +1619,9 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) { #endif ctx->current_exception = gc_copy_value (ctx, ctx->current_exception, from_base, from_end, to_base, &to_free, to_end); + /* Copy actor identity key */ + ctx->actor_sym = gc_copy_value (ctx, ctx->actor_sym, from_base, from_end, to_base, &to_free, to_end); + /* Copy class prototypes */ #ifdef DUMP_GC_DETAIL printf(" roots: class_proto (count=%d)\n", ctx->class_count); fflush(stdout); @@ -1892,6 +1895,7 @@ JSContext *JS_NewContextRawWithHeapSize (JSRuntime *rt, size_t heap_size) { /* Initialize per-context execution state (moved from JSRuntime) */ ctx->current_exception = JS_NULL; + ctx->actor_sym = JS_NULL; /* Initialize constant text pool (avoids overflow pages for common case) */ { @@ -1973,6 +1977,14 @@ void JS_SetContextOpaque (JSContext *ctx, void *opaque) { ctx->user_opaque = opaque; } +void JS_SetActorSym (JSContext *ctx, JSValue sym) { + ctx->actor_sym = sym; +} + +JSValue JS_GetActorSym (JSContext *ctx) { + return ctx->actor_sym; +} + void JS_SetClassProto (JSContext *ctx, JSClassID class_id, JSValue obj) { assert (class_id < ctx->class_count); set_value (ctx, &ctx->class_proto[class_id], obj); @@ -11365,9 +11377,15 @@ static char *js_do_nota_decode (JSContext *js, JSValue *tmp, char *nota, JSValue case NOTA_SYM: nota = nota_read_sym (&b, nota); if (b == NOTA_PRIVATE) { - JSValue inner; - nota = js_do_nota_decode (js, &inner, nota, holder, JS_NULL, reviver); + JSGCRef inner_ref; + JS_PushGCRef (js, &inner_ref); + inner_ref.val = JS_NULL; + nota = js_do_nota_decode (js, &inner_ref.val, nota, holder, JS_NULL, reviver); JSValue obj = JS_NewObject (js); + if (!JS_IsNull (js->actor_sym)) + JS_SetPropertyKey (js, obj, js->actor_sym, inner_ref.val); + JS_CellStone (js, obj); + JS_PopGCRef (js, &inner_ref); *tmp = obj; } else { switch (b) { @@ -11461,11 +11479,17 @@ static void nota_encode_value (NotaEncodeContext *enc, JSValueConst val, JSValue } JSValue adata = JS_NULL; + if (!JS_IsNull (ctx->actor_sym)) { + int has = JS_HasPropertyKey (ctx, replaced_ref.val, ctx->actor_sym); + if (has > 0) adata = JS_GetPropertyKey (ctx, replaced_ref.val, ctx->actor_sym); + } if (!JS_IsNull (adata)) { nota_write_sym (&enc->nb, NOTA_PRIVATE); nota_encode_value (enc, adata, replaced_ref.val, JS_NULL); + JS_FreeValue (ctx, adata); break; } + JS_FreeValue (ctx, adata); if (nota_stack_has (enc, replaced_ref.val)) { enc->cycle = 1; break; @@ -11872,6 +11896,10 @@ static void wota_encode_value (WotaEncodeContext *enc, JSValueConst val, JSValue break; } JSValue adata = JS_NULL; + if (!JS_IsNull (ctx->actor_sym)) { + int has = JS_HasPropertyKey (ctx, replaced, ctx->actor_sym); + if (has > 0) adata = JS_GetPropertyKey (ctx, replaced, ctx->actor_sym); + } if (!JS_IsNull (adata)) { wota_write_sym (&enc->wb, WOTA_PRIVATE); wota_encode_value (enc, adata, replaced, JS_NULL); @@ -11928,9 +11956,15 @@ static char *decode_wota_value (JSContext *ctx, char *data_ptr, JSValue *out_val int scode; data_ptr = wota_read_sym (&scode, data_ptr); if (scode == WOTA_PRIVATE) { - JSValue inner = JS_NULL; - data_ptr = decode_wota_value (ctx, data_ptr, &inner, holder, JS_NULL, reviver); + JSGCRef inner_ref; + JS_PushGCRef (ctx, &inner_ref); + inner_ref.val = JS_NULL; + data_ptr = decode_wota_value (ctx, data_ptr, &inner_ref.val, holder, JS_NULL, reviver); JSValue obj = JS_NewObject (ctx); + if (!JS_IsNull (ctx->actor_sym)) + JS_SetPropertyKey (ctx, obj, ctx->actor_sym, inner_ref.val); + JS_CellStone (ctx, obj); + JS_PopGCRef (ctx, &inner_ref); *out_val = obj; } else if (scode == WOTA_NULL) *out_val = JS_NULL; else if (scode == WOTA_FALSE) *out_val = JS_NewBool (ctx, 0);