gx fices
This commit is contained in:
4
parse.cm
4
parse.cm
@@ -1627,6 +1627,8 @@ var parse = function(tokens, src, filename, tokenizer) {
|
||||
if (r.v != null) {
|
||||
left_node.level = r.level
|
||||
left_node.function_nr = r.def_function_nr
|
||||
r.v.nr_uses = r.v.nr_uses + 1
|
||||
if (r.level > 0) r.v.closure = 1
|
||||
} else {
|
||||
left_node.level = -1
|
||||
}
|
||||
@@ -1718,6 +1720,8 @@ var parse = function(tokens, src, filename, tokenizer) {
|
||||
if (r.v != null) {
|
||||
operand.level = r.level
|
||||
operand.function_nr = r.def_function_nr
|
||||
r.v.nr_uses = r.v.nr_uses + 1
|
||||
if (r.level > 0) r.v.closure = 1
|
||||
} else {
|
||||
operand.level = -1
|
||||
}
|
||||
|
||||
@@ -273,6 +273,7 @@ void script_startup(cell_rt *prt)
|
||||
JSContext *js = JS_NewContext(g_runtime);
|
||||
|
||||
JS_SetContextOpaque(js, prt);
|
||||
JS_SetGCScanExternal(js, actor_gc_scan);
|
||||
prt->context = js;
|
||||
|
||||
/* Set per-actor heap memory limit */
|
||||
@@ -574,6 +575,7 @@ int cell_init(int argc, char **argv)
|
||||
|
||||
cli_rt->context = ctx;
|
||||
JS_SetContextOpaque(ctx, cli_rt);
|
||||
JS_SetGCScanExternal(ctx, actor_gc_scan);
|
||||
|
||||
JS_AddGCRef(ctx, &cli_rt->idx_buffer_ref);
|
||||
JS_AddGCRef(ctx, &cli_rt->on_exception_ref);
|
||||
|
||||
@@ -100,6 +100,8 @@ void exit_handler(void);
|
||||
void actor_loop();
|
||||
void actor_initialize(void);
|
||||
void actor_free(cell_rt *actor);
|
||||
void actor_gc_scan(JSContext *ctx, uint8_t *fb, uint8_t *fe,
|
||||
uint8_t *tb, uint8_t **tf, uint8_t *te);
|
||||
int scheduler_actor_count(void);
|
||||
void scheduler_enable_quiescence(void);
|
||||
|
||||
|
||||
@@ -971,7 +971,6 @@ JSValue js_new_register_function(JSContext *ctx, JSCodeRegister *code, JSValue e
|
||||
fn->u.cell.code = code_obj;
|
||||
fn->u.cell.env_record = env_ref.val;
|
||||
fn->u.cell.outer_frame = frame_ref.val;
|
||||
|
||||
JSValue out = fn_ref.val;
|
||||
JS_DeleteGCRef(ctx, &fn_ref);
|
||||
JS_PopGCRef(ctx, &frame_ref);
|
||||
@@ -1254,8 +1253,8 @@ void __asan_on_error(void) {
|
||||
const char *file = NULL;
|
||||
uint16_t line = 0;
|
||||
uint32_t pc = is_first ? cur_pc : 0;
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code) {
|
||||
JSCodeRegister *code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(FN_READ_CODE(fn))->u.reg.code) {
|
||||
JSCodeRegister *code = JS_VALUE_GET_CODE(FN_READ_CODE(fn))->u.reg.code;
|
||||
file = code->filename_cstr;
|
||||
func_name = code->name_cstr;
|
||||
if (!is_first)
|
||||
@@ -1291,7 +1290,7 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
||||
ctx->suspended_frame_ref.val = JS_NULL;
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
code = JS_VALUE_GET_CODE(FN_READ_CODE(fn))->u.reg.code;
|
||||
env = fn->u.cell.env_record;
|
||||
pc = ctx->suspended_pc;
|
||||
result = JS_NULL;
|
||||
@@ -1497,28 +1496,34 @@ vm_dispatch:
|
||||
|
||||
VM_CASE(MACH_LOADK): {
|
||||
int bx = MACH_GET_Bx(instr);
|
||||
|
||||
if (bx < (int)code->cpool_count)
|
||||
frame->slots[a] = code->cpool[bx];
|
||||
VM_BREAK();
|
||||
}
|
||||
|
||||
VM_CASE(MACH_LOADI):
|
||||
|
||||
frame->slots[a] = JS_NewInt32(ctx, MACH_GET_sBx(instr));
|
||||
VM_BREAK();
|
||||
|
||||
VM_CASE(MACH_LOADNULL):
|
||||
|
||||
frame->slots[a] = JS_NULL;
|
||||
VM_BREAK();
|
||||
|
||||
VM_CASE(MACH_LOADTRUE):
|
||||
|
||||
frame->slots[a] = JS_TRUE;
|
||||
VM_BREAK();
|
||||
|
||||
VM_CASE(MACH_LOADFALSE):
|
||||
|
||||
frame->slots[a] = JS_FALSE;
|
||||
VM_BREAK();
|
||||
|
||||
VM_CASE(MACH_MOVE):
|
||||
|
||||
frame->slots[a] = frame->slots[b];
|
||||
VM_BREAK();
|
||||
|
||||
@@ -2070,6 +2075,18 @@ vm_dispatch:
|
||||
fn = JS_VALUE_GET_FUNCTION(target->function);
|
||||
target = (JSFrameRegister *)JS_VALUE_GET_PTR(fn->u.cell.outer_frame);
|
||||
}
|
||||
{
|
||||
uint64_t tcap = objhdr_cap56(target->header);
|
||||
if ((unsigned)c >= tcap) {
|
||||
fprintf(stderr, "MACH_SETUP OOB: slot=%d >= target_cap=%llu depth=%d "
|
||||
"cur_fn=%s (%s) pc=%u\n",
|
||||
c, (unsigned long long)tcap, depth,
|
||||
code->name_cstr ? code->name_cstr : "?",
|
||||
code->filename_cstr ? code->filename_cstr : "?", pc - 1);
|
||||
fflush(stderr);
|
||||
VM_BREAK();
|
||||
}
|
||||
}
|
||||
target->slots[c] = frame->slots[a];
|
||||
VM_BREAK();
|
||||
}
|
||||
@@ -2162,9 +2179,9 @@ vm_dispatch:
|
||||
const char *callee_file = "?";
|
||||
{
|
||||
JSFunction *callee_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
if (callee_fn->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(callee_fn->u.cell.code)->u.reg.code) {
|
||||
if (JS_VALUE_GET_CODE(callee_fn->u.cell.code)->u.reg.code->name_cstr) callee_name = JS_VALUE_GET_CODE(callee_fn->u.cell.code)->u.reg.code->name_cstr;
|
||||
if (JS_VALUE_GET_CODE(callee_fn->u.cell.code)->u.reg.code->filename_cstr) callee_file = JS_VALUE_GET_CODE(callee_fn->u.cell.code)->u.reg.code->filename_cstr;
|
||||
if (callee_fn->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(FN_READ_CODE(callee_fn))->u.reg.code) {
|
||||
if (JS_VALUE_GET_CODE(FN_READ_CODE(callee_fn))->u.reg.code->name_cstr) callee_name = JS_VALUE_GET_CODE(FN_READ_CODE(callee_fn))->u.reg.code->name_cstr;
|
||||
if (JS_VALUE_GET_CODE(FN_READ_CODE(callee_fn))->u.reg.code->filename_cstr) callee_file = JS_VALUE_GET_CODE(FN_READ_CODE(callee_fn))->u.reg.code->filename_cstr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -2174,11 +2191,12 @@ vm_dispatch:
|
||||
frame_ref.val = JS_MKPTR(frame);
|
||||
int ret_info = JS_VALUE_GET_INT(frame->address);
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
code = JS_VALUE_GET_CODE(FN_READ_CODE(fn))->u.reg.code;
|
||||
env = fn->u.cell.env_record;
|
||||
pc = ret_info >> 16;
|
||||
int ret_slot = ret_info & 0xFFFF;
|
||||
if (ret_slot != 0xFFFF) {
|
||||
|
||||
#ifdef VALIDATE_GC
|
||||
if (JS_IsPtr(result)) {
|
||||
void *rp = JS_VALUE_GET_PTR(result);
|
||||
@@ -2207,11 +2225,14 @@ vm_dispatch:
|
||||
frame_ref.val = JS_MKPTR(frame);
|
||||
int ret_info = JS_VALUE_GET_INT(frame->address);
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
code = JS_VALUE_GET_CODE(FN_READ_CODE(fn))->u.reg.code;
|
||||
env = fn->u.cell.env_record;
|
||||
pc = ret_info >> 16;
|
||||
int ret_slot = ret_info & 0xFFFF;
|
||||
if (ret_slot != 0xFFFF) frame->slots[ret_slot] = result;
|
||||
if (ret_slot != 0xFFFF) {
|
||||
|
||||
frame->slots[ret_slot] = result;
|
||||
}
|
||||
}
|
||||
VM_BREAK();
|
||||
|
||||
@@ -2233,6 +2254,7 @@ vm_dispatch:
|
||||
|
||||
VM_CASE(MACH_CLOSURE): {
|
||||
int bx = MACH_GET_Bx(instr);
|
||||
|
||||
if ((uint32_t)bx < code->func_count) {
|
||||
JSCodeRegister *fn_code = code->functions[bx];
|
||||
/* Read env fresh from frame->function — C local can be stale */
|
||||
@@ -2630,7 +2652,7 @@ vm_dispatch:
|
||||
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER) {
|
||||
/* Register function: switch frames inline (fast path) */
|
||||
JSCodeRegister *fn_code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
JSCodeRegister *fn_code = JS_VALUE_GET_CODE(FN_READ_CODE(fn))->u.reg.code;
|
||||
JSFrameRegister *new_frame = alloc_frame_register(ctx, fn_code->nr_slots);
|
||||
if (!new_frame) {
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
@@ -2640,7 +2662,7 @@ vm_dispatch:
|
||||
fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->slots[a]);
|
||||
fn_val = fr->function;
|
||||
fn = JS_VALUE_GET_FUNCTION(fn_val);
|
||||
fn_code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
fn_code = JS_VALUE_GET_CODE(FN_READ_CODE(fn))->u.reg.code;
|
||||
new_frame->function = fn_val;
|
||||
/* Copy this + args from call frame to new frame */
|
||||
int copy_count = (c_argc < fn_code->arity) ? c_argc : fn_code->arity;
|
||||
@@ -2702,7 +2724,7 @@ vm_dispatch:
|
||||
goto disrupt;
|
||||
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER) {
|
||||
JSCodeRegister *fn_code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
JSCodeRegister *fn_code = JS_VALUE_GET_CODE(FN_READ_CODE(fn))->u.reg.code;
|
||||
int current_slots = (int)objhdr_cap56(frame->header);
|
||||
|
||||
if (fn_code->nr_slots <= current_slots) {
|
||||
@@ -2730,7 +2752,7 @@ vm_dispatch:
|
||||
fr = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->slots[a]);
|
||||
fn_val = fr->function;
|
||||
fn = JS_VALUE_GET_FUNCTION(fn_val);
|
||||
fn_code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
fn_code = JS_VALUE_GET_CODE(FN_READ_CODE(fn))->u.reg.code;
|
||||
new_frame->function = fn_val;
|
||||
int copy_count = (c_argc < fn_code->arity) ? c_argc : fn_code->arity;
|
||||
new_frame->slots[0] = fr->slots[0]; /* this */
|
||||
@@ -2769,7 +2791,7 @@ vm_dispatch:
|
||||
frame_ref.val = JS_MKPTR(frame);
|
||||
int ret_info = JS_VALUE_GET_INT(frame->address);
|
||||
JSFunction *ret_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
code = JS_VALUE_GET_CODE(ret_fn->u.cell.code)->u.reg.code;
|
||||
code = JS_VALUE_GET_CODE(FN_READ_CODE(ret_fn))->u.reg.code;
|
||||
env = ret_fn->u.cell.env_record;
|
||||
pc = ret_info >> 16;
|
||||
int ret_slot = ret_info & 0xFFFF;
|
||||
@@ -2822,7 +2844,7 @@ vm_dispatch:
|
||||
uint32_t frame_pc = pc;
|
||||
for (;;) {
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
code = JS_VALUE_GET_CODE(FN_READ_CODE(fn))->u.reg.code;
|
||||
/* Only enter handler if we're not already inside it */
|
||||
if (code->disruption_pc > 0 && frame_pc < code->disruption_pc) {
|
||||
env = fn->u.cell.env_record;
|
||||
|
||||
@@ -786,11 +786,12 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
NativeRTState *st = native_state(ctx);
|
||||
if (!st) return JS_EXCEPTION;
|
||||
JSFunction *f = JS_VALUE_GET_FUNCTION(func_obj);
|
||||
cell_compiled_fn fn = (cell_compiled_fn)JS_VALUE_GET_CODE(f->u.cell.code)->u.native.fn_ptr;
|
||||
int nr_slots = JS_VALUE_GET_CODE(f->u.cell.code)->u.native.nr_slots;
|
||||
JSCode *f_code = JS_VALUE_GET_CODE(FN_READ_CODE(f));
|
||||
cell_compiled_fn fn = (cell_compiled_fn)f_code->u.native.fn_ptr;
|
||||
int nr_slots = f_code->u.native.nr_slots;
|
||||
int arity = f->length;
|
||||
void *prev_dl_handle = st->current_dl_handle;
|
||||
st->current_dl_handle = JS_VALUE_GET_CODE(f->u.cell.code)->u.native.dl_handle;
|
||||
st->current_dl_handle = f_code->u.native.dl_handle;
|
||||
|
||||
#define RETURN_DISPATCH(v) \
|
||||
do { \
|
||||
@@ -841,7 +842,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
if (JS_IsFunction(frame->function)) {
|
||||
JSFunction *cur_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
if (cur_fn->kind == JS_FUNC_KIND_NATIVE)
|
||||
st->current_dl_handle = JS_VALUE_GET_CODE(cur_fn->u.cell.code)->u.native.dl_handle;
|
||||
st->current_dl_handle = JS_VALUE_GET_CODE(FN_READ_CODE(cur_fn))->u.native.dl_handle;
|
||||
}
|
||||
|
||||
JSValue result = fn(ctx, fp);
|
||||
@@ -874,7 +875,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
JS_RaiseDisrupt(ctx, "not a function");
|
||||
/* Resume caller with exception pending */
|
||||
JSFunction *exc_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(exc_fn->u.cell.code)->u.native.fn_ptr;
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(FN_READ_CODE(exc_fn))->u.native.fn_ptr;
|
||||
JS_PopGCRef(ctx, &callee_ref);
|
||||
continue;
|
||||
}
|
||||
@@ -882,14 +883,14 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
JSFunction *callee_fn = JS_VALUE_GET_FUNCTION(callee_fn_val);
|
||||
if (!cell_check_call_arity(ctx, callee_fn, callee_argc)) {
|
||||
JSFunction *exc_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(exc_fn->u.cell.code)->u.native.fn_ptr;
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(FN_READ_CODE(exc_fn))->u.native.fn_ptr;
|
||||
JS_PopGCRef(ctx, &callee_ref);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (callee_fn->kind == JS_FUNC_KIND_NATIVE) {
|
||||
/* Native-to-native call — no C stack growth */
|
||||
cell_compiled_fn callee_ptr = (cell_compiled_fn)JS_VALUE_GET_CODE(callee_fn->u.cell.code)->u.native.fn_ptr;
|
||||
cell_compiled_fn callee_ptr = (cell_compiled_fn)JS_VALUE_GET_CODE(FN_READ_CODE(callee_fn))->u.native.fn_ptr;
|
||||
|
||||
if (pending_is_tail) {
|
||||
/* Tail call: replace current frame with the prepared callee frame. */
|
||||
@@ -930,7 +931,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_val);
|
||||
fp = (JSValue *)frame->slots;
|
||||
JSFunction *exc_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(exc_fn->u.cell.code)->u.native.fn_ptr;
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(FN_READ_CODE(exc_fn))->u.native.fn_ptr;
|
||||
JS_PopGCRef(ctx, &callee_ref);
|
||||
continue;
|
||||
}
|
||||
@@ -967,7 +968,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
/* fn and fp still point to the calling native function's frame.
|
||||
Just resume it — it will detect JS_EXCEPTION in the return slot. */
|
||||
JSFunction *exc_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(exc_fn->u.cell.code)->u.native.fn_ptr;
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(FN_READ_CODE(exc_fn))->u.native.fn_ptr;
|
||||
JS_PopGCRef(ctx, &callee_ref);
|
||||
continue;
|
||||
}
|
||||
@@ -998,7 +999,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
fp[ret_slot] = ret;
|
||||
/* Resume caller */
|
||||
JSFunction *caller_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(caller_fn->u.cell.code)->u.native.fn_ptr;
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(FN_READ_CODE(caller_fn))->u.native.fn_ptr;
|
||||
} else {
|
||||
/* Regular call: store result and resume current function */
|
||||
int ret_info = JS_VALUE_GET_INT(frame->address);
|
||||
@@ -1007,7 +1008,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
fp[ret_slot] = ret;
|
||||
/* fn stays the same — we resume the same function at next segment */
|
||||
JSFunction *cur_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(cur_fn->u.cell.code)->u.native.fn_ptr;
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(FN_READ_CODE(cur_fn))->u.native.fn_ptr;
|
||||
}
|
||||
}
|
||||
JS_PopGCRef(ctx, &callee_ref);
|
||||
@@ -1040,7 +1041,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
fp[ret_slot] = JS_EXCEPTION;
|
||||
|
||||
JSFunction *exc_caller_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(exc_caller_fn->u.cell.code)->u.native.fn_ptr;
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(FN_READ_CODE(exc_caller_fn))->u.native.fn_ptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1064,7 +1065,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
fp[ret_slot] = result;
|
||||
|
||||
JSFunction *caller_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(caller_fn->u.cell.code)->u.native.fn_ptr;
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(FN_READ_CODE(caller_fn))->u.native.fn_ptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1149,8 +1150,8 @@ JSValue cell_rt_frame(JSContext *ctx, JSValue fn, int64_t nargs) {
|
||||
}
|
||||
int nr_slots = (int)nargs + 2;
|
||||
JSFunction *f = JS_VALUE_GET_FUNCTION(fn);
|
||||
if (f->kind == JS_FUNC_KIND_NATIVE && JS_VALUE_GET_CODE(f->u.cell.code)->u.native.nr_slots > nr_slots)
|
||||
nr_slots = JS_VALUE_GET_CODE(f->u.cell.code)->u.native.nr_slots;
|
||||
if (f->kind == JS_FUNC_KIND_NATIVE && JS_VALUE_GET_CODE(FN_READ_CODE(f))->u.native.nr_slots > nr_slots)
|
||||
nr_slots = JS_VALUE_GET_CODE(FN_READ_CODE(f))->u.native.nr_slots;
|
||||
JSFrameRegister *new_frame = alloc_frame_register(ctx, nr_slots);
|
||||
if (!new_frame) return JS_EXCEPTION;
|
||||
new_frame->function = fn;
|
||||
|
||||
@@ -118,6 +118,7 @@ void *js_mallocz (JSContext *ctx, size_t size);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ASAN
|
||||
#include <sanitizer/asan_interface.h>
|
||||
static struct JSContext *__asan_js_ctx;
|
||||
#endif
|
||||
|
||||
@@ -747,6 +748,11 @@ struct JSContext {
|
||||
JSValue (*compile_regexp) (JSContext *ctx, JSValue pattern, JSValue flags);
|
||||
void *user_opaque;
|
||||
|
||||
/* GC callback to scan external C-side roots (actor letters, timers) */
|
||||
void (*gc_scan_external)(JSContext *ctx,
|
||||
uint8_t *from_base, uint8_t *from_end,
|
||||
uint8_t *to_base, uint8_t **to_free, uint8_t *to_end);
|
||||
|
||||
js_hook trace_hook;
|
||||
int trace_type;
|
||||
void *trace_data;
|
||||
@@ -990,6 +996,8 @@ typedef struct JSFunction {
|
||||
} u;
|
||||
} JSFunction;
|
||||
|
||||
#define FN_READ_CODE(fn) ((fn)->u.cell.code)
|
||||
|
||||
/* ============================================================
|
||||
Context-Neutral Module Format (Phase 2+)
|
||||
Struct definitions are in quickjs.h
|
||||
|
||||
@@ -330,6 +330,12 @@ 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);
|
||||
|
||||
typedef void (*JS_GCScanFn)(JSContext *ctx,
|
||||
uint8_t *from_base, uint8_t *from_end,
|
||||
uint8_t *to_base, uint8_t **to_free, uint8_t *to_end);
|
||||
void JS_SetGCScanExternal(JSContext *ctx, JS_GCScanFn fn);
|
||||
|
||||
void JS_SetActorSym (JSContext *ctx, JSValue sym);
|
||||
JSValue JS_GetActorSym (JSContext *ctx);
|
||||
JSRuntime *JS_GetRuntime (JSContext *ctx);
|
||||
|
||||
@@ -52,8 +52,8 @@ void heap_check_fail(void *ptr, JSContext *ctx) {
|
||||
JSFunction *fn = (JSFunction *)JS_VALUE_GET_PTR(frame->function);
|
||||
const char *name = NULL, *file = NULL;
|
||||
uint16_t line = 0;
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code) {
|
||||
JSCodeRegister *code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(FN_READ_CODE(fn))->u.reg.code) {
|
||||
JSCodeRegister *code = JS_VALUE_GET_CODE(FN_READ_CODE(fn))->u.reg.code;
|
||||
file = code->filename_cstr;
|
||||
name = code->name_cstr;
|
||||
if (!first)
|
||||
@@ -149,7 +149,8 @@ int JS_IsPretext (JSValue v) {
|
||||
}
|
||||
|
||||
JSValue *JS_PushGCRef (JSContext *ctx, JSGCRef *ref) {
|
||||
assert(ref != ctx->top_gc_ref && "JS_ROOT used in a loop — same address pushed twice");
|
||||
if (ref == ctx->top_gc_ref)
|
||||
return &ref->val; /* already at top — loop re-entry; just update val */
|
||||
ref->prev = ctx->top_gc_ref;
|
||||
ctx->top_gc_ref = ref;
|
||||
ref->val = JS_NULL;
|
||||
@@ -1370,14 +1371,14 @@ JSValue gc_copy_value (JSContext *ctx, JSValue v, uint8_t *from_base, uint8_t *f
|
||||
|
||||
/* Frame shortening: returned frames (caller == JS_NULL) only need
|
||||
[this][args][closure_locals] — shrink during copy. */
|
||||
if (type == OBJ_FRAME) {
|
||||
if (0 && type == OBJ_FRAME) {
|
||||
JSFrame *f = (JSFrame *)hdr_ptr;
|
||||
if (JS_IsNull (f->caller) && JS_IsPtr (f->function)) {
|
||||
/* fn may be forwarded, but kind (offset 18) and u.cell.code (offset 24)
|
||||
are past the 16 bytes overwritten by fwd+size. */
|
||||
JSFunction *fn = (JSFunction *)JS_VALUE_GET_PTR (f->function);
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER) {
|
||||
JSCode *jc = (JSCode *)JS_VALUE_GET_PTR (fn->u.cell.code);
|
||||
JSCode *jc = (JSCode *)JS_VALUE_GET_PTR (FN_READ_CODE(fn));
|
||||
if (jc && jc->kind == JS_CODE_KIND_REGISTER && jc->u.reg.code
|
||||
&& jc->u.reg.code->nr_close_slots > 0) {
|
||||
uint16_t cs = 1 + jc->u.reg.code->arity + jc->u.reg.code->nr_close_slots;
|
||||
@@ -1501,10 +1502,11 @@ void gc_scan_object (JSContext *ctx, void *ptr, uint8_t *from_base, uint8_t *fro
|
||||
objhdr_t fh = *(objhdr_t *)JS_VALUE_GET_PTR (frame->function);
|
||||
if (objhdr_type (fh) == OBJ_FUNCTION) {
|
||||
JSFunction *fn = (JSFunction *)JS_VALUE_GET_PTR (frame->function);
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code) {
|
||||
if (JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code->name_cstr) fname = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code->name_cstr;
|
||||
if (JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code->filename_cstr) ffile = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code->filename_cstr;
|
||||
fnslots = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code->nr_slots;
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(FN_READ_CODE(fn))->u.reg.code) {
|
||||
JSCodeRegister *_vc = JS_VALUE_GET_CODE(FN_READ_CODE(fn))->u.reg.code;
|
||||
if (_vc->name_cstr) fname = _vc->name_cstr;
|
||||
if (_vc->filename_cstr) ffile = _vc->filename_cstr;
|
||||
fnslots = _vc->nr_slots;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1610,8 +1612,8 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) {
|
||||
}
|
||||
if (objhdr_type (fnh) == OBJ_FUNCTION) {
|
||||
JSFunction *fnp = (JSFunction *)JS_VALUE_GET_PTR (fn_v);
|
||||
if (fnp->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(fnp->u.cell.code)->u.reg.code && JS_VALUE_GET_CODE(fnp->u.cell.code)->u.reg.code->name_cstr)
|
||||
fn_name = JS_VALUE_GET_CODE(fnp->u.cell.code)->u.reg.code->name_cstr;
|
||||
if (fnp->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(FN_READ_CODE(fnp))->u.reg.code && JS_VALUE_GET_CODE(FN_READ_CODE(fnp))->u.reg.code->name_cstr)
|
||||
fn_name = JS_VALUE_GET_CODE(FN_READ_CODE(fnp))->u.reg.code->name_cstr;
|
||||
}
|
||||
}
|
||||
fprintf (stderr, "VALIDATE_GC: pre-gc frame %p slot[%llu] -> %p (chased %p) bad type %d (hdr=0x%llx) fn=%s\n",
|
||||
@@ -1708,6 +1710,10 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan external C-side roots (actor letters, timers) */
|
||||
if (ctx->gc_scan_external)
|
||||
ctx->gc_scan_external(ctx, from_base, from_end, to_base, &to_free, to_end);
|
||||
|
||||
/* Cheney scan: scan copied objects to find more references */
|
||||
uint8_t *scan = to_base;
|
||||
#ifdef DUMP_GC_DETAIL
|
||||
@@ -1821,7 +1827,6 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Return old block (in poison mode, just poison it and leak) */
|
||||
heap_block_free (rt, from_base, old_heap_size);
|
||||
|
||||
/* Update context with new block */
|
||||
@@ -2147,6 +2152,10 @@ void JS_SetContextOpaque (JSContext *ctx, void *opaque) {
|
||||
ctx->user_opaque = opaque;
|
||||
}
|
||||
|
||||
void JS_SetGCScanExternal(JSContext *ctx, JS_GCScanFn fn) {
|
||||
ctx->gc_scan_external = fn;
|
||||
}
|
||||
|
||||
void JS_SetActorSym (JSContext *ctx, JSValue sym) {
|
||||
ctx->actor_sym = sym;
|
||||
}
|
||||
@@ -4813,7 +4822,7 @@ JSValue JS_CallInternal (JSContext *ctx, JSValue func_obj, JSValue this_obj,
|
||||
case JS_FUNC_KIND_C_DATA:
|
||||
return js_call_c_function (ctx, func_obj, this_obj, argc, argv);
|
||||
case JS_FUNC_KIND_REGISTER:
|
||||
return JS_CallRegisterVM (ctx, JS_VALUE_GET_CODE(f->u.cell.code)->u.reg.code, this_obj, argc, argv,
|
||||
return JS_CallRegisterVM (ctx, JS_VALUE_GET_CODE(FN_READ_CODE(f))->u.reg.code, this_obj, argc, argv,
|
||||
f->u.cell.env_record, f->u.cell.outer_frame);
|
||||
case JS_FUNC_KIND_NATIVE:
|
||||
return cell_native_dispatch (ctx, func_obj, this_obj, argc, argv);
|
||||
@@ -4846,7 +4855,7 @@ JSValue JS_Call (JSContext *ctx, JSValue func_obj, JSValue this_obj, int argc, J
|
||||
case JS_FUNC_KIND_C:
|
||||
return js_call_c_function (ctx, func_obj, this_obj, argc, argv);
|
||||
case JS_FUNC_KIND_REGISTER:
|
||||
return JS_CallRegisterVM (ctx, JS_VALUE_GET_CODE(f->u.cell.code)->u.reg.code, this_obj, argc, argv,
|
||||
return JS_CallRegisterVM (ctx, JS_VALUE_GET_CODE(FN_READ_CODE(f))->u.reg.code, this_obj, argc, argv,
|
||||
f->u.cell.env_record, f->u.cell.outer_frame);
|
||||
case JS_FUNC_KIND_NATIVE:
|
||||
return cell_native_dispatch (ctx, func_obj, this_obj, argc, argv);
|
||||
@@ -11614,8 +11623,8 @@ JSValue JS_GetStack(JSContext *ctx) {
|
||||
if (!JS_IsFunction(frame->function)) break;
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code) {
|
||||
JSCodeRegister *code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(FN_READ_CODE(fn))->u.reg.code) {
|
||||
JSCodeRegister *code = JS_VALUE_GET_CODE(FN_READ_CODE(fn))->u.reg.code;
|
||||
uint32_t pc = is_first ? cur_pc : (uint32_t)(JS_VALUE_GET_INT(frame->address) >> 16);
|
||||
frames[count].fn = code->name_cstr;
|
||||
frames[count].file = code->filename_cstr;
|
||||
@@ -11674,8 +11683,8 @@ void JS_CrashPrintStack(JSContext *ctx) {
|
||||
if (!JS_IsFunction(frame->function)) break;
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code) {
|
||||
JSCodeRegister *code = JS_VALUE_GET_CODE(fn->u.cell.code)->u.reg.code;
|
||||
if (fn->kind == JS_FUNC_KIND_REGISTER && JS_VALUE_GET_CODE(FN_READ_CODE(fn))->u.reg.code) {
|
||||
JSCodeRegister *code = JS_VALUE_GET_CODE(FN_READ_CODE(fn))->u.reg.code;
|
||||
uint32_t pc = is_first ? cur_pc : (uint32_t)(JS_VALUE_GET_INT(frame->address) >> 16);
|
||||
|
||||
const char *name = code->name_cstr ? code->name_cstr : "<anonymous>";
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "stb_ds.h"
|
||||
#include "cell.h"
|
||||
#include "quickjs-internal.h"
|
||||
#include "cell_internal.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -857,6 +858,36 @@ ENDTURN_SLOW:
|
||||
pthread_mutex_unlock(actor->mutex);
|
||||
}
|
||||
|
||||
/* GC callback: scan actor's letters and timers so the copying GC
|
||||
can relocate JSValues stored in C-side data structures. */
|
||||
void actor_gc_scan(JSContext *ctx,
|
||||
uint8_t *from_base, uint8_t *from_end,
|
||||
uint8_t *to_base, uint8_t **to_free, uint8_t *to_end)
|
||||
{
|
||||
cell_rt *actor = JS_GetContextOpaque(ctx);
|
||||
if (!actor) return;
|
||||
|
||||
/* Lock msg_mutex to synchronize with the timer thread, which reads
|
||||
timers and writes letters under the same lock. */
|
||||
pthread_mutex_lock(actor->msg_mutex);
|
||||
|
||||
for (int i = 0; i < arrlen(actor->letters); i++) {
|
||||
if (actor->letters[i].type == LETTER_CALLBACK) {
|
||||
actor->letters[i].callback = gc_copy_value(ctx,
|
||||
actor->letters[i].callback,
|
||||
from_base, from_end, to_base, to_free, to_end);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < hmlen(actor->timers); i++) {
|
||||
actor->timers[i].value = gc_copy_value(ctx,
|
||||
actor->timers[i].value,
|
||||
from_base, from_end, to_base, to_free, to_end);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(actor->msg_mutex);
|
||||
}
|
||||
|
||||
void actor_clock(cell_rt *actor, JSValue fn)
|
||||
{
|
||||
letter l;
|
||||
|
||||
Reference in New Issue
Block a user