Compare commits
2 Commits
mach_suite
...
bytecode_c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6de542f0d0 | ||
|
|
6ba4727119 |
173
source/mach.c
173
source/mach.c
@@ -1142,174 +1142,6 @@ JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case MACH_CALL: {
|
|
||||||
/* Lua-style call: R(A)=func, B=nargs in R(A+1)..R(A+B), C=nresults */
|
|
||||||
int base = a;
|
|
||||||
int nargs = b;
|
|
||||||
int nresults = c;
|
|
||||||
JSValue func_val = frame->slots[base];
|
|
||||||
|
|
||||||
if (!JS_IsFunction(func_val)) {
|
|
||||||
JS_ThrowTypeError(ctx, "not a function");
|
|
||||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
|
||||||
goto disrupt;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(func_val);
|
|
||||||
if (fn->kind == JS_FUNC_KIND_C) {
|
|
||||||
/* C function: copy args to C stack */
|
|
||||||
JSValue args[nargs > 0 ? nargs : 1];
|
|
||||||
for (int i = 0; i < nargs; i++)
|
|
||||||
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, args);
|
|
||||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
|
||||||
ctx->reg_current_frame = JS_NULL;
|
|
||||||
if (JS_IsException(ret)) { goto disrupt; }
|
|
||||||
if (nresults > 0) frame->slots[base] = ret;
|
|
||||||
} else if (fn->kind == JS_FUNC_KIND_REGISTER) {
|
|
||||||
/* Register function: allocate frame, copy args, switch */
|
|
||||||
JSCodeRegister *fn_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);
|
|
||||||
goto disrupt;
|
|
||||||
}
|
|
||||||
/* Re-read pointers — GC may have moved them */
|
|
||||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
|
||||||
func_val = frame->slots[base];
|
|
||||||
fn = JS_VALUE_GET_FUNCTION(func_val);
|
|
||||||
new_frame->function = func_val;
|
|
||||||
new_frame->slots[0] = JS_NULL; /* this */
|
|
||||||
for (int i = 0; i < nargs && i < fn_code->arity; i++)
|
|
||||||
new_frame->slots[1 + i] = frame->slots[base + 1 + i];
|
|
||||||
|
|
||||||
/* Save return info: pc in upper 16 bits, base reg or 0xFFFF (discard) in lower */
|
|
||||||
int ret_slot = (nresults > 0) ? base : 0xFFFF;
|
|
||||||
frame->address = JS_NewInt32(ctx, (pc << 16) | ret_slot);
|
|
||||||
new_frame->caller = JS_MKPTR(frame);
|
|
||||||
|
|
||||||
frame = new_frame;
|
|
||||||
frame_ref.val = JS_MKPTR(frame);
|
|
||||||
code = fn_code;
|
|
||||||
env = fn->u.reg.env_record;
|
|
||||||
pc = code->entry_point;
|
|
||||||
} else {
|
|
||||||
/* Other function kinds (bytecode) — copy args to C stack */
|
|
||||||
JSValue args[nargs > 0 ? nargs : 1];
|
|
||||||
for (int i = 0; i < nargs; i++)
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case MACH_CALLMETHOD: {
|
|
||||||
/* Method call: R(A)=obj, B=nargs in R(A+2)..R(A+1+B), C=cpool key index
|
|
||||||
Result stored in R(A). C=0xFF means key is in R(A+1).
|
|
||||||
If obj is a function (proxy): call obj(key_str, [args...])
|
|
||||||
Else (record): get property, call property(obj_as_this, args...) */
|
|
||||||
int base = a;
|
|
||||||
int nargs = b;
|
|
||||||
JSGCRef key_ref;
|
|
||||||
JS_PushGCRef(ctx, &key_ref);
|
|
||||||
key_ref.val = (c == 0xFF) ? frame->slots[base + 1] : code->cpool[c];
|
|
||||||
|
|
||||||
if (JS_IsFunction(frame->slots[base]) && JS_IsText(key_ref.val) &&
|
|
||||||
JS_VALUE_GET_FUNCTION(frame->slots[base])->length == 2) {
|
|
||||||
/* Proxy call (arity-2 functions only): obj(name, [args...]) */
|
|
||||||
JSValue arr = JS_NewArray(ctx);
|
|
||||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
|
||||||
if (JS_IsException(arr)) { JS_PopGCRef(ctx, &key_ref); goto disrupt; }
|
|
||||||
frame->slots[base + 1] = arr; /* protect from GC in temp slot */
|
|
||||||
for (int i = 0; i < nargs; i++) {
|
|
||||||
JS_SetPropertyNumber(ctx, frame->slots[base + 1], i, frame->slots[base + 2 + i]);
|
|
||||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
|
||||||
}
|
|
||||||
/* 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, 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; }
|
|
||||||
frame->slots[base] = ret;
|
|
||||||
} else if (JS_IsFunction(frame->slots[base])) {
|
|
||||||
/* Non-proxy function with non-text key: disrupt */
|
|
||||||
JS_ThrowTypeError(ctx, "cannot use bracket notation on non-proxy function");
|
|
||||||
JS_PopGCRef(ctx, &key_ref);
|
|
||||||
goto disrupt;
|
|
||||||
} else {
|
|
||||||
/* Record method call: get property, call with this=obj */
|
|
||||||
if (JS_IsNull(frame->slots[base])) {
|
|
||||||
JS_ThrowTypeError(ctx, "cannot read properties of null");
|
|
||||||
JS_PopGCRef(ctx, &key_ref);
|
|
||||||
goto disrupt;
|
|
||||||
}
|
|
||||||
JSValue method = JS_GetProperty(ctx, frame->slots[base], key_ref.val);
|
|
||||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
|
||||||
if (JS_IsException(method)) { JS_PopGCRef(ctx, &key_ref); goto disrupt; }
|
|
||||||
if (!JS_IsFunction(method)) {
|
|
||||||
JS_ThrowTypeError(ctx, "not a function");
|
|
||||||
JS_PopGCRef(ctx, &key_ref);
|
|
||||||
goto disrupt;
|
|
||||||
}
|
|
||||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(method);
|
|
||||||
if (fn->kind == JS_FUNC_KIND_C) {
|
|
||||||
JSValue args[nargs > 0 ? nargs : 1];
|
|
||||||
for (int i = 0; i < nargs; i++)
|
|
||||||
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, 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; }
|
|
||||||
frame->slots[base] = ret;
|
|
||||||
} else if (fn->kind == JS_FUNC_KIND_REGISTER) {
|
|
||||||
JSCodeRegister *fn_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);
|
|
||||||
JS_PopGCRef(ctx, &key_ref);
|
|
||||||
goto disrupt;
|
|
||||||
}
|
|
||||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
|
||||||
method = JS_GetProperty(ctx, frame->slots[base], key_ref.val);
|
|
||||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
|
||||||
fn = JS_VALUE_GET_FUNCTION(method);
|
|
||||||
new_frame->function = method;
|
|
||||||
new_frame->slots[0] = frame->slots[base]; /* this */
|
|
||||||
for (int i = 0; i < nargs && i < fn_code->arity; i++)
|
|
||||||
new_frame->slots[1 + i] = frame->slots[base + 2 + i];
|
|
||||||
int ret_slot = base;
|
|
||||||
frame->address = JS_NewInt32(ctx, (pc << 16) | ret_slot);
|
|
||||||
new_frame->caller = JS_MKPTR(frame);
|
|
||||||
frame = new_frame;
|
|
||||||
frame_ref.val = JS_MKPTR(frame);
|
|
||||||
code = fn_code;
|
|
||||||
env = fn->u.reg.env_record;
|
|
||||||
pc = code->entry_point;
|
|
||||||
} else {
|
|
||||||
/* Bytecode or other function */
|
|
||||||
JSValue args[nargs > 0 ? nargs : 1];
|
|
||||||
for (int i = 0; i < nargs; i++)
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
JS_PopGCRef(ctx, &key_ref);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case MACH_RETURN:
|
case MACH_RETURN:
|
||||||
result = frame->slots[a];
|
result = frame->slots[a];
|
||||||
if (JS_IsNull(frame->caller)) goto done;
|
if (JS_IsNull(frame->caller)) goto done;
|
||||||
@@ -3248,11 +3080,6 @@ static void dump_register_code(JSContext *ctx, JSCodeRegister *code, int indent)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call */
|
|
||||||
case MACH_CALL:
|
|
||||||
printf("r%d, %d, %d", a, b, c);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Return / throw */
|
/* Return / throw */
|
||||||
case MACH_RETURN:
|
case MACH_RETURN:
|
||||||
case MACH_THROW:
|
case MACH_THROW:
|
||||||
|
|||||||
@@ -469,7 +469,6 @@ typedef enum MachOpcode {
|
|||||||
MACH_JMPNULL, /* if R(A)==null: pc += sBx */
|
MACH_JMPNULL, /* if R(A)==null: pc += sBx */
|
||||||
|
|
||||||
/* Function calls — Lua-style consecutive registers (legacy .mach) */
|
/* Function calls — Lua-style consecutive registers (legacy .mach) */
|
||||||
MACH_CALL, /* Call R(A) with B args R(A+1)..R(A+B), C=0 discard, C=1 keep result in R(A) */
|
|
||||||
MACH_RETURN, /* Return R(A) */
|
MACH_RETURN, /* Return R(A) */
|
||||||
MACH_RETNIL, /* Return null */
|
MACH_RETNIL, /* Return null */
|
||||||
|
|
||||||
@@ -488,8 +487,6 @@ typedef enum MachOpcode {
|
|||||||
MACH_HASPROP, /* R(A) = R(C) in R(B) — has property check */
|
MACH_HASPROP, /* R(A) = R(C) in R(B) — has property check */
|
||||||
MACH_REGEXP, /* R(A) = regexp(K(B), K(C)) — regex literal */
|
MACH_REGEXP, /* R(A) = regexp(K(B), K(C)) — regex literal */
|
||||||
|
|
||||||
MACH_CALLMETHOD, /* Method call: R(A)=obj, B=nargs in R(A+2)..R(A+1+B), C=cpool key */
|
|
||||||
|
|
||||||
MACH_EQ_TOL, /* R(A) = eq_tol(R(B), R(B+1), R(B+2)), C=3 */
|
MACH_EQ_TOL, /* R(A) = eq_tol(R(B), R(B+1), R(B+2)), C=3 */
|
||||||
MACH_NEQ_TOL, /* R(A) = ne_tol(R(B), R(B+1), R(B+2)), C=3 */
|
MACH_NEQ_TOL, /* R(A) = ne_tol(R(B), R(B+1), R(B+2)), C=3 */
|
||||||
|
|
||||||
@@ -645,7 +642,6 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = {
|
|||||||
[MACH_JMPTRUE] = "jmptrue",
|
[MACH_JMPTRUE] = "jmptrue",
|
||||||
[MACH_JMPFALSE] = "jmpfalse",
|
[MACH_JMPFALSE] = "jmpfalse",
|
||||||
[MACH_JMPNULL] = "jmpnull",
|
[MACH_JMPNULL] = "jmpnull",
|
||||||
[MACH_CALL] = "call",
|
|
||||||
[MACH_RETURN] = "return",
|
[MACH_RETURN] = "return",
|
||||||
[MACH_RETNIL] = "retnil",
|
[MACH_RETNIL] = "retnil",
|
||||||
[MACH_NEWOBJECT] = "newobject",
|
[MACH_NEWOBJECT] = "newobject",
|
||||||
@@ -658,7 +654,6 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = {
|
|||||||
[MACH_DELETEINDEX] = "deleteindex",
|
[MACH_DELETEINDEX] = "deleteindex",
|
||||||
[MACH_HASPROP] = "hasprop",
|
[MACH_HASPROP] = "hasprop",
|
||||||
[MACH_REGEXP] = "regexp",
|
[MACH_REGEXP] = "regexp",
|
||||||
[MACH_CALLMETHOD] = "callmethod",
|
|
||||||
[MACH_EQ_TOL] = "eq_tol",
|
[MACH_EQ_TOL] = "eq_tol",
|
||||||
[MACH_NEQ_TOL] = "neq_tol",
|
[MACH_NEQ_TOL] = "neq_tol",
|
||||||
[MACH_NOP] = "nop",
|
[MACH_NOP] = "nop",
|
||||||
|
|||||||
Reference in New Issue
Block a user