diff --git a/qbe_emit.cm b/qbe_emit.cm index 8aade4c9..e312e7d1 100644 --- a/qbe_emit.cm +++ b/qbe_emit.cm @@ -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) diff --git a/source/qbe_helpers.c b/source/qbe_helpers.c index a684b8a1..43ad4eb5 100644 --- a/source/qbe_helpers.c +++ b/source/qbe_helpers.c @@ -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) {