fix mach crashes

This commit is contained in:
2026-02-06 23:15:33 -06:00
parent 024d796ca4
commit 1e4646999d

View File

@@ -104,7 +104,7 @@
// #define DUMP_ROPE_REBALANCE
/* test the GC by forcing it before each object allocation */
#define FORCE_GC_AT_MALLOC
/* #define FORCE_GC_AT_MALLOC */
#define POISON_HEAP
/* POISON_HEAP: Use ASan's memory poisoning to detect stale pointer access */
@@ -3448,6 +3448,32 @@ static JSValue js_sub_string (JSContext *ctx, JSText *p, int start, int end) {
return pretext_end (ctx, str);
}
/* Substring from a JSValue (handles both immediate ASCII and heap strings) */
static JSValue js_sub_string_val (JSContext *ctx, JSValue src, int start, int end) {
int len = end - start;
if (len <= 0) return JS_NewString (ctx, "");
if (MIST_IsImmediateASCII (src)) {
/* IMM: extract chars directly, try to return IMM */
if (len <= MIST_ASCII_MAX_LEN) {
char buf[MIST_ASCII_MAX_LEN + 1];
for (int i = 0; i < len; i++)
buf[i] = (char)MIST_GetImmediateASCIIChar (src, start + i);
return js_new_string8_len (ctx, buf, len);
}
/* Longer than 7 — shouldn't happen for IMM (max 7 chars) but handle it */
JSText *str = js_alloc_string (ctx, len);
if (!str) return JS_EXCEPTION;
for (int i = 0; i < len; i++)
string_put (str, i, MIST_GetImmediateASCIIChar (src, start + i));
str->length = len;
return pretext_end (ctx, str);
}
/* Heap string — delegate to existing js_sub_string */
return js_sub_string (ctx, JS_VALUE_GET_STRING (src), start, end);
}
/* Allocate a new pretext (mutable JSText) with initial capacity */
static JSText *pretext_init (JSContext *ctx, int capacity) {
if (capacity <= 0) capacity = 16;
@@ -21507,12 +21533,8 @@ static JSValue js_cell_character (JSContext *ctx, JSValue this_val, int argc, JS
/* Handle string - return first character */
if (tag == JS_TAG_STRING || tag == JS_TAG_STRING_IMM) {
JSText *p = JS_VALUE_GET_STRING (arg);
if (JSText_len (p) == 0) return JS_NewString (ctx, "");
/* UTF-32: each element is a full code point, no surrogate handling needed
*/
return js_sub_string (ctx, p, 0, 1);
if (js_string_value_len (arg) == 0) return JS_NewString (ctx, "");
return js_sub_string_val (ctx, arg, 0, 1);
}
/* Handle integer - return character from codepoint */
@@ -21569,17 +21591,14 @@ static JSValue js_cell_text (JSContext *ctx, JSValue this_val, int argc, JSValue
if (argc == 1) return str;
JSText *p = JS_VALUE_GET_STRING (str);
int len = (int)JSText_len (p);
if (argc >= 2) {
int tag1 = JS_VALUE_GET_TAG (argv[1]);
if (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64) {
int len = js_string_value_len (str);
int from, to;
if (JS_ToInt32 (ctx, &from, argv[1])) {
if (JS_ToInt32 (ctx, &from, argv[1]))
return JS_EXCEPTION;
}
if (from < 0) from += len;
if (from < 0) from = 0;
@@ -21587,20 +21606,17 @@ static JSValue js_cell_text (JSContext *ctx, JSValue this_val, int argc, JSValue
to = len;
if (argc >= 3) {
if (JS_ToInt32 (ctx, &to, argv[2])) {
if (JS_ToInt32 (ctx, &to, argv[2]))
return JS_EXCEPTION;
}
if (to < 0) to += len;
if (to < 0) to = 0;
if (to > len) to = len;
}
if (from > to) {
if (from > to)
return JS_NULL;
}
JSValue sub = js_sub_string (ctx, p, from, to);
return sub;
return js_sub_string_val (ctx, str, from, to);
}
}
@@ -22106,9 +22122,7 @@ static JSValue js_cell_text_replace (JSContext *ctx, JSValue this_val, int argc,
}
if (boundary < len) {
/* Re-chase sp after GC points */
JSText *sp = JS_VALUE_GET_STRING (argv[0]);
JSValue ch = js_sub_string (ctx, sp, boundary, boundary + 1);
JSValue ch = js_sub_string_val (ctx, argv[0], boundary, boundary + 1);
if (JS_IsException (ch)) goto fail_str_target;
b = pretext_concat_value (ctx, b, ch);
if (!b) goto fail_str_target;
@@ -22120,7 +22134,6 @@ static JSValue js_cell_text_replace (JSContext *ctx, JSValue this_val, int argc,
int pos = 0;
int32_t count = 0;
JSText *sp;
while (pos <= len - t_len && (limit < 0 || count < limit)) {
int found = -1;
@@ -22194,7 +22207,6 @@ static JSValue js_cell_text_replace (JSContext *ctx, JSValue this_val, int argc,
if (!b) goto fail_str_target;
}
(void)sp; /* Suppress unused variable warning */
return pretext_end (ctx, b);
fail_str_target:
@@ -22214,8 +22226,7 @@ static JSValue js_cell_text_replace (JSContext *ctx, JSValue this_val, int argc,
if (JS_SetPropertyStr (ctx, rx, "lastIndex", JS_NewInt32 (ctx, 0)) < 0)
goto fail_rx;
JSText *sp = JS_VALUE_GET_STRING (argv[0]); /* Re-chase before js_sub_string */
JSValue sub_str = js_sub_string (ctx, sp, pos, len);
JSValue sub_str = js_sub_string_val (ctx, argv[0], pos, len);
if (JS_IsException (sub_str)) goto fail_rx;
JSValue exec_res
@@ -22262,8 +22273,7 @@ static JSValue js_cell_text_replace (JSContext *ctx, JSValue this_val, int argc,
if (match_len < 0) match_len = 0;
if (found > pos) {
sp = JS_VALUE_GET_STRING (argv[0]); /* Re-chase before js_sub_string */
JSValue prefix = js_sub_string (ctx, sp, pos, found);
JSValue prefix = js_sub_string_val (ctx, argv[0], pos, found);
if (JS_IsException (prefix)) goto fail_rx;
b = pretext_concat_value (ctx, b, prefix);
if (!b) goto fail_rx;
@@ -22290,8 +22300,7 @@ static JSValue js_cell_text_replace (JSContext *ctx, JSValue this_val, int argc,
}
if (pos < len) {
JSText *sp = JS_VALUE_GET_STRING (argv[0]); /* Re-chase before js_sub_string */
JSValue tail = js_sub_string (ctx, sp, pos, len);
JSValue tail = js_sub_string_val (ctx, argv[0], pos, len);
if (JS_IsException (tail)) goto fail_rx;
b = pretext_concat_value (ctx, b, tail);
if (!b) goto fail_rx;
@@ -23316,8 +23325,7 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
/* array(text, separator) - split by separator */
/* array(text, length) - dice into chunks */
if (JS_VALUE_IS_TEXT (arg)) {
JSText *p = JS_VALUE_GET_STRING (arg);
int len = (int)JSText_len (p);
int len = js_string_value_len (arg);
if (argc < 2 || JS_IsNull (argv[1])) {
/* Split into characters */
@@ -23325,7 +23333,7 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
if (JS_IsException (result)) { return result; }
JSArray *out = JS_VALUE_GET_ARRAY (result);
for (int i = 0; i < len; i++) {
JSValue ch = js_sub_string (ctx, p, i, i + 1);
JSValue ch = js_sub_string_val (ctx, arg, i, i + 1);
if (JS_IsException (ch)) {
return JS_EXCEPTION;
}
@@ -23374,7 +23382,7 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
if (sep_len == 0) {
for (int i = 0; i < len; i++) {
JSValue ch = js_sub_string (ctx, p, i, i + 1);
JSValue ch = js_sub_string_val (ctx, arg, i, i + 1);
JS_SetPropertyInt64 (ctx, result, idx++, ch);
}
} else {
@@ -23409,12 +23417,10 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
int64_t out_idx = 0;
while (pos <= len) {
/* force lastIndex = 0 so flags don't matter and we fully control
* iteration */
if (JS_SetPropertyStr (ctx, rx, "lastIndex", JS_NewInt32 (ctx, 0)) < 0)
goto fail_rx_split;
JSValue sub_str = js_sub_string (ctx, p, pos, len);
JSValue sub_str = js_sub_string_val (ctx, arg, pos, len);
if (JS_IsException (sub_str)) goto fail_rx_split;
JSValue exec_res
@@ -23422,59 +23428,44 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
if (JS_IsException (exec_res)) goto fail_rx_split;
if (JS_IsNull (exec_res)) {
/* remainder */
JSValue tail = js_sub_string (ctx, p, pos, len);
JSValue tail = js_sub_string_val (ctx, arg, pos, len);
if (JS_IsException (tail)) goto fail_rx_split;
if (JS_ArrayPush (ctx, &result, tail) < 0) { goto fail_rx_split; }
break;
}
/* local match index within sub_str */
JSValue idx_val = JS_GetPropertyStr (ctx, exec_res, "index");
if (JS_IsException (idx_val)) {
goto fail_rx_split;
}
if (JS_IsException (idx_val)) goto fail_rx_split;
int32_t local_index = 0;
if (JS_ToInt32 (ctx, &local_index, idx_val)) {
goto fail_rx_split;
}
if (JS_ToInt32 (ctx, &local_index, idx_val)) goto fail_rx_split;
if (local_index < 0) local_index = 0;
int found = pos + local_index;
if (found < pos) found = pos;
if (found > len) {
/* treat as no more matches */
JSValue tail = js_sub_string (ctx, p, pos, len);
JSValue tail = js_sub_string_val (ctx, arg, pos, len);
if (JS_IsException (tail)) goto fail_rx_split;
JS_SetPropertyInt64 (ctx, result, out_idx++, tail);
break;
}
JSValue end_val = JS_GetPropertyStr (ctx, exec_res, "end");
if (JS_IsException (end_val)) {
goto fail_rx_split;
}
if (JS_IsException (end_val)) goto fail_rx_split;
int32_t end = 0;
if (JS_ToInt32 (ctx, &end, end_val)) {
goto fail_rx_split;
}
if (JS_ToInt32 (ctx, &end, end_val)) goto fail_rx_split;
int match_len = end - local_index;
if (match_len < 0) match_len = 0;
/* emit piece before match */
JSValue part = js_sub_string (ctx, p, pos, found);
JSValue part = js_sub_string_val (ctx, arg, pos, found);
if (JS_IsException (part)) goto fail_rx_split;
if (JS_ArrayPush (ctx, &result, part) < 0) { goto fail_rx_split; }
/* advance past match; ensure progress on empty matches */
pos = found + match_len;
if (match_len == 0) {
if (found >= len) {
/* match at end: add trailing empty field and stop */
JSValue empty = JS_NewStringLen (ctx, "", 0);
if (JS_IsException (empty)) goto fail_rx_split;
if (JS_ArrayPush (ctx, &result, empty) < 0) { goto fail_rx_split; }
@@ -23484,58 +23475,42 @@ static JSValue js_cell_array (JSContext *ctx, JSValue this_val, int argc, JSValu
}
}
/* restore lastIndex */
JS_SetPropertyStr (ctx, rx, "lastIndex", orig_last_index);
/* str removed - arg not owned */
return result;
fail_rx_split:
/* best-effort restore lastIndex */
if (!JS_IsException (orig_last_index)) {
JS_SetPropertyStr (ctx, rx, "lastIndex", orig_last_index);
} else {
}
/* str removed - arg not owned */
return JS_EXCEPTION;
}
if (JS_VALUE_IS_NUMBER (argv[1])) {
/* Dice into chunks */
int chunk_len;
if (JS_ToInt32 (ctx, &chunk_len, argv[1])) {
/* str removed - arg not owned */
if (JS_ToInt32 (ctx, &chunk_len, argv[1]))
return JS_NULL;
}
if (chunk_len <= 0) {
/* str removed - arg not owned */
if (chunk_len <= 0)
return JS_NULL;
}
int64_t count = (len + chunk_len - 1) / chunk_len;
JSValue result = JS_NewArrayLen (ctx, count);
if (JS_IsException (result)) {
/* str removed - arg not owned */
if (JS_IsException (result))
return result;
}
int64_t idx = 0;
for (int i = 0; i < len; i += chunk_len) {
int end = i + chunk_len;
if (end > len) end = len;
JSValue chunk = js_sub_string (ctx, p, i, end);
if (JS_IsException (chunk)) {
/* str removed - arg not owned */
JSValue chunk = js_sub_string_val (ctx, arg, i, end);
if (JS_IsException (chunk))
return JS_EXCEPTION;
}
JS_SetPropertyInt64 (ctx, result, idx++, chunk);
}
/* str removed - arg not owned */
return result;
}
/* str removed - arg not owned */
return JS_NULL;
}
@@ -31133,7 +31108,7 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
}
/* Assignment */
if (strcmp(kind, "=") == 0) {
if (strcmp(kind, "assign") == 0) {
cJSON *left = cJSON_GetObjectItem(node, "left");
cJSON *right = cJSON_GetObjectItem(node, "right");
const char *lk = cJSON_GetStringValue(cJSON_GetObjectItem(left, "kind"));
@@ -31523,18 +31498,31 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
mach_emit(cs, MACH_AsBx(MACH_JMPFALSE, cr, 0));
mach_free_reg_to(cs, save);
/* Compile then branch */
/* Compile then branch — "then" is a direct array of statements */
if (then_body) {
cJSON *stmts = cJSON_GetObjectItem(then_body, "statements");
if (stmts && cJSON_IsArray(stmts)) {
int count = cJSON_GetArraySize(stmts);
if (cJSON_IsArray(then_body)) {
int count = cJSON_GetArraySize(then_body);
for (int i = 0; i < count; i++)
mach_compile_stmt(cs, cJSON_GetArrayItem(stmts, i));
mach_compile_stmt(cs, cJSON_GetArrayItem(then_body, i));
} else {
mach_compile_stmt(cs, then_body);
cJSON *stmts = cJSON_GetObjectItem(then_body, "statements");
if (stmts && cJSON_IsArray(stmts)) {
int count = cJSON_GetArraySize(stmts);
for (int i = 0; i < count; i++)
mach_compile_stmt(cs, cJSON_GetArrayItem(stmts, i));
} else {
mach_compile_stmt(cs, then_body);
}
}
}
/* Check for else-if chain ("list") or plain else */
if (!else_body) {
cJSON *list = cJSON_GetObjectItem(stmt, "list");
if (list && cJSON_IsArray(list) && cJSON_GetArraySize(list) > 0)
else_body = cJSON_GetArrayItem(list, 0);
}
if (else_body) {
int jmpend_pc = mach_current_pc(cs);
mach_emit(cs, MACH_sJ(MACH_JMP, 0));
@@ -31543,14 +31531,20 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
int offset = mach_current_pc(cs) - (jmpfalse_pc + 1);
cs->code[jmpfalse_pc] = MACH_AsBx(MACH_JMPFALSE, cr, (int16_t)offset);
/* Compile else */
cJSON *stmts = cJSON_GetObjectItem(else_body, "statements");
if (stmts && cJSON_IsArray(stmts)) {
int count = cJSON_GetArraySize(stmts);
/* Compile else — could be a direct array, object, or else-if stmt */
if (cJSON_IsArray(else_body)) {
int count = cJSON_GetArraySize(else_body);
for (int i = 0; i < count; i++)
mach_compile_stmt(cs, cJSON_GetArrayItem(stmts, i));
mach_compile_stmt(cs, cJSON_GetArrayItem(else_body, i));
} else {
mach_compile_stmt(cs, else_body);
cJSON *stmts = cJSON_GetObjectItem(else_body, "statements");
if (stmts && cJSON_IsArray(stmts)) {
int count = cJSON_GetArraySize(stmts);
for (int i = 0; i < count; i++)
mach_compile_stmt(cs, cJSON_GetArrayItem(stmts, i));
} else {
mach_compile_stmt(cs, else_body);
}
}
/* Patch jmpend */
@@ -31568,8 +31562,11 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
if (strcmp(kind, "while") == 0) {
cJSON *cond = cJSON_GetObjectItem(stmt, "expression");
if (!cond) cond = cJSON_GetObjectItem(stmt, "condition");
cJSON *body = cJSON_GetObjectItem(stmt, "block");
if (!body) body = cJSON_GetObjectItem(stmt, "body");
int old_break = cs->loop_break;
int old_continue = cs->loop_continue;
cs->loop_break = -1;
cs->loop_continue = -1;
int loop_top = mach_current_pc(cs);
@@ -31579,18 +31576,32 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
mach_emit(cs, MACH_AsBx(MACH_JMPFALSE, cr, 0));
mach_free_reg_to(cs, save);
/* Compile body */
if (body) {
cJSON *stmts = cJSON_GetObjectItem(body, "statements");
/* Compile body — "statements" on a child "block"/"body", or directly on the node */
{
cJSON *body = cJSON_GetObjectItem(stmt, "block");
if (!body) body = cJSON_GetObjectItem(stmt, "body");
cJSON *stmts = body ? cJSON_GetObjectItem(body, "statements") : NULL;
if (!stmts) stmts = cJSON_GetObjectItem(stmt, "statements");
if (stmts && cJSON_IsArray(stmts)) {
int count = cJSON_GetArraySize(stmts);
for (int i = 0; i < count; i++)
mach_compile_stmt(cs, cJSON_GetArrayItem(stmts, i));
} else {
} else if (body) {
mach_compile_stmt(cs, body);
}
}
/* Patch continue chain to loop_top */
{
int cp = cs->loop_continue;
while (cp >= 0) {
int prev = MACH_GET_sJ(cs->code[cp]);
int off = loop_top - (cp + 1);
cs->code[cp] = MACH_sJ(MACH_JMP, off);
cp = prev;
}
}
/* Jump back to loop top */
int offset = loop_top - (mach_current_pc(cs) + 1);
mach_emit(cs, MACH_sJ(MACH_JMP, offset));
@@ -31598,18 +31609,33 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
/* Patch jmpfalse to after loop */
offset = mach_current_pc(cs) - (jmpfalse_pc + 1);
cs->code[jmpfalse_pc] = MACH_AsBx(MACH_JMPFALSE, cr, (int16_t)offset);
/* Patch break chain */
int bp = cs->loop_break;
while (bp >= 0) {
int prev = MACH_GET_sJ(cs->code[bp]);
offset = mach_current_pc(cs) - (bp + 1);
cs->code[bp] = MACH_sJ(MACH_JMP, offset);
bp = prev;
}
cs->loop_break = old_break;
cs->loop_continue = old_continue;
return;
}
/* For loop */
if (strcmp(kind, "for") == 0) {
cJSON *init = cJSON_GetObjectItem(stmt, "initial");
cJSON *cond = cJSON_GetObjectItem(stmt, "condition");
if (!cond) cond = cJSON_GetObjectItem(stmt, "expression");
cJSON *init = cJSON_GetObjectItem(stmt, "init");
cJSON *cond = cJSON_GetObjectItem(stmt, "test");
cJSON *update = cJSON_GetObjectItem(stmt, "update");
cJSON *body = cJSON_GetObjectItem(stmt, "block");
if (!body) body = cJSON_GetObjectItem(stmt, "body");
int old_break = cs->loop_break;
int old_continue = cs->loop_continue;
cs->loop_break = -1;
cs->loop_continue = -1;
/* Init */
if (init) mach_compile_stmt(cs, init);
@@ -31625,23 +31651,34 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
mach_free_reg_to(cs, save);
}
/* Body */
if (body) {
cJSON *stmts = cJSON_GetObjectItem(body, "statements");
/* Body — "statements" on a child "block"/"body", or directly on the for node */
{
cJSON *stmts = body ? cJSON_GetObjectItem(body, "statements") : NULL;
if (!stmts) stmts = cJSON_GetObjectItem(stmt, "statements");
if (stmts && cJSON_IsArray(stmts)) {
int count = cJSON_GetArraySize(stmts);
for (int i = 0; i < count; i++)
mach_compile_stmt(cs, cJSON_GetArrayItem(stmts, i));
} else {
} else if (body) {
mach_compile_stmt(cs, body);
}
}
/* Update */
/* Patch continue chain to update (or loop_top if no update) */
{
int continue_target = mach_current_pc(cs);
int cp = cs->loop_continue;
while (cp >= 0) {
int prev = MACH_GET_sJ(cs->code[cp]);
int off = continue_target - (cp + 1);
cs->code[cp] = MACH_sJ(MACH_JMP, off);
cp = prev;
}
}
/* Update — assignment expressions must be compiled as statements */
if (update) {
int save = cs->freereg;
mach_compile_expr(cs, update, -1);
mach_free_reg_to(cs, save);
mach_compile_stmt(cs, update);
}
/* Jump back */
@@ -31655,6 +31692,48 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) {
int cr = MACH_GET_A(cs->code[jmpfalse_pc]);
cs->code[jmpfalse_pc] = MACH_AsBx(MACH_JMPFALSE, cr, (int16_t)offset);
}
/* Patch break chain */
int bp = cs->loop_break;
while (bp >= 0) {
int prev = MACH_GET_sJ(cs->code[bp]);
offset = mach_current_pc(cs) - (bp + 1);
cs->code[bp] = MACH_sJ(MACH_JMP, offset);
bp = prev;
}
cs->loop_break = old_break;
cs->loop_continue = old_continue;
return;
}
/* Break */
if (strcmp(kind, "break") == 0) {
int pc = mach_current_pc(cs);
mach_emit(cs, MACH_sJ(MACH_JMP, cs->loop_break));
cs->loop_break = pc;
return;
}
/* Continue */
if (strcmp(kind, "continue") == 0) {
int pc = mach_current_pc(cs);
mach_emit(cs, MACH_sJ(MACH_JMP, cs->loop_continue));
cs->loop_continue = pc;
return;
}
/* Assignment as statement */
if (strcmp(kind, "assign") == 0 ||
strcmp(kind, "+=") == 0 || strcmp(kind, "-=") == 0 ||
strcmp(kind, "*=") == 0 || strcmp(kind, "/=") == 0 ||
strcmp(kind, "%=") == 0 || strcmp(kind, "**=") == 0 ||
strcmp(kind, "&=") == 0 || strcmp(kind, "|=") == 0 ||
strcmp(kind, "^=") == 0 || strcmp(kind, "<<=") == 0 ||
strcmp(kind, ">>=") == 0 || strcmp(kind, ">>>=") == 0 ||
strcmp(kind, "++") == 0 || strcmp(kind, "--") == 0) {
int save = cs->freereg;
mach_compile_expr(cs, stmt, -1);
mach_free_reg_to(cs, save);
return;
}
@@ -32409,13 +32488,15 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
JSFunction *fn = JS_VALUE_GET_FUNCTION(func_val);
if (fn->kind == JS_FUNC_KIND_C) {
/* C function: copy args to C stack so GC can't invalidate argv */
JSValue c_argv[nargs > 0 ? nargs : 1];
/* C function: push args onto value stack (C-allocated, GC-scanned) */
int vs_base = ctx->value_stack_top;
for (int i = 0; i < nargs; i++)
c_argv[i] = frame->slots[base + 1 + i];
ctx->value_stack[vs_base + i] = frame->slots[base + 1 + i];
ctx->value_stack_top = vs_base + nargs;
ctx->reg_current_frame = frame_ref.val;
ctx->rt->current_register_pc = pc > 0 ? pc - 1 : 0;
JSValue ret = js_call_c_function(ctx, func_val, JS_NULL, nargs, c_argv);
JSValue ret = js_call_c_function(ctx, func_val, JS_NULL, nargs, &ctx->value_stack[vs_base]);
ctx->value_stack_top = vs_base;
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
ctx->reg_current_frame = JS_NULL;
if (JS_IsException(ret)) { goto disrupt; }
@@ -32448,11 +32529,13 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
env = fn->u.reg.env_record;
pc = code->entry_point;
} else {
/* Other function kinds (bytecode) — copy args to C stack */
JSValue bc_argv[nargs > 0 ? nargs : 1];
/* Other function kinds (bytecode) — push args onto value stack */
int vs_base = ctx->value_stack_top;
for (int i = 0; i < nargs; i++)
bc_argv[i] = frame->slots[base + 1 + i];
JSValue ret = js_call_c_function(ctx, func_val, JS_NULL, nargs, bc_argv);
ctx->value_stack[vs_base + i] = frame->slots[base + 1 + i];
ctx->value_stack_top = vs_base + nargs;
JSValue ret = js_call_c_function(ctx, func_val, JS_NULL, nargs, &ctx->value_stack[vs_base]);
ctx->value_stack_top = vs_base;
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
if (JS_IsException(ret)) { goto disrupt; }
if (nresults > 0) frame->slots[base] = ret;
@@ -32540,24 +32623,32 @@ static JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
continue;
disrupt:
/* Search frame chain for a disruption handler */
for (;;) {
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
code = fn->u.reg.code;
if (code->disruption_pc > 0) {
env = fn->u.reg.env_record;
pc = code->disruption_pc;
break;
/* Search frame chain for a disruption handler.
Use frame_pc to track each frame's execution point:
- For the faulting frame, it's the current pc.
- For unwound caller frames, read from frame->address. */
{
uint32_t frame_pc = pc;
for (;;) {
JSFunction *fn = JS_VALUE_GET_FUNCTION(frame->function);
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.reg.env_record;
pc = code->disruption_pc;
break;
}
if (JS_IsNull(frame->caller)) {
result = JS_NULL;
goto done;
}
/* Unwind one frame — read caller's saved pc from its address field */
JSFrameRegister *caller = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller);
frame->caller = JS_NULL;
frame = caller;
frame_ref.val = JS_MKPTR(frame);
frame_pc = (uint32_t)(JS_VALUE_GET_INT(frame->address) >> 16);
}
if (JS_IsNull(frame->caller)) {
result = JS_NULL;
goto done;
}
/* Unwind one frame */
JSFrameRegister *caller = (JSFrameRegister *)JS_VALUE_GET_PTR(frame->caller);
frame->caller = JS_NULL;
frame = caller;
frame_ref.val = JS_MKPTR(frame);
}
}