Merge branch 'optimize_mcode' into fix_aot
This commit is contained in:
159
source/mach.c
159
source/mach.c
@@ -89,7 +89,7 @@
|
||||
[P] IS_IDENTICAL, IS_INT, IS_NUM, IS_TEXT, IS_BOOL, IS_NULL
|
||||
[P] IS_ARRAY, IS_FUNC, IS_RECORD, IS_STONE, IS_PROXY
|
||||
[P] NOT, AND, OR, BITNOT, BITAND, BITOR, BITXOR
|
||||
[P] JMP, JMPTRUE, JMPFALSE, JMPNULL, JMPNOTNULL
|
||||
[P] JMP, JMPTRUE, JMPFALSE, JMPNULL, JMPNOTNULL, WARYTRUE, WARYFALSE, JMPEMPTY
|
||||
[P] RETURN, RETNIL, SETARG, GETUP, SETUP, DISRUPT, THROW
|
||||
[P] LENGTH (array + imm-ASCII fast path only; text/blob fallback is [G])
|
||||
[N] EQ_TEXT..GE_TEXT (js_string_compare_value — no allocation)
|
||||
@@ -282,6 +282,10 @@ typedef enum MachOpcode {
|
||||
MACH_IS_UPPER, /* R(A) = is_upper(R(B)) */
|
||||
MACH_IS_WS, /* R(A) = is_whitespace(R(B)) */
|
||||
MACH_IS_ACTOR, /* R(A) = is_actor(R(B)) — has actor_sym property */
|
||||
MACH_APPLY, /* R(A) = apply(R(B), R(C)) — call fn with args from array (ABC) */
|
||||
MACH_WARYTRUE, /* if toBool(R(A)): pc += sBx — coercing (iAsBx) */
|
||||
MACH_WARYFALSE, /* if !toBool(R(A)): pc += sBx — coercing (iAsBx) */
|
||||
MACH_JMPEMPTY, /* if R(A)==empty_text: pc += sBx (iAsBx) */
|
||||
|
||||
MACH_OP_COUNT
|
||||
} MachOpcode;
|
||||
@@ -406,6 +410,10 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = {
|
||||
[MACH_IS_UPPER] = "is_upper",
|
||||
[MACH_IS_WS] = "is_ws",
|
||||
[MACH_IS_ACTOR] = "is_actor",
|
||||
[MACH_APPLY] = "apply",
|
||||
[MACH_WARYTRUE] = "wary_true",
|
||||
[MACH_WARYFALSE] = "wary_false",
|
||||
[MACH_JMPEMPTY] = "jump_empty",
|
||||
};
|
||||
|
||||
/* ---- Compile-time constant pool entry ---- */
|
||||
@@ -1427,6 +1435,8 @@ vm_dispatch:
|
||||
DT(MACH_IS_DIGIT), DT(MACH_IS_LETTER),
|
||||
DT(MACH_IS_LOWER), DT(MACH_IS_UPPER),
|
||||
DT(MACH_IS_WS), DT(MACH_IS_ACTOR),
|
||||
DT(MACH_APPLY),
|
||||
DT(MACH_WARYTRUE), DT(MACH_WARYFALSE), DT(MACH_JMPEMPTY),
|
||||
};
|
||||
#pragma GCC diagnostic pop
|
||||
#undef DT
|
||||
@@ -2069,12 +2079,7 @@ vm_dispatch:
|
||||
}
|
||||
|
||||
VM_CASE(MACH_JMPTRUE): {
|
||||
JSValue v = frame->slots[a];
|
||||
int cond;
|
||||
if (v == JS_TRUE) cond = 1;
|
||||
else if (v == JS_FALSE || v == JS_NULL) cond = 0;
|
||||
else cond = JS_ToBool(ctx, v);
|
||||
if (cond) {
|
||||
if (frame->slots[a] == JS_TRUE) {
|
||||
int offset = MACH_GET_sBx(instr);
|
||||
pc = (uint32_t)((int32_t)pc + offset);
|
||||
if (offset < 0) {
|
||||
@@ -2095,12 +2100,7 @@ vm_dispatch:
|
||||
}
|
||||
|
||||
VM_CASE(MACH_JMPFALSE): {
|
||||
JSValue v = frame->slots[a];
|
||||
int cond;
|
||||
if (v == JS_TRUE) cond = 1;
|
||||
else if (v == JS_FALSE || v == JS_NULL) cond = 0;
|
||||
else cond = JS_ToBool(ctx, v);
|
||||
if (!cond) {
|
||||
if (frame->slots[a] == JS_FALSE) {
|
||||
int offset = MACH_GET_sBx(instr);
|
||||
pc = (uint32_t)((int32_t)pc + offset);
|
||||
if (offset < 0) {
|
||||
@@ -2517,6 +2517,49 @@ vm_dispatch:
|
||||
frame->slots[a] = JS_NewBool(ctx, result);
|
||||
VM_BREAK();
|
||||
}
|
||||
VM_CASE(MACH_APPLY): {
|
||||
/* A=dest, B=fn, C=arr_or_val */
|
||||
JSValue fn_val = frame->slots[b];
|
||||
JSValue arg_val = frame->slots[c];
|
||||
if (!mist_is_function(fn_val)) {
|
||||
frame->slots[a] = fn_val;
|
||||
VM_BREAK();
|
||||
}
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION(fn_val);
|
||||
JSValue ret;
|
||||
ctx->reg_current_frame = frame_ref.val;
|
||||
ctx->current_register_pc = pc > 0 ? pc - 1 : 0;
|
||||
ctx->vm_call_depth++;
|
||||
if (!mist_is_array(arg_val)) {
|
||||
/* Non-array: use as single argument */
|
||||
if (!mach_check_call_arity(ctx, fn, 1)) {
|
||||
ctx->vm_call_depth--;
|
||||
goto disrupt;
|
||||
}
|
||||
ret = JS_CallInternal(ctx, fn_val, JS_NULL, 1, &arg_val, 0);
|
||||
} else {
|
||||
JSArray *arr = JS_VALUE_GET_ARRAY(arg_val);
|
||||
int len = arr->len;
|
||||
if (!mach_check_call_arity(ctx, fn, len)) {
|
||||
ctx->vm_call_depth--;
|
||||
goto disrupt;
|
||||
}
|
||||
if (len == 0) {
|
||||
ret = JS_CallInternal(ctx, fn_val, JS_NULL, 0, NULL, 0);
|
||||
} else {
|
||||
JSValue *args = alloca(sizeof(JSValue) * len);
|
||||
for (int i = 0; i < len; i++)
|
||||
args[i] = arr->values[i];
|
||||
ret = JS_CallInternal(ctx, fn_val, JS_NULL, len, args, 0);
|
||||
}
|
||||
}
|
||||
ctx->vm_call_depth--;
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(frame_ref.val);
|
||||
ctx->reg_current_frame = JS_NULL;
|
||||
if (JS_IsException(ret)) goto disrupt;
|
||||
frame->slots[a] = ret;
|
||||
VM_BREAK();
|
||||
}
|
||||
/* Logical */
|
||||
VM_CASE(MACH_NOT): {
|
||||
int bval = JS_ToBool(ctx, frame->slots[b]);
|
||||
@@ -2826,6 +2869,67 @@ vm_dispatch:
|
||||
VM_BREAK();
|
||||
}
|
||||
|
||||
/* Wary jumps — coerce via JS_ToBool (old JMPTRUE/JMPFALSE behavior) */
|
||||
VM_CASE(MACH_WARYTRUE): {
|
||||
JSValue v = frame->slots[a];
|
||||
int cond;
|
||||
if (v == JS_TRUE) cond = 1;
|
||||
else if (v == JS_FALSE || v == JS_NULL) cond = 0;
|
||||
else cond = JS_ToBool(ctx, v);
|
||||
if (cond) {
|
||||
int offset = MACH_GET_sBx(instr);
|
||||
pc = (uint32_t)((int32_t)pc + offset);
|
||||
if (offset < 0) {
|
||||
int pf = atomic_load_explicit(&ctx->pause_flag, memory_order_relaxed);
|
||||
if (pf == 2) {
|
||||
result = JS_RaiseDisrupt(ctx, "interrupted");
|
||||
goto done;
|
||||
}
|
||||
if (pf == 1) {
|
||||
if (ctx->vm_call_depth > 0)
|
||||
atomic_store_explicit(&ctx->pause_flag, 0, memory_order_relaxed);
|
||||
else
|
||||
goto suspend;
|
||||
}
|
||||
}
|
||||
}
|
||||
VM_BREAK();
|
||||
}
|
||||
|
||||
VM_CASE(MACH_WARYFALSE): {
|
||||
JSValue v = frame->slots[a];
|
||||
int cond;
|
||||
if (v == JS_TRUE) cond = 1;
|
||||
else if (v == JS_FALSE || v == JS_NULL) cond = 0;
|
||||
else cond = JS_ToBool(ctx, v);
|
||||
if (!cond) {
|
||||
int offset = MACH_GET_sBx(instr);
|
||||
pc = (uint32_t)((int32_t)pc + offset);
|
||||
if (offset < 0) {
|
||||
int pf = atomic_load_explicit(&ctx->pause_flag, memory_order_relaxed);
|
||||
if (pf == 2) {
|
||||
result = JS_RaiseDisrupt(ctx, "interrupted");
|
||||
goto done;
|
||||
}
|
||||
if (pf == 1) {
|
||||
if (ctx->vm_call_depth > 0)
|
||||
atomic_store_explicit(&ctx->pause_flag, 0, memory_order_relaxed);
|
||||
else
|
||||
goto suspend;
|
||||
}
|
||||
}
|
||||
}
|
||||
VM_BREAK();
|
||||
}
|
||||
|
||||
VM_CASE(MACH_JMPEMPTY): {
|
||||
if (frame->slots[a] == JS_EMPTY_TEXT) {
|
||||
int offset = MACH_GET_sBx(instr);
|
||||
pc = (uint32_t)((int32_t)pc + offset);
|
||||
}
|
||||
VM_BREAK();
|
||||
}
|
||||
|
||||
/* Disrupt (mcode alias) */
|
||||
VM_CASE(MACH_DISRUPT):
|
||||
goto disrupt;
|
||||
@@ -3174,6 +3278,7 @@ static MachCode *mcode_lower_func(cJSON *fobj, const char *filename) {
|
||||
else if (strcmp(op, "is_upper") == 0) { AB2(MACH_IS_UPPER); }
|
||||
else if (strcmp(op, "is_ws") == 0) { AB2(MACH_IS_WS); }
|
||||
else if (strcmp(op, "is_actor") == 0) { AB2(MACH_IS_ACTOR); }
|
||||
else if (strcmp(op, "apply") == 0) { ABC3(MACH_APPLY); }
|
||||
/* Logical */
|
||||
else if (strcmp(op, "not") == 0) { AB2(MACH_NOT); }
|
||||
else if (strcmp(op, "and") == 0) { ABC3(MACH_AND); }
|
||||
@@ -3324,6 +3429,34 @@ static MachCode *mcode_lower_func(cJSON *fobj, const char *filename) {
|
||||
EM(MACH_AsBx(MACH_JMPNOTNULL, reg, 0));
|
||||
ml_patch(&s, pc_now, lbl, 0, reg);
|
||||
}
|
||||
else if (strcmp(op, "jump_null") == 0) {
|
||||
int reg = A1;
|
||||
const char *lbl = cJSON_GetArrayItem(it, 2)->valuestring;
|
||||
int pc_now = s.code_count;
|
||||
EM(MACH_AsBx(MACH_JMPNULL, reg, 0));
|
||||
ml_patch(&s, pc_now, lbl, 0, reg);
|
||||
}
|
||||
else if (strcmp(op, "wary_true") == 0) {
|
||||
int reg = A1;
|
||||
const char *lbl = cJSON_GetArrayItem(it, 2)->valuestring;
|
||||
int pc_now = s.code_count;
|
||||
EM(MACH_AsBx(MACH_WARYTRUE, reg, 0));
|
||||
ml_patch(&s, pc_now, lbl, 0, reg);
|
||||
}
|
||||
else if (strcmp(op, "wary_false") == 0) {
|
||||
int reg = A1;
|
||||
const char *lbl = cJSON_GetArrayItem(it, 2)->valuestring;
|
||||
int pc_now = s.code_count;
|
||||
EM(MACH_AsBx(MACH_WARYFALSE, reg, 0));
|
||||
ml_patch(&s, pc_now, lbl, 0, reg);
|
||||
}
|
||||
else if (strcmp(op, "jump_empty") == 0) {
|
||||
int reg = A1;
|
||||
const char *lbl = cJSON_GetArrayItem(it, 2)->valuestring;
|
||||
int pc_now = s.code_count;
|
||||
EM(MACH_AsBx(MACH_JMPEMPTY, reg, 0));
|
||||
ml_patch(&s, pc_now, lbl, 0, reg);
|
||||
}
|
||||
/* Return / error */
|
||||
else if (strcmp(op, "return") == 0) {
|
||||
EM(MACH_ABC(MACH_RETURN, A1, 0, 0));
|
||||
|
||||
@@ -9446,15 +9446,23 @@ static JSValue js_cell_fn_apply (JSContext *ctx, JSValue this_val, int argc, JSV
|
||||
if (argc < 1) return JS_NULL;
|
||||
if (!JS_IsFunction (argv[0])) return argv[0];
|
||||
|
||||
JSFunction *fn = JS_VALUE_GET_FUNCTION (argv[0]);
|
||||
|
||||
if (argc < 2)
|
||||
return JS_CallInternal (ctx, argv[0], JS_NULL, 0, NULL, 0);
|
||||
|
||||
if (!JS_IsArray (argv[1]))
|
||||
if (!JS_IsArray (argv[1])) {
|
||||
if (fn->length >= 0 && 1 > fn->length)
|
||||
return JS_RaiseDisrupt (ctx, "too many arguments for apply: expected %d, got 1", fn->length);
|
||||
return JS_CallInternal (ctx, argv[0], JS_NULL, 1, &argv[1], 0);
|
||||
}
|
||||
|
||||
JSArray *arr = JS_VALUE_GET_ARRAY (argv[1]);
|
||||
int len = arr->len;
|
||||
|
||||
if (fn->length >= 0 && len > fn->length)
|
||||
return JS_RaiseDisrupt (ctx, "too many arguments for apply: expected %d, got %d", fn->length, len);
|
||||
|
||||
if (len == 0)
|
||||
return JS_CallInternal (ctx, argv[0], JS_NULL, 0, NULL, 0);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user