Merge branch 'better_fn_error'
This commit is contained in:
@@ -494,6 +494,37 @@ static int mach_check_call_arity(JSContext *ctx, JSFunction *fn, int argc) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Scan backwards from pc to find what loaded the callee register.
|
||||
Returns the name in buf, or NULL if unknown. */
|
||||
static const char *mach_callee_name(JSContext *ctx, JSCodeRegister *code,
|
||||
uint32_t pc, int reg,
|
||||
char *buf, size_t buf_size) {
|
||||
int hops = 4; /* limit move-chain depth */
|
||||
for (int i = (int)pc - 2; i >= 0 && hops > 0; i--) {
|
||||
MachInstr32 prev = code->instructions[i];
|
||||
int prev_op = MACH_GET_OP(prev);
|
||||
int prev_a = MACH_GET_A(prev);
|
||||
if (prev_a != reg) continue;
|
||||
if (prev_op == MACH_GETENV || prev_op == MACH_GETINTRINSIC) {
|
||||
int bx = MACH_GET_Bx(prev);
|
||||
if ((uint32_t)bx < code->cpool_count && JS_IsText(code->cpool[bx]))
|
||||
return JS_KeyGetStr(ctx, buf, buf_size, code->cpool[bx]);
|
||||
}
|
||||
if (prev_op == MACH_LOAD_FIELD) {
|
||||
int ci = MACH_GET_C(prev);
|
||||
if ((uint32_t)ci < code->cpool_count && JS_IsText(code->cpool[ci]))
|
||||
return JS_KeyGetStr(ctx, buf, buf_size, code->cpool[ci]);
|
||||
}
|
||||
if (prev_op == MACH_MOVE) {
|
||||
reg = MACH_GET_B(prev);
|
||||
hops--;
|
||||
continue;
|
||||
}
|
||||
break; /* some other op wrote to this reg — give up */
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ---- Link pass: resolve GETNAME to GETINTRINSIC or GETENV ---- */
|
||||
|
||||
static void mach_link_code(JSContext *ctx, JSCodeRegister *code, JSValue env) {
|
||||
@@ -2560,7 +2591,12 @@ vm_dispatch:
|
||||
/* A=frame_slot, B=func_reg, C=argc */
|
||||
JSValue func_val = frame->slots[b];
|
||||
if (!mist_is_function(func_val)) {
|
||||
JS_RaiseDisrupt(ctx, "not a function");
|
||||
char nbuf[KEY_GET_STR_BUF_SIZE];
|
||||
const char *name = mach_callee_name(ctx, code, pc, b, nbuf, sizeof(nbuf));
|
||||
if (name)
|
||||
JS_RaiseDisrupt(ctx, "%s is not a function", name);
|
||||
else
|
||||
JS_RaiseDisrupt(ctx, "not a function");
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
goto disrupt;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user