From 259bc139fc304e15f9271793e5353e9320be6e0d Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Wed, 11 Feb 2026 10:17:55 -0600 Subject: [PATCH] rm stack usage --- source/mach.c | 74 +++++++++---------- source/mcode.c | 170 ++++++++++++++++++++----------------------- source/qbe_helpers.c | 11 +-- source/runtime.c | 2 - 4 files changed, 117 insertions(+), 140 deletions(-) diff --git a/source/mach.c b/source/mach.c index f180843f..7f6e88ca 100644 --- a/source/mach.c +++ b/source/mach.c @@ -2723,20 +2723,23 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, JS_PushGCRef(ctx, &of_gc); of_gc.val = outer_frame; - /* Protect argv and this_obj from GC by pushing onto value_stack. - argv is a C-allocated array whose JSValues may point to GC heap objects; + /* Protect argv and this_obj from GC using JSGCRef. alloc_frame_register and js_new_register_function can trigger GC. */ - int vs_save = ctx->value_stack_top; int nargs_copy = (argc < code->arity) ? argc : code->arity; - ctx->value_stack[vs_save] = this_obj; - for (int i = 0; i < nargs_copy; i++) - ctx->value_stack[vs_save + 1 + i] = argv[i]; - ctx->value_stack_top = vs_save + 1 + nargs_copy; + JSGCRef this_gc; + JS_PushGCRef(ctx, &this_gc); + this_gc.val = this_obj; + JSGCRef arg_gcs[nargs_copy > 0 ? nargs_copy : 1]; + for (int i = 0; i < nargs_copy; i++) { + JS_PushGCRef(ctx, &arg_gcs[i]); + arg_gcs[i].val = argv[i]; + } /* Allocate initial frame */ JSFrameRegister *frame = alloc_frame_register(ctx, code->nr_slots); if (!frame) { - ctx->value_stack_top = vs_save; + for (int i = nargs_copy - 1; i >= 0; i--) JS_PopGCRef(ctx, &arg_gcs[i]); + JS_PopGCRef(ctx, &this_gc); JS_PopGCRef(ctx, &of_gc); JS_PopGCRef(ctx, &env_gc); return JS_EXCEPTION; @@ -2758,13 +2761,14 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, JS_PopGCRef(ctx, &env_gc); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); frame->function = top_fn; - frame->slots[0] = ctx->value_stack[vs_save]; /* slot 0 = this (GC-safe from value_stack) */ + frame->slots[0] = this_gc.val; /* slot 0 = this */ - /* Copy arguments from GC-safe value_stack */ + /* Copy arguments from GC-safe refs */ for (int i = 0; i < nargs_copy; i++) { - frame->slots[1 + i] = ctx->value_stack[vs_save + 1 + i]; + frame->slots[1 + i] = arg_gcs[i].val; } - ctx->value_stack_top = vs_save; + for (int i = nargs_copy - 1; i >= 0; i--) JS_PopGCRef(ctx, &arg_gcs[i]); + JS_PopGCRef(ctx, &this_gc); uint32_t pc = code->entry_point; JSValue result = JS_NULL; @@ -3127,15 +3131,13 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, JSFunction *fn = JS_VALUE_GET_FUNCTION(func_val); if (fn->kind == JS_FUNC_KIND_C) { - /* C function: push args onto value stack (C-allocated, GC-scanned) */ - int vs_base = ctx->value_stack_top; + /* C function: copy args to C stack */ + JSValue args[nargs > 0 ? nargs : 1]; for (int i = 0; i < nargs; i++) - ctx->value_stack[vs_base + i] = frame->slots[base + 1 + i]; - ctx->value_stack_top = vs_base + nargs; + args[i] = frame->slots[base + 1 + i]; ctx->reg_current_frame = frame_ref.val; ctx->current_register_pc = pc > 0 ? pc - 1 : 0; - JSValue ret = js_call_c_function(ctx, func_val, JS_NULL, nargs, &ctx->value_stack[vs_base]); - ctx->value_stack_top = vs_base; + JSValue ret = js_call_c_function(ctx, func_val, JS_NULL, nargs, args); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); ctx->reg_current_frame = JS_NULL; if (JS_IsException(ret)) { goto disrupt; } @@ -3168,13 +3170,11 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, env = fn->u.reg.env_record; pc = code->entry_point; } else { - /* Other function kinds (bytecode) — push args onto value stack */ - int vs_base = ctx->value_stack_top; + /* Other function kinds (bytecode) — copy args to C stack */ + JSValue args[nargs > 0 ? nargs : 1]; for (int i = 0; i < nargs; i++) - ctx->value_stack[vs_base + i] = frame->slots[base + 1 + i]; - ctx->value_stack_top = vs_base + nargs; - JSValue ret = JS_CallInternal(ctx, func_val, JS_NULL, nargs, &ctx->value_stack[vs_base], 0); - ctx->value_stack_top = vs_base; + args[i] = frame->slots[base + 1 + i]; + JSValue ret = JS_CallInternal(ctx, func_val, JS_NULL, nargs, args, 0); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); if (JS_IsException(ret)) { goto disrupt; } if (nresults > 0) frame->slots[base] = ret; @@ -3204,15 +3204,11 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, JS_SetPropertyUint32(ctx, frame->slots[base + 1], i, frame->slots[base + 2 + i]); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); } - /* Push proxy args onto value stack; re-read obj since GC may have moved it */ - int vs_base = ctx->value_stack_top; - ctx->value_stack[vs_base] = key_ref.val; - ctx->value_stack[vs_base + 1] = frame->slots[base + 1]; /* the array */ - ctx->value_stack_top = vs_base + 2; + /* Call proxy with key and array from C stack */ + JSValue call_args[2] = { key_ref.val, frame->slots[base + 1] }; ctx->reg_current_frame = frame_ref.val; ctx->current_register_pc = pc > 0 ? pc - 1 : 0; - JSValue ret = JS_CallInternal(ctx, frame->slots[base], JS_NULL, 2, &ctx->value_stack[vs_base], 0); - ctx->value_stack_top = vs_base; + JSValue ret = JS_CallInternal(ctx, frame->slots[base], JS_NULL, 2, call_args, 0); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); ctx->reg_current_frame = JS_NULL; if (JS_IsException(ret)) { JS_PopGCRef(ctx, &key_ref); goto disrupt; } @@ -3239,14 +3235,12 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, } JSFunction *fn = JS_VALUE_GET_FUNCTION(method); if (fn->kind == JS_FUNC_KIND_C) { - int vs_base = ctx->value_stack_top; + JSValue args[nargs > 0 ? nargs : 1]; for (int i = 0; i < nargs; i++) - ctx->value_stack[vs_base + i] = frame->slots[base + 2 + i]; - ctx->value_stack_top = vs_base + nargs; + args[i] = frame->slots[base + 2 + i]; ctx->reg_current_frame = frame_ref.val; ctx->current_register_pc = pc > 0 ? pc - 1 : 0; - JSValue ret = js_call_c_function(ctx, method, frame->slots[base], nargs, &ctx->value_stack[vs_base]); - ctx->value_stack_top = vs_base; + JSValue ret = js_call_c_function(ctx, method, frame->slots[base], nargs, args); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); ctx->reg_current_frame = JS_NULL; if (JS_IsException(ret)) { JS_PopGCRef(ctx, &key_ref); goto disrupt; } @@ -3277,12 +3271,10 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, pc = code->entry_point; } else { /* Bytecode or other function */ - int vs_base = ctx->value_stack_top; + JSValue args[nargs > 0 ? nargs : 1]; for (int i = 0; i < nargs; i++) - ctx->value_stack[vs_base + i] = frame->slots[base + 2 + i]; - ctx->value_stack_top = vs_base + nargs; - JSValue ret = JS_CallInternal(ctx, method, frame->slots[base], nargs, &ctx->value_stack[vs_base], 0); - ctx->value_stack_top = vs_base; + args[i] = frame->slots[base + 2 + i]; + JSValue ret = JS_CallInternal(ctx, method, frame->slots[base], nargs, args, 0); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); if (JS_IsException(ret)) { JS_PopGCRef(ctx, &key_ref); goto disrupt; } frame->slots[base] = ret; diff --git a/source/mcode.c b/source/mcode.c index 96aabbb5..7a9534ba 100644 --- a/source/mcode.c +++ b/source/mcode.c @@ -176,18 +176,27 @@ JSValue js_new_mcode_function(JSContext *ctx, JSMCode *code) { /* Main MCODE interpreter — executes pre-parsed JSMCode */ JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, int argc, JSValue *argv, JSValue outer_frame) { - /* Protect argv, this_obj, outer_frame from GC by pushing onto value_stack. + /* Protect argv, this_obj, outer_frame from GC using JSGCRef. alloc_frame_register and js_new_mcode_function can trigger GC. */ - int vs_save = ctx->value_stack_top; int nargs_copy = (argc < code->nr_args) ? argc : code->nr_args; - ctx->value_stack[vs_save] = this_obj; - ctx->value_stack[vs_save + 1] = outer_frame; - for (int i = 0; i < nargs_copy; i++) - ctx->value_stack[vs_save + 2 + i] = argv[i]; - ctx->value_stack_top = vs_save + 2 + nargs_copy; + JSGCRef this_gc, of_gc; + JS_PushGCRef(ctx, &this_gc); + this_gc.val = this_obj; + JS_PushGCRef(ctx, &of_gc); + of_gc.val = outer_frame; + JSGCRef arg_gcs[nargs_copy > 0 ? nargs_copy : 1]; + for (int i = 0; i < nargs_copy; i++) { + JS_PushGCRef(ctx, &arg_gcs[i]); + arg_gcs[i].val = argv[i]; + } JSFrameRegister *frame = alloc_frame_register(ctx, code->nr_slots); - if (!frame) { ctx->value_stack_top = vs_save; return JS_EXCEPTION; } + if (!frame) { + for (int i = nargs_copy - 1; i >= 0; i--) JS_PopGCRef(ctx, &arg_gcs[i]); + JS_PopGCRef(ctx, &of_gc); + JS_PopGCRef(ctx, &this_gc); + return JS_EXCEPTION; + } /* Protect frame from GC */ JSGCRef frame_ref; @@ -197,22 +206,26 @@ JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, /* Create a function object for the main frame so return can find the code */ JSValue main_func = js_new_mcode_function(ctx, code); if (JS_IsException(main_func)) { - ctx->value_stack_top = vs_save; JS_DeleteGCRef(ctx, &frame_ref); + for (int i = nargs_copy - 1; i >= 0; i--) JS_PopGCRef(ctx, &arg_gcs[i]); + JS_PopGCRef(ctx, &of_gc); + JS_PopGCRef(ctx, &this_gc); return JS_ThrowInternalError(ctx, "failed to allocate main function for MCODE"); } frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); /* Set outer_frame AFTER allocation so it uses the post-GC value */ JSFunction *main_fn = JS_VALUE_GET_FUNCTION(main_func); - main_fn->u.mcode.outer_frame = ctx->value_stack[vs_save + 1]; + main_fn->u.mcode.outer_frame = of_gc.val; frame->function = main_func; - /* Setup initial frame from GC-safe value_stack */ - frame->slots[0] = ctx->value_stack[vs_save]; /* slot 0 is this */ + /* Setup initial frame from GC-safe refs */ + frame->slots[0] = this_gc.val; /* slot 0 is this */ for (int i = 0; i < nargs_copy; i++) { - frame->slots[1 + i] = ctx->value_stack[vs_save + 2 + i]; + frame->slots[1 + i] = arg_gcs[i].val; } - ctx->value_stack_top = vs_save; + for (int i = nargs_copy - 1; i >= 0; i--) JS_PopGCRef(ctx, &arg_gcs[i]); + JS_PopGCRef(ctx, &of_gc); + JS_PopGCRef(ctx, &this_gc); uint32_t pc = 0; JSValue result = JS_NULL; @@ -827,11 +840,8 @@ JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, int dest = (int)a1->valuedouble; JSValue v = frame->slots[(int)a2->valuedouble]; if (!JS_IsText(v)) { goto disrupt; } - int vs_base = ctx->value_stack_top; - ctx->value_stack[vs_base] = v; - ctx->value_stack_top = vs_base + 1; - JSValue res = js_cell_text_lower(ctx, JS_NULL, 1, &ctx->value_stack[vs_base]); - ctx->value_stack_top = vs_base; + JSValue tmp = v; + JSValue res = js_cell_text_lower(ctx, JS_NULL, 1, &tmp); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); frame->slots[dest] = res; } @@ -839,11 +849,8 @@ JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, int dest = (int)a1->valuedouble; JSValue v = frame->slots[(int)a2->valuedouble]; if (!JS_IsText(v)) { goto disrupt; } - int vs_base = ctx->value_stack_top; - ctx->value_stack[vs_base] = v; - ctx->value_stack_top = vs_base + 1; - JSValue res = js_cell_text_upper(ctx, JS_NULL, 1, &ctx->value_stack[vs_base]); - ctx->value_stack_top = vs_base; + JSValue tmp = v; + JSValue res = js_cell_text_upper(ctx, JS_NULL, 1, &tmp); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); frame->slots[dest] = res; } @@ -851,11 +858,8 @@ JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, int dest = (int)a1->valuedouble; JSValue v = frame->slots[(int)a2->valuedouble]; if (!JS_IsNumber(v)) { goto disrupt; } - int vs_base = ctx->value_stack_top; - ctx->value_stack[vs_base] = v; - ctx->value_stack_top = vs_base + 1; - JSValue res = js_cell_character(ctx, JS_NULL, 1, &ctx->value_stack[vs_base]); - ctx->value_stack_top = vs_base; + JSValue tmp = v; + JSValue res = js_cell_character(ctx, JS_NULL, 1, &tmp); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); frame->slots[dest] = res; } @@ -863,11 +867,8 @@ JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, int dest = (int)a1->valuedouble; JSValue v = frame->slots[(int)a2->valuedouble]; if (!JS_IsText(v)) { goto disrupt; } - int vs_base = ctx->value_stack_top; - ctx->value_stack[vs_base] = v; - ctx->value_stack_top = vs_base + 1; - JSValue res = js_cell_text_codepoint(ctx, JS_NULL, 1, &ctx->value_stack[vs_base]); - ctx->value_stack_top = vs_base; + JSValue tmp = v; + JSValue res = js_cell_text_codepoint(ctx, JS_NULL, 1, &tmp); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); frame->slots[dest] = res; } @@ -1472,18 +1473,15 @@ JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, code = fn->u.mcode.code; pc = 0; } else { - /* C or bytecode function — collect args on value stack (GC-safe) */ + /* C or bytecode function — collect args on C stack */ int nr_slots = (int)objhdr_cap56(new_frame->hdr); int c_argc = (nr_slots >= 2) ? nr_slots - 2 : 0; - int vs_base = ctx->value_stack_top; - for (int i = 0; i < c_argc; i++) { - ctx->value_stack[vs_base + i] = new_frame->slots[i + 1]; - } - ctx->value_stack_top = vs_base + c_argc; + JSValue args[c_argc > 0 ? c_argc : 1]; + for (int i = 0; i < c_argc; i++) + args[i] = new_frame->slots[i + 1]; ctx->reg_current_frame = frame_ref.val; ctx->current_register_pc = pc > 0 ? pc - 1 : 0; - JSValue c_result = JS_Call(ctx, new_frame->function, new_frame->slots[0], c_argc, &ctx->value_stack[vs_base]); - ctx->value_stack_top = vs_base; + JSValue c_result = JS_Call(ctx, new_frame->function, new_frame->slots[0], c_argc, args); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); ctx->reg_current_frame = JS_NULL; if (JS_IsException(c_result)) { goto disrupt; } @@ -1507,14 +1505,13 @@ JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, if (JS_IsFunction(obj)) { /* Proxy call: obj(name, [args...]) */ - /* Store key on value stack immediately to protect from GC */ - int vs_base = ctx->value_stack_top; - ctx->value_stack[vs_base] = JS_NewString(ctx, method_name); + JSGCRef key_gc; + JS_PushGCRef(ctx, &key_gc); + key_gc.val = JS_NewString(ctx, method_name); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); - ctx->value_stack_top = vs_base + 1; /* protect key from GC */ JSValue arr = JS_NewArray(ctx); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); - if (JS_IsException(arr)) goto disrupt; + if (JS_IsException(arr)) { JS_PopGCRef(ctx, &key_gc); goto disrupt; } frame->slots[dest] = arr; /* protect from GC */ cJSON *p = a3->next; for (int i = 0; i < nargs; i++, p = p->next) { @@ -1523,14 +1520,13 @@ JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, JS_SetPropertyUint32(ctx, frame->slots[dest], i, frame->slots[areg]); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); } - ctx->value_stack[vs_base + 1] = frame->slots[dest]; - ctx->value_stack_top = vs_base + 2; + JSValue call_args[2] = { key_gc.val, frame->slots[dest] }; ctx->reg_current_frame = frame_ref.val; ctx->current_register_pc = pc > 0 ? pc - 1 : 0; - JSValue ret = JS_CallInternal(ctx, frame->slots[obj_reg], JS_NULL, 2, &ctx->value_stack[vs_base], 0); - ctx->value_stack_top = vs_base; + JSValue ret = JS_CallInternal(ctx, frame->slots[obj_reg], JS_NULL, 2, call_args, 0); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); ctx->reg_current_frame = JS_NULL; + JS_PopGCRef(ctx, &key_gc); if (JS_IsException(ret)) goto disrupt; frame->slots[dest] = ret; } else { @@ -1570,17 +1566,15 @@ JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, pc = 0; } else { /* C or bytecode function */ - int vs_base = ctx->value_stack_top; + JSValue args[nargs > 0 ? nargs : 1]; cJSON *p = a3->next; for (int i = 0; i < nargs; i++, p = p->next) { if (cJSON_IsString(p)) break; - ctx->value_stack[vs_base + i] = frame->slots[(int)p->valuedouble]; + args[i] = frame->slots[(int)p->valuedouble]; } - ctx->value_stack_top = vs_base + nargs; ctx->reg_current_frame = frame_ref.val; ctx->current_register_pc = pc > 0 ? pc - 1 : 0; - JSValue ret = JS_Call(ctx, method, frame->slots[obj_reg], nargs, &ctx->value_stack[vs_base]); - ctx->value_stack_top = vs_base; + JSValue ret = JS_Call(ctx, method, frame->slots[obj_reg], nargs, args); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); ctx->reg_current_frame = JS_NULL; if (JS_IsException(ret)) goto disrupt; @@ -1606,10 +1600,8 @@ JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, if (JS_IsFunction(obj) && JS_VALUE_IS_TEXT(key) && JS_VALUE_GET_FUNCTION(obj)->length == 2) { - /* Proxy call (arity-2 functions only): obj(key, [args...]) */ - int vs_base = ctx->value_stack_top; - ctx->value_stack[vs_base] = key; /* protect key on value stack */ - ctx->value_stack_top = vs_base + 1; /* protect key from GC */ + /* Proxy call (arity-2 functions only): obj(key, [args...]) + key lives in frame->slots[key_reg], which is GC-safe */ JSValue arr = JS_NewArray(ctx); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); if (JS_IsException(arr)) goto disrupt; @@ -1620,12 +1612,10 @@ JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, JS_SetPropertyUint32(ctx, frame->slots[dest], i, frame->slots[areg]); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); } - ctx->value_stack[vs_base + 1] = frame->slots[dest]; - ctx->value_stack_top = vs_base + 2; + JSValue call_args[2] = { frame->slots[key_reg], frame->slots[dest] }; ctx->reg_current_frame = frame_ref.val; ctx->current_register_pc = pc > 0 ? pc - 1 : 0; - JSValue ret = JS_CallInternal(ctx, frame->slots[obj_reg], JS_NULL, 2, &ctx->value_stack[vs_base], 0); - ctx->value_stack_top = vs_base; + JSValue ret = JS_CallInternal(ctx, frame->slots[obj_reg], JS_NULL, 2, call_args, 0); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); ctx->reg_current_frame = JS_NULL; if (JS_IsException(ret)) goto disrupt; @@ -1667,16 +1657,14 @@ JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, code = fn->u.mcode.code; pc = 0; } else { - int vs_base = ctx->value_stack_top; + JSValue args[nargs > 0 ? nargs : 1]; cJSON *p = a3->next; for (int i = 0; i < nargs; i++, p = p->next) { - ctx->value_stack[vs_base + i] = frame->slots[(int)p->valuedouble]; + args[i] = frame->slots[(int)p->valuedouble]; } - ctx->value_stack_top = vs_base + nargs; ctx->reg_current_frame = frame_ref.val; ctx->current_register_pc = pc > 0 ? pc - 1 : 0; - JSValue ret = JS_Call(ctx, method, frame->slots[obj_reg], nargs, &ctx->value_stack[vs_base]); - ctx->value_stack_top = vs_base; + JSValue ret = JS_Call(ctx, method, frame->slots[obj_reg], nargs, args); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); ctx->reg_current_frame = JS_NULL; if (JS_IsException(ret)) goto disrupt; @@ -1767,17 +1755,19 @@ JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); int len = JS_IsNumber(len_val) ? (int)JS_VALUE_GET_INT(len_val) : 0; if (len > 256) len = 256; - int vs_base = ctx->value_stack_top; + JSGCRef arg_refs[len > 0 ? len : 1]; for (int i = 0; i < len; i++) { - ctx->value_stack[vs_base + i] = JS_GetPropertyUint32(ctx, frame->slots[arr_slot], i); + JS_PushGCRef(ctx, &arg_refs[i]); + arg_refs[i].val = JS_GetPropertyUint32(ctx, frame->slots[arr_slot], i); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); } - ctx->value_stack_top = vs_base + len; + JSValue args[len > 0 ? len : 1]; + for (int i = 0; i < len; i++) args[i] = arg_refs[i].val; ctx->reg_current_frame = frame_ref.val; ctx->current_register_pc = pc > 0 ? pc - 1 : 0; - result = JS_Call(ctx, frame->slots[func_slot], JS_NULL, len, &ctx->value_stack[vs_base]); - ctx->value_stack_top = vs_base; + result = JS_Call(ctx, frame->slots[func_slot], JS_NULL, len, args); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); + for (int i = len - 1; i >= 0; i--) JS_PopGCRef(ctx, &arg_refs[i]); if (JS_IsException(result)) { goto disrupt; } } @@ -1846,13 +1836,8 @@ JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, int pt_slot = (int)a1->valuedouble; int right_slot = (int)a2->valuedouble; if (!JS_IsText(frame->slots[pt_slot]) || !JS_IsText(frame->slots[right_slot])) { goto disrupt; } - int vs_base = ctx->value_stack_top; - ctx->value_stack[vs_base] = frame->slots[pt_slot]; - ctx->value_stack[vs_base + 1] = frame->slots[right_slot]; - ctx->value_stack_top = vs_base + 2; - JSText *s = JS_VALUE_GET_PTR(ctx->value_stack[vs_base]); - s = pretext_concat_value(ctx, s, ctx->value_stack[vs_base + 1]); - ctx->value_stack_top = vs_base; + JSText *s = JS_VALUE_GET_PTR(frame->slots[pt_slot]); + s = pretext_concat_value(ctx, s, frame->slots[right_slot]); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); if (!s) { goto disrupt; } frame->slots[pt_slot] = JS_MKPTR(s); @@ -1875,19 +1860,24 @@ JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, const char *flags_str = a3 ? a3->valuestring : ""; if (!pattern) pattern = ""; if (!flags_str) flags_str = ""; - int vs_base = ctx->value_stack_top; - ctx->value_stack[vs_base] = JS_NewString(ctx, pattern); /* pat_val */ + JSGCRef pat_gc, flags_gc; + JS_PushGCRef(ctx, &pat_gc); + pat_gc.val = JS_NewString(ctx, pattern); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); - ctx->value_stack_top = vs_base + 1; /* protect pattern from GC */ - ctx->value_stack[vs_base + 1] = *flags_str ? JS_NewString(ctx, flags_str) : JS_NULL; /* flags_val */ + JS_PushGCRef(ctx, &flags_gc); + flags_gc.val = *flags_str ? JS_NewString(ctx, flags_str) : JS_NULL; frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); - ctx->value_stack_top = vs_base + 2; - JSValue bc = js_compile_regexp(ctx, ctx->value_stack[vs_base], ctx->value_stack[vs_base + 1]); + JSValue bc = js_compile_regexp(ctx, pat_gc.val, flags_gc.val); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); - if (JS_IsException(bc)) { ctx->value_stack_top = vs_base; goto disrupt; } - JSValue re_obj = js_regexp_constructor_internal(ctx, ctx->value_stack[vs_base], bc); + if (JS_IsException(bc)) { + JS_PopGCRef(ctx, &flags_gc); + JS_PopGCRef(ctx, &pat_gc); + goto disrupt; + } + JSValue re_obj = js_regexp_constructor_internal(ctx, pat_gc.val, bc); frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val); - ctx->value_stack_top = vs_base; + JS_PopGCRef(ctx, &flags_gc); + JS_PopGCRef(ctx, &pat_gc); if (JS_IsException(re_obj)) { goto disrupt; } frame->slots[dest] = re_obj; } diff --git a/source/qbe_helpers.c b/source/qbe_helpers.c index d5aab35d..7f23b41f 100644 --- a/source/qbe_helpers.c +++ b/source/qbe_helpers.c @@ -336,15 +336,12 @@ JSValue cell_rt_invoke(JSContext *ctx, JSValue frame_val) { int nr_slots = (int)objhdr_cap56(fr->hdr); int c_argc = (nr_slots >= 2) ? nr_slots - 2 : 0; - /* Push args onto value stack (GC-safe) */ - int vs_base = ctx->value_stack_top; + /* Copy args to C stack */ + JSValue args[c_argc > 0 ? c_argc : 1]; for (int i = 0; i < c_argc; i++) - ctx->value_stack[vs_base + i] = fr->slots[i + 1]; - ctx->value_stack_top = vs_base + c_argc; + args[i] = fr->slots[i + 1]; - JSValue result = JS_Call(ctx, fr->function, fr->slots[0], - c_argc, &ctx->value_stack[vs_base]); - ctx->value_stack_top = vs_base; + JSValue result = JS_Call(ctx, fr->function, fr->slots[0], c_argc, args); if (JS_IsException(result)) return JS_EXCEPTION; return result; diff --git a/source/runtime.c b/source/runtime.c index 8d0979eb..1059f378 100644 --- a/source/runtime.c +++ b/source/runtime.c @@ -1441,7 +1441,6 @@ JSContext *JS_NewContextRawWithHeapSize (JSRuntime *rt, size_t heap_size) { /* Initialize per-context execution state (moved from JSRuntime) */ ctx->current_exception = JS_UNINITIALIZED; - JS_UpdateStackTop (ctx); /* Initialize stone text intern table */ ctx->st_pages = NULL; @@ -4264,7 +4263,6 @@ JSValue js_call_c_function (JSContext *ctx, JSValue func_obj, JSValue this_obj, JSValue ret_val; JSValue *arg_buf; int arg_count, i; - int saved_vs_top = -1; /* for value stack padding cleanup */ JSCFunctionEnum cproto; f = JS_VALUE_GET_FUNCTION (func_obj);