wary jumps

This commit is contained in:
2026-02-21 20:58:24 -06:00
parent d27047dd82
commit 7372b80e07
2 changed files with 122 additions and 4 deletions

View File

@@ -633,6 +633,15 @@ ${sr("gc", "%idx_slot")}
${sr("a", "%fn_slot")}
%r =l call $cell_rt_frame(l %ctx, l %a, l %nargs)
${alloc_tail("%r")}
}`
// apply(ctx, fp, dest, fn_slot, arg_slot)
h[] = `export function l $__apply_ss(l %ctx, l %fp, l %dest, l %fn_slot, l %arg_slot) ${lb}
@entry
${sr("a", "%fn_slot")}
${sr("b", "%arg_slot")}
%r =l call $cell_rt_apply(l %ctx, l %a, l %b)
${alloc_tail("%r")}
}`
// goframe(ctx, fp, dest, fn_slot, nargs)
@@ -1023,6 +1032,18 @@ var qbe_emit = function(ir, qbe, export_name) {
var jnn_lbl = null
var jnn_idx = null
var jnn_backedge = false
var wt_lbl = null
var wt_idx = null
var wt_backedge = false
var wf_lbl = null
var wf_idx = null
var wf_backedge = false
var jn_lbl = null
var jn_idx = null
var jn_backedge = false
var je_lbl = null
var je_idx = null
var je_backedge = false
var truthy = null
var lhs_d = null
var rhs_d = null
@@ -2625,8 +2646,8 @@ var qbe_emit = function(ir, qbe, export_name) {
jt_lbl = sanitize(a2)
jt_idx = label_pos[jt_lbl]
jt_backedge = jt_idx != null && jt_idx < instr_idx
truthy = emit_truthy_w(v)
emit(` jnz ${truthy}, @${p}_take, @${p}_f`)
emit(` %${p}_take =w ceql ${v}, ${text(qbe.js_true)}`)
emit(` jnz %${p}_take, @${p}_take, @${p}_f`)
emit(`@${p}_take`)
if (jt_backedge) {
emit_backedge_branch(jt_lbl)
@@ -2642,8 +2663,8 @@ var qbe_emit = function(ir, qbe, export_name) {
jf_lbl = sanitize(a2)
jf_idx = label_pos[jf_lbl]
jf_backedge = jf_idx != null && jf_idx < instr_idx
truthy = emit_truthy_w(v)
emit(` jnz ${truthy}, @${p}_t, @${p}_take`)
emit(` %${p}_take =w ceql ${v}, ${text(qbe.js_false)}`)
emit(` jnz %${p}_take, @${p}_take, @${p}_t`)
emit(`@${p}_take`)
if (jf_backedge) {
emit_backedge_branch(jf_lbl)
@@ -2653,6 +2674,74 @@ var qbe_emit = function(ir, qbe, export_name) {
emit(`@${p}_t`)
continue
}
if (op == "wary_true") {
v = s_read(a1)
p = fresh()
wt_lbl = sanitize(a2)
wt_idx = label_pos[wt_lbl]
wt_backedge = wt_idx != null && wt_idx < instr_idx
truthy = emit_truthy_w(v)
emit(` jnz ${truthy}, @${p}_take, @${p}_f`)
emit(`@${p}_take`)
if (wt_backedge) {
emit_backedge_branch(wt_lbl)
} else {
emit(` jmp @${wt_lbl}`)
}
emit(`@${p}_f`)
continue
}
if (op == "wary_false") {
v = s_read(a1)
p = fresh()
wf_lbl = sanitize(a2)
wf_idx = label_pos[wf_lbl]
wf_backedge = wf_idx != null && wf_idx < instr_idx
truthy = emit_truthy_w(v)
emit(` jnz ${truthy}, @${p}_t, @${p}_take`)
emit(`@${p}_take`)
if (wf_backedge) {
emit_backedge_branch(wf_lbl)
} else {
emit(` jmp @${wf_lbl}`)
}
emit(`@${p}_t`)
continue
}
if (op == "jump_null") {
v = s_read(a1)
p = fresh()
jn_lbl = sanitize(a2)
jn_idx = label_pos[jn_lbl]
jn_backedge = jn_idx != null && jn_idx < instr_idx
emit(` %${p} =w ceql ${v}, ${text(qbe.js_null)}`)
if (jn_backedge) {
emit(` jnz %${p}, @${p}_bn, @${p}_n`)
emit(`@${p}_bn`)
emit_backedge_branch(jn_lbl)
} else {
emit(` jnz %${p}, @${jn_lbl}, @${p}_n`)
}
emit(`@${p}_n`)
continue
}
if (op == "jump_empty") {
v = s_read(a1)
p = fresh()
je_lbl = sanitize(a2)
je_idx = label_pos[je_lbl]
je_backedge = je_idx != null && je_idx < instr_idx
emit(` %${p} =w ceql ${v}, ${text(qbe.js_empty_text)}`)
if (je_backedge) {
emit(` jnz %${p}, @${p}_bn, @${p}_n`)
emit(`@${p}_bn`)
emit_backedge_branch(je_lbl)
} else {
emit(` jnz %${p}, @${je_lbl}, @${p}_n`)
}
emit(`@${p}_n`)
continue
}
if (op == "jump_not_null") {
v = s_read(a1)
p = fresh()
@@ -2678,6 +2767,11 @@ var qbe_emit = function(ir, qbe, export_name) {
emit_exc_check()
continue
}
if (op == "apply") {
emit(` %fp =l call $__apply_ss(l %ctx, l %fp, l ${text(a1)}, l ${text(a2)}, l ${text(a3)})`)
emit_exc_check()
continue
}
if (op == "setarg") {
v = s_read(a1)
lhs = s_read(a3)

View File

@@ -639,6 +639,30 @@ static int cell_check_call_arity(JSContext *ctx, JSFunction *fn, int argc) {
return 1;
}
JSValue cell_rt_apply(JSContext *ctx, JSValue fn_val, JSValue arg_val) {
if (!mist_is_function(fn_val))
return fn_val;
JSFunction *fn = JS_VALUE_GET_FUNCTION(fn_val);
if (!mist_is_array(arg_val)) {
if (!cell_check_call_arity(ctx, fn, 1))
return JS_EXCEPTION;
return JS_CallInternal(ctx, fn_val, JS_NULL, 1, &arg_val, 0);
}
JSArray *arr = JS_VALUE_GET_ARRAY(arg_val);
int len = arr->len;
if (!cell_check_call_arity(ctx, fn, len))
return JS_EXCEPTION;
if (len == 0)
return JS_CallInternal(ctx, fn_val, JS_NULL, 0, NULL, 0);
JSValue args[len];
for (int i = 0; i < len; i++)
args[i] = arr->values[i];
return JS_CallInternal(ctx, fn_val, JS_NULL, len, args, 0);
}
static inline void cell_copy_args_0_4(JSValue *fp, JSValue *argv, int copy) {
/* fp[0] is `this`; copy args into fp[1..4] */
switch (copy) {