asserts only for frame gets

This commit is contained in:
2026-02-21 19:06:41 -06:00
parent bbeb757e40
commit 99fa86a09c
3 changed files with 490 additions and 284 deletions

View File

@@ -41,49 +41,6 @@ ${sw("w", "%fp2", "%dest", result_var)}
// Category A: Pure QBE helpers (no C calls)
// ============================================================
// ============================================================
// Category B: Non-allocating C call helpers
// ============================================================
// Type checks via C (no ctx needed except is_proxy)
var tc_ops = [
["is_stone", "JS_IsStone", false],
["is_proxy", "cell_rt_is_proxy", true]
]
var i = 0
var tc_name = null
var tc_cfn = null
var tc_ctx = null
while (i < length(tc_ops)) {
tc_name = tc_ops[i][0]
tc_cfn = tc_ops[i][1]
tc_ctx = tc_ops[i][2]
if (tc_ctx) {
h[] = `export function $__${tc_name}_ss(l %ctx, l %fp, l %dest, l %src) ${lb}
@entry
${sr("a", "%src")}
%cr =w call $${tc_cfn}(l %ctx, l %a)
%crext =l extuw %cr
%sh =l shl %crext, 5
%r =l or %sh, 3
${sw("w", "%fp", "%dest", "%r")}
ret
}`
} else {
h[] = `export function $__${tc_name}_ss(l %fp, l %dest, l %src) ${lb}
@entry
${sr("a", "%src")}
%cr =w call $${tc_cfn}(l %a)
%crext =l extuw %cr
%sh =l shl %crext, 5
%r =l or %sh, 3
${sw("w", "%fp", "%dest", "%r")}
ret
}`
}
i = i + 1
}
// is_record: pointer + header type check (OBJ_RECORD=3), chase forwards
h[] = `export function $__is_record_ss(l %fp, l %dest, l %src) ${lb}
@entry
@@ -179,7 +136,7 @@ ${sw("w", "%fp", "%dest", "%r")}
// eq_tol, ne_tol (return tagged JSValue directly) — needs tolerance (3rd value)
var tol_ops = ["eq_tol", "ne_tol"]
i = 0
var i = 0
while (i < length(tol_ops)) {
h[] = `export function $__${tol_ops[i]}_ss(l %ctx, l %fp, l %dest, l %s1, l %s2, l %s3) ${lb}
@entry
@@ -266,25 +223,6 @@ ${sw("w", "%fp", "%dest", "%r")}
ret
}`
// and, or (return tagged JSValue directly)
h[] = `export function $__and_ss(l %ctx, l %fp, l %dest, l %s1, l %s2) ${lb}
@entry
${sr("a", "%s1")}
${sr("b", "%s2")}
%r =l call $cell_rt_and(l %ctx, l %a, l %b)
${sw("w", "%fp", "%dest", "%r")}
ret
}`
h[] = `export function $__or_ss(l %ctx, l %fp, l %dest, l %s1, l %s2) ${lb}
@entry
${sr("a", "%s1")}
${sr("b", "%s2")}
%r =l call $cell_rt_or(l %ctx, l %a, l %b)
${sw("w", "%fp", "%dest", "%r")}
ret
}`
// Bitwise unary/binary ops: mirror MACH mcode op behavior via JS_ToInt32 coercion.
h[] = `export function $__bnot_ss(l %ctx, l %fp, l %dest, l %src) ${lb}
@entry
@@ -325,7 +263,7 @@ ${sw("w", "%fp", "%dest", "%r")}
// Category C: Allocating helpers (return fp or 0)
// ============================================================
// concat allocates; keep refresh path
// concat allocates; runtime helper mirrors MACH self-assign fast path
h[] = `export function l $__concat_ss(l %ctx, l %fp, l %dest, l %s1, l %s2) ${lb}
@entry
${sr("a", "%s1")}
@@ -1098,6 +1036,8 @@ var qbe_emit = function(ir, qbe, export_name) {
var text_arg_slot = 0
var text_dest_slot = 0
var cmp_id = 0
var depth = 0
var d = 0
// Pre-scan: count invoke/tail_invoke points to assign segment numbers.
// Must skip dead code (instructions after terminators) the same way
@@ -1234,14 +1174,7 @@ var qbe_emit = function(ir, qbe, export_name) {
// Poll pause/interrupt state on taken backward jumps.
var emit_backedge_branch = function(target_label) {
var chk_lbl = fresh()
emit(` %${chk_lbl} =w call $cell_rt_check_backedge(l %ctx)`)
if (has_handler && !in_handler) {
emit(` jnz %${chk_lbl}, @disruption_handler, @${target_label}`)
} else {
needs_exc_ret = true
emit(` jnz %${chk_lbl}, @_exc_ret, @${target_label}`)
}
emit(` jmp @${target_label}`)
}
// Inline JS_ToBool equivalent for hot branch paths.
@@ -1894,7 +1827,24 @@ var qbe_emit = function(ir, qbe, export_name) {
}
if (op == "stone_text") {
v = s_read(a1)
emit(` call $cell_rt_stone_text(l ${v})`)
p = fresh()
emit(` %${p}_ptag =l and ${v}, 7`)
emit(` %${p}_is_ptr =w ceql %${p}_ptag, 1`)
emit(` jnz %${p}_is_ptr, @${p}_ptr, @${p}_done`)
emit(`@${p}_ptr`)
emit(` %${p}_ptr =l and ${v}, -8`)
emit(` %${p}_hdr =l loadl %${p}_ptr`)
emit(` %${p}_ht =l and %${p}_hdr, 7`)
emit(` %${p}_is_text =w ceql %${p}_ht, 2`)
emit(` jnz %${p}_is_text, @${p}_stone_chk, @${p}_done`)
emit(`@${p}_stone_chk`)
emit(` %${p}_s =l and %${p}_hdr, 8`)
emit(` %${p}_is_stone =w cnel %${p}_s, 0`)
emit(` jnz %${p}_is_stone, @${p}_done, @${p}_set`)
emit(`@${p}_set`)
emit(` %${p}_new_hdr =l or %${p}_hdr, 8`)
emit(` storel %${p}_new_hdr, %${p}_ptr`)
emit(`@${p}_done`)
continue
}
@@ -1955,19 +1905,279 @@ var qbe_emit = function(ir, qbe, export_name) {
continue
}
if (op == "is_stone") {
emit(` call $__is_stone_ss(l %fp, l ${text(a1)}, l ${text(a2)})`)
v = s_read(a2)
p = fresh()
emit(` %${p}_ptag =l and ${v}, 7`)
emit(` %${p}_is_ptr =w ceql %${p}_ptag, 1`)
emit(` jnz %${p}_is_ptr, @${p}_ptr, @${p}_yes`)
emit(`@${p}_ptr`)
emit(` %${p}_ptr =l and ${v}, -8`)
emit(` %${p}_hdr =l loadl %${p}_ptr`)
emit(`@${p}_chase`)
emit(` %${p}_ht =l and %${p}_hdr, 7`)
emit(` %${p}_is_fwd =w ceql %${p}_ht, 7`)
emit(` jnz %${p}_is_fwd, @${p}_follow, @${p}_chk`)
emit(`@${p}_follow`)
emit(` %${p}_ptr =l shr %${p}_hdr, 3`)
emit(` %${p}_hdr =l loadl %${p}_ptr`)
emit(` jmp @${p}_chase`)
emit(`@${p}_chk`)
emit(` %${p}_s =l and %${p}_hdr, 8`)
emit(` %${p}_w =w cnel %${p}_s, 0`)
emit(` jmp @${p}_done`)
emit(`@${p}_yes`)
emit(` %${p}_w =w copy 1`)
emit(`@${p}_done`)
s_write(a1, emit_pack_bool_js(`%${p}_w`))
continue
}
if (op == "is_proxy") {
emit(` call $__is_proxy_ss(l %ctx, l %fp, l ${text(a1)}, l ${text(a2)})`)
v = s_read(a2)
p = fresh()
emit(` %${p}_ptag =l and ${v}, 7`)
emit(` %${p}_is_ptr =w ceql %${p}_ptag, 1`)
emit(` jnz %${p}_is_ptr, @${p}_ptr, @${p}_no`)
emit(`@${p}_ptr`)
emit(` %${p}_ptr =l and ${v}, -8`)
emit(` %${p}_hdr =l loadl %${p}_ptr`)
emit(`@${p}_chase`)
emit(` %${p}_ht =l and %${p}_hdr, 7`)
emit(` %${p}_is_fwd =w ceql %${p}_ht, 7`)
emit(` jnz %${p}_is_fwd, @${p}_follow, @${p}_chk`)
emit(`@${p}_follow`)
emit(` %${p}_ptr =l shr %${p}_hdr, 3`)
emit(` %${p}_hdr =l loadl %${p}_ptr`)
emit(` jmp @${p}_chase`)
emit(`@${p}_chk`)
emit(` %${p}_is_fn =w ceql %${p}_ht, 4`)
emit(` jnz %${p}_is_fn, @${p}_len_chk, @${p}_no`)
emit(`@${p}_len_chk`)
emit(` %${p}_len_p =l add %${p}_ptr, 16`)
emit(` %${p}_len_q =l loadl %${p}_len_p`)
emit(` %${p}_len =l and %${p}_len_q, 65535`)
emit(` %${p}_w =w ceql %${p}_len, 2`)
emit(` jmp @${p}_done`)
emit(`@${p}_no`)
emit(` %${p}_w =w copy 0`)
emit(`@${p}_done`)
s_write(a1, emit_pack_bool_js(`%${p}_w`))
continue
}
if (op == "is_blob" || op == "is_data" || op == "is_fit" ||
op == "is_char" || op == "is_digit" || op == "is_letter" ||
if (op == "is_blob") {
v = s_read(a2)
p = fresh()
emit(` %${p}_ptag =l and ${v}, 7`)
emit(` %${p}_is_ptr =w ceql %${p}_ptag, 1`)
emit(` jnz %${p}_is_ptr, @${p}_ptr, @${p}_no`)
emit(`@${p}_ptr`)
emit(` %${p}_ptr =l and ${v}, -8`)
emit(` %${p}_hdr =l loadl %${p}_ptr`)
emit(`@${p}_chase`)
emit(` %${p}_ht =l and %${p}_hdr, 7`)
emit(` %${p}_is_fwd =w ceql %${p}_ht, 7`)
emit(` jnz %${p}_is_fwd, @${p}_follow, @${p}_chk`)
emit(`@${p}_follow`)
emit(` %${p}_ptr =l shr %${p}_hdr, 3`)
emit(` %${p}_hdr =l loadl %${p}_ptr`)
emit(` jmp @${p}_chase`)
emit(`@${p}_chk`)
emit(` %${p}_w =w ceql %${p}_ht, 1`)
emit(` jmp @${p}_done`)
emit(`@${p}_no`)
emit(` %${p}_w =w copy 0`)
emit(`@${p}_done`)
s_write(a1, emit_pack_bool_js(`%${p}_w`))
continue
}
if (op == "is_data") {
v = s_read(a2)
p = fresh()
emit(` %${p}_ptag =l and ${v}, 7`)
emit(` %${p}_is_ptr =w ceql %${p}_ptag, 1`)
emit(` jnz %${p}_is_ptr, @${p}_ptr, @${p}_no`)
emit(`@${p}_ptr`)
emit(` %${p}_ptr =l and ${v}, -8`)
emit(` %${p}_hdr =l loadl %${p}_ptr`)
emit(`@${p}_chase`)
emit(` %${p}_ht =l and %${p}_hdr, 7`)
emit(` %${p}_is_fwd =w ceql %${p}_ht, 7`)
emit(` jnz %${p}_is_fwd, @${p}_follow, @${p}_chk`)
emit(`@${p}_follow`)
emit(` %${p}_ptr =l shr %${p}_hdr, 3`)
emit(` %${p}_hdr =l loadl %${p}_ptr`)
emit(` jmp @${p}_chase`)
emit(`@${p}_chk`)
emit(` %${p}_is_arr =w ceql %${p}_ht, 0`)
emit(` %${p}_is_fn =w ceql %${p}_ht, 4`)
emit(` %${p}_is_blob =w ceql %${p}_ht, 1`)
emit(` %${p}_bad =w or %${p}_is_arr, %${p}_is_fn`)
emit(` %${p}_bad =w or %${p}_bad, %${p}_is_blob`)
emit(` %${p}_w =w ceqw %${p}_bad, 0`)
emit(` jmp @${p}_done`)
emit(`@${p}_no`)
emit(` %${p}_w =w copy 0`)
emit(`@${p}_done`)
s_write(a1, emit_pack_bool_js(`%${p}_w`))
continue
}
if (op == "is_fit") {
v = s_read(a2)
p = fresh()
emit(` %${p}_tag =l and ${v}, 1`)
emit(` %${p}_is_int =w ceql %${p}_tag, 0`)
emit(` jnz %${p}_is_int, @${p}_yes, @${p}_sfloat_chk`)
emit(`@${p}_sfloat_chk`)
emit(` %${p}_ptag =l and ${v}, 7`)
emit(` %${p}_is_sfloat =w ceql %${p}_ptag, 5`)
emit(` jnz %${p}_is_sfloat, @${p}_sfloat, @${p}_no`)
emit(`@${p}_sfloat`)
lhs_d = emit_num_to_double(v)
emit(` %${p}_ti =d call $trunc(d ${lhs_d})`)
emit(` %${p}_eqi =w ceqd ${lhs_d}, %${p}_ti`)
emit(` %${p}_ad =d call $fabs(d ${lhs_d})`)
emit(` %${p}_ltlim =w cltd %${p}_ad, d_9007199254740992.0`)
emit(` %${p}_eqlim =w ceqd %${p}_ad, d_9007199254740992.0`)
emit(` %${p}_lim =w or %${p}_ltlim, %${p}_eqlim`)
emit(` %${p}_w =w and %${p}_eqi, %${p}_lim`)
emit(` jmp @${p}_done`)
emit(`@${p}_yes`)
emit(` %${p}_w =w copy 1`)
emit(` jmp @${p}_done`)
emit(`@${p}_no`)
emit(` %${p}_w =w copy 0`)
emit(`@${p}_done`)
s_write(a1, emit_pack_bool_js(`%${p}_w`))
continue
}
if (op == "is_char") {
v = s_read(a2)
p = fresh()
emit(` %${p}_imm =l and ${v}, 31`)
emit(` %${p}_is_imm =w ceql %${p}_imm, 11`)
emit(` jnz %${p}_is_imm, @${p}_imm_path, @${p}_ptr_chk`)
emit(`@${p}_imm_path`)
emit(` %${p}_ilen =l shr ${v}, 5`)
emit(` %${p}_ilen =l and %${p}_ilen, 7`)
emit(` %${p}_w =w ceql %${p}_ilen, 1`)
emit(` jmp @${p}_done`)
emit(`@${p}_ptr_chk`)
emit(` %${p}_ptag =l and ${v}, 7`)
emit(` %${p}_is_ptr =w ceql %${p}_ptag, 1`)
emit(` jnz %${p}_is_ptr, @${p}_ptr, @${p}_no`)
emit(`@${p}_ptr`)
emit(` %${p}_ptr =l and ${v}, -8`)
emit(` %${p}_hdr =l loadl %${p}_ptr`)
emit(`@${p}_chase`)
emit(` %${p}_ht =l and %${p}_hdr, 7`)
emit(` %${p}_is_fwd =w ceql %${p}_ht, 7`)
emit(` jnz %${p}_is_fwd, @${p}_follow, @${p}_chk`)
emit(`@${p}_follow`)
emit(` %${p}_ptr =l shr %${p}_hdr, 3`)
emit(` %${p}_hdr =l loadl %${p}_ptr`)
emit(` jmp @${p}_chase`)
emit(`@${p}_chk`)
emit(` %${p}_is_text =w ceql %${p}_ht, 2`)
emit(` jnz %${p}_is_text, @${p}_len_chk, @${p}_no`)
emit(`@${p}_len_chk`)
emit(` %${p}_len_p =l add %${p}_ptr, 8`)
emit(` %${p}_len_l =l loadl %${p}_len_p`)
emit(` %${p}_w =w ceql %${p}_len_l, 1`)
emit(` jmp @${p}_done`)
emit(`@${p}_no`)
emit(` %${p}_w =w copy 0`)
emit(`@${p}_done`)
s_write(a1, emit_pack_bool_js(`%${p}_w`))
continue
}
if (op == "is_digit" || op == "is_letter" ||
op == "is_lower" || op == "is_upper" || op == "is_ws") {
v = s_read(a2)
p = fresh()
emit(` %${p}_w =w call $cell_rt_${op}(l ${v})`)
emit(` %${p}_imm =l and ${v}, 31`)
emit(` %${p}_is_imm =w ceql %${p}_imm, 11`)
emit(` jnz %${p}_is_imm, @${p}_imm_len, @${p}_ptr_chk`)
emit(`@${p}_imm_len`)
emit(` %${p}_ilen =l shr ${v}, 5`)
emit(` %${p}_ilen =l and %${p}_ilen, 7`)
emit(` %${p}_imm_one =w ceql %${p}_ilen, 1`)
emit(` jnz %${p}_imm_one, @${p}_imm_char, @${p}_no`)
emit(`@${p}_imm_char`)
emit(` %${p}_ch_l =l shr ${v}, 8`)
emit(` %${p}_ch_l =l and %${p}_ch_l, 255`)
emit(` %${p}_ch_w =w copy %${p}_ch_l`)
emit(` jmp @${p}_pred`)
emit(`@${p}_ptr_chk`)
emit(` %${p}_ptag =l and ${v}, 7`)
emit(` %${p}_is_ptr =w ceql %${p}_ptag, 1`)
emit(` jnz %${p}_is_ptr, @${p}_ptr, @${p}_no`)
emit(`@${p}_ptr`)
emit(` %${p}_ptr =l and ${v}, -8`)
emit(` %${p}_hdr =l loadl %${p}_ptr`)
emit(`@${p}_chase`)
emit(` %${p}_ht =l and %${p}_hdr, 7`)
emit(` %${p}_is_fwd =w ceql %${p}_ht, 7`)
emit(` jnz %${p}_is_fwd, @${p}_follow, @${p}_text_chk`)
emit(`@${p}_follow`)
emit(` %${p}_ptr =l shr %${p}_hdr, 3`)
emit(` %${p}_hdr =l loadl %${p}_ptr`)
emit(` jmp @${p}_chase`)
emit(`@${p}_text_chk`)
emit(` %${p}_is_text =w ceql %${p}_ht, 2`)
emit(` jnz %${p}_is_text, @${p}_text_len, @${p}_no`)
emit(`@${p}_text_len`)
emit(` %${p}_len_p =l add %${p}_ptr, 8`)
emit(` %${p}_len_l =l loadl %${p}_len_p`)
emit(` %${p}_text_one =w ceql %${p}_len_l, 1`)
emit(` jnz %${p}_text_one, @${p}_text_char, @${p}_no`)
emit(`@${p}_text_char`)
emit(` %${p}_pack_p =l add %${p}_ptr, 24`)
emit(` %${p}_pack =l loadl %${p}_pack_p`)
emit(` %${p}_ch_l =l shr %${p}_pack, 32`)
emit(` %${p}_ch_l =l and %${p}_ch_l, 255`)
emit(` %${p}_ch_w =w copy %${p}_ch_l`)
emit(`@${p}_pred`)
if (op == "is_digit") {
emit(` %${p}_lt_0 =w csltw %${p}_ch_w, 48`)
emit(` %${p}_ge_0 =w ceqw %${p}_lt_0, 0`)
emit(` %${p}_lt_9 =w csltw %${p}_ch_w, 58`)
emit(` %${p}_w =w and %${p}_ge_0, %${p}_lt_9`)
} else if (op == "is_lower") {
emit(` %${p}_lt_a =w csltw %${p}_ch_w, 97`)
emit(` %${p}_ge_a =w ceqw %${p}_lt_a, 0`)
emit(` %${p}_lt_z =w csltw %${p}_ch_w, 123`)
emit(` %${p}_w =w and %${p}_ge_a, %${p}_lt_z`)
} else if (op == "is_upper") {
emit(` %${p}_lt_A =w csltw %${p}_ch_w, 65`)
emit(` %${p}_ge_A =w ceqw %${p}_lt_A, 0`)
emit(` %${p}_lt_Z =w csltw %${p}_ch_w, 91`)
emit(` %${p}_w =w and %${p}_ge_A, %${p}_lt_Z`)
} else if (op == "is_letter") {
emit(` %${p}_lt_A =w csltw %${p}_ch_w, 65`)
emit(` %${p}_ge_A =w ceqw %${p}_lt_A, 0`)
emit(` %${p}_lt_Z =w csltw %${p}_ch_w, 91`)
emit(` %${p}_is_upper =w and %${p}_ge_A, %${p}_lt_Z`)
emit(` %${p}_lt_a =w csltw %${p}_ch_w, 97`)
emit(` %${p}_ge_a =w ceqw %${p}_lt_a, 0`)
emit(` %${p}_lt_z =w csltw %${p}_ch_w, 123`)
emit(` %${p}_is_lower =w and %${p}_ge_a, %${p}_lt_z`)
emit(` %${p}_w =w or %${p}_is_upper, %${p}_is_lower`)
} else {
emit(` %${p}_is_sp =w ceqw %${p}_ch_w, 32`)
emit(` %${p}_is_tb =w ceqw %${p}_ch_w, 9`)
emit(` %${p}_is_nl =w ceqw %${p}_ch_w, 10`)
emit(` %${p}_is_cr =w ceqw %${p}_ch_w, 13`)
emit(` %${p}_is_ff =w ceqw %${p}_ch_w, 12`)
emit(` %${p}_is_vt =w ceqw %${p}_ch_w, 11`)
emit(` %${p}_w =w or %${p}_is_sp, %${p}_is_tb`)
emit(` %${p}_w =w or %${p}_w, %${p}_is_nl`)
emit(` %${p}_w =w or %${p}_w, %${p}_is_cr`)
emit(` %${p}_w =w or %${p}_w, %${p}_is_ff`)
emit(` %${p}_w =w or %${p}_w, %${p}_is_vt`)
}
emit(` jmp @${p}_done`)
emit(`@${p}_no`)
emit(` %${p}_w =w copy 0`)
emit(`@${p}_done`)
s_write(a1, emit_pack_bool_js(`%${p}_w`))
continue
}
@@ -1999,6 +2209,33 @@ var qbe_emit = function(ir, qbe, export_name) {
lhs = s_read(a2)
rhs = s_read(a3)
p = fresh()
emit(` %${p}_a_tag =l and ${lhs}, 1`)
emit(` %${p}_b_tag =l and ${rhs}, 1`)
emit(` %${p}_a_int =w ceql %${p}_a_tag, 0`)
emit(` %${p}_b_int =w ceql %${p}_b_tag, 0`)
emit(` %${p}_both_int =w and %${p}_a_int, %${p}_b_int`)
emit(` jnz %${p}_both_int, @${p}_int, @${p}_slow`)
emit(`@${p}_int`)
emit(` %${p}_ai =l sar ${lhs}, 1`)
emit(` %${p}_bi =l sar ${rhs}, 1`)
emit(` %${p}_aiw =w copy %${p}_ai`)
emit(` %${p}_biw =w copy %${p}_bi`)
if (op == "eq") {
emit(` %${p}_w =w ceqw %${p}_aiw, %${p}_biw`)
} else if (op == "ne") {
emit(` %${p}_w =w cnew %${p}_aiw, %${p}_biw`)
} else if (op == "lt") {
emit(` %${p}_w =w csltw %${p}_aiw, %${p}_biw`)
} else if (op == "le") {
emit(` %${p}_w =w cslew %${p}_aiw, %${p}_biw`)
} else if (op == "gt") {
emit(` %${p}_w =w csgtw %${p}_aiw, %${p}_biw`)
} else {
emit(` %${p}_w =w csgew %${p}_aiw, %${p}_biw`)
}
s_write(a1, emit_pack_bool_js(`%${p}_w`))
emit(` jmp @${p}_done`)
emit(`@${p}_slow`)
cmp_id = 0
if (op == "eq") cmp_id = 0
else if (op == "ne") cmp_id = 1
@@ -2016,6 +2253,7 @@ var qbe_emit = function(ir, qbe, export_name) {
}
emit(`@${p}_ok`)
s_write(a1, `%${p}_r`)
emit(`@${p}_done`)
continue
}
@@ -2032,11 +2270,31 @@ var qbe_emit = function(ir, qbe, export_name) {
continue
}
if (op == "and") {
emit(` call $__and_ss(l %ctx, l %fp, l ${text(a1)}, l ${text(a2)}, l ${text(a3)})`)
lhs = s_read(a2)
rhs = s_read(a3)
p = fresh()
truthy = emit_truthy_w(lhs)
emit(` jnz ${truthy}, @${p}_t, @${p}_f`)
emit(`@${p}_t`)
s_write(a1, rhs)
emit(` jmp @${p}_done`)
emit(`@${p}_f`)
s_write(a1, lhs)
emit(`@${p}_done`)
continue
}
if (op == "or") {
emit(` call $__or_ss(l %ctx, l %fp, l ${text(a1)}, l ${text(a2)}, l ${text(a3)})`)
lhs = s_read(a2)
rhs = s_read(a3)
p = fresh()
truthy = emit_truthy_w(lhs)
emit(` jnz ${truthy}, @${p}_t, @${p}_f`)
emit(`@${p}_t`)
s_write(a1, lhs)
emit(` jmp @${p}_done`)
emit(`@${p}_f`)
s_write(a1, rhs)
emit(`@${p}_done`)
continue
}
@@ -2210,8 +2468,66 @@ var qbe_emit = function(ir, qbe, export_name) {
}
if (op == "store_index") {
// IR: ["store_index", obj, val, idx]
lhs = s_read(a1)
rhs = s_read(a2)
v = s_read(a3)
p = fresh()
emit(` %${p}_idx_tag =l and ${v}, 1`)
emit(` %${p}_idx_is_int =w ceql %${p}_idx_tag, 0`)
emit(` jnz %${p}_idx_is_int, @${p}_idx_ok, @${p}_slow`)
emit(`@${p}_idx_ok`)
emit(` %${p}_idx_l =l sar ${v}, 1`)
emit(` %${p}_idx_w =w copy %${p}_idx_l`)
emit(` %${p}_idx_neg =w csltw %${p}_idx_w, 0`)
emit(` jnz %${p}_idx_neg, @${p}_slow, @${p}_arr_ptr_chk`)
emit(`@${p}_arr_ptr_chk`)
emit(` %${p}_ptag =l and ${lhs}, 7`)
emit(` %${p}_is_ptr =w ceql %${p}_ptag, 1`)
emit(` jnz %${p}_is_ptr, @${p}_arr_ptr, @${p}_slow`)
emit(`@${p}_arr_ptr`)
emit(` %${p}_arr_ptr =l and ${lhs}, -8`)
emit(` %${p}_arr_hdr =l loadl %${p}_arr_ptr`)
emit(`@${p}_arr_chase`)
emit(` %${p}_arr_ty =l and %${p}_arr_hdr, 7`)
emit(` %${p}_arr_is_fwd =w ceql %${p}_arr_ty, 7`)
emit(` jnz %${p}_arr_is_fwd, @${p}_arr_follow, @${p}_arr_chk`)
emit(`@${p}_arr_follow`)
emit(` %${p}_arr_ptr =l shr %${p}_arr_hdr, 3`)
emit(` %${p}_arr_hdr =l loadl %${p}_arr_ptr`)
emit(` jmp @${p}_arr_chase`)
emit(`@${p}_arr_chk`)
emit(` %${p}_arr_is_array =w ceql %${p}_arr_ty, 0`)
emit(` jnz %${p}_arr_is_array, @${p}_arr_stone_chk, @${p}_slow`)
emit(`@${p}_arr_stone_chk`)
emit(` %${p}_arr_stone =l and %${p}_arr_hdr, 8`)
emit(` %${p}_arr_is_stone =w cnel %${p}_arr_stone, 0`)
emit(` jnz %${p}_arr_is_stone, @${p}_slow, @${p}_cap_chk`)
emit(`@${p}_cap_chk`)
emit(` %${p}_cap_l =l shr %${p}_arr_hdr, 8`)
emit(` %${p}_cap_w =w copy %${p}_cap_l`)
emit(` %${p}_in_cap =w csltw %${p}_idx_w, %${p}_cap_w`)
emit(` jnz %${p}_in_cap, @${p}_len_chk, @${p}_slow`)
emit(`@${p}_len_chk`)
emit(` %${p}_len_p =l add %${p}_arr_ptr, 8`)
emit(` %${p}_len_l =l loadl %${p}_len_p`)
emit(` %${p}_len_w =w copy %${p}_len_l`)
emit(` %${p}_need_len =w csgew %${p}_idx_w, %${p}_len_w`)
emit(` jnz %${p}_need_len, @${p}_bump_len, @${p}_store`)
emit(`@${p}_bump_len`)
emit(` %${p}_next_len_w =w add %${p}_idx_w, 1`)
emit(` %${p}_next_len_l =l extsw %${p}_next_len_w`)
emit(` storel %${p}_next_len_l, %${p}_len_p`)
emit(`@${p}_store`)
emit(` %${p}_idx2_l =l extsw %${p}_idx_w`)
emit(` %${p}_idx2_off =l shl %${p}_idx2_l, 3`)
emit(` %${p}_vals_p =l add %${p}_arr_ptr, 16`)
emit(` %${p}_item_p =l add %${p}_vals_p, %${p}_idx2_off`)
emit(` storel ${rhs}, %${p}_item_p`)
emit(` jmp @${p}_done`)
emit(`@${p}_slow`)
emit(` %fp =l call $__store_index_ss(l %ctx, l %fp, l ${text(a1)}, l ${text(a2)}, l ${text(a3)})`)
emit_exc_check()
emit(`@${p}_done`)
continue
}
if (op == "store_dynamic") {
@@ -2240,15 +2556,53 @@ var qbe_emit = function(ir, qbe, export_name) {
if (op == "get") {
// mcode: get(dest, slot, depth) — a2=slot, a3=depth
p = fresh()
emit(` %${p} =l call $cell_rt_get_closure(l %ctx, l %fp, l ${text(a3)}, l ${text(a2)})`)
s_write(a1, `%${p}`)
depth = a3
if (depth == 0) {
v = s_read(a2)
s_write(a1, v)
} else {
p = fresh()
emit(` %${p}_fp =l copy %fp`)
d = 0
while (d < depth) {
emit(` %${p}_fn_p_${text(d)} =l sub %${p}_fp, 24`)
emit(` %${p}_fn_${text(d)} =l loadl %${p}_fn_p_${text(d)}`)
emit(` %${p}_fn_ptr_${text(d)} =l and %${p}_fn_${text(d)}, -8`)
emit(` %${p}_outer_p_${text(d)} =l add %${p}_fn_ptr_${text(d)}, 40`)
emit(` %${p}_outer_${text(d)} =l loadl %${p}_outer_p_${text(d)}`)
emit(` %${p}_outer_ptr_${text(d)} =l and %${p}_outer_${text(d)}, -8`)
emit(` %${p}_fp =l add %${p}_outer_ptr_${text(d)}, 32`)
d = d + 1
}
emit(` %${p}_slotp =l add %${p}_fp, ${text(a2 * 8)}`)
emit(` %${p}_val =l loadl %${p}_slotp`)
s_write(a1, `%${p}_val`)
}
continue
}
if (op == "put") {
// mcode: put(val, slot, depth) — a2=slot, a3=depth
v = s_read(a1)
emit(` call $cell_rt_put_closure(l %ctx, l %fp, l ${v}, l ${text(a3)}, l ${text(a2)})`)
depth = a3
if (depth == 0) {
s_write(a2, v)
} else {
p = fresh()
emit(` %${p}_fp =l copy %fp`)
d = 0
while (d < depth) {
emit(` %${p}_fn_p_${text(d)} =l sub %${p}_fp, 24`)
emit(` %${p}_fn_${text(d)} =l loadl %${p}_fn_p_${text(d)}`)
emit(` %${p}_fn_ptr_${text(d)} =l and %${p}_fn_${text(d)}, -8`)
emit(` %${p}_outer_p_${text(d)} =l add %${p}_fn_ptr_${text(d)}, 40`)
emit(` %${p}_outer_${text(d)} =l loadl %${p}_outer_p_${text(d)}`)
emit(` %${p}_outer_ptr_${text(d)} =l and %${p}_outer_${text(d)}, -8`)
emit(` %${p}_fp =l add %${p}_outer_ptr_${text(d)}, 32`)
d = d + 1
}
emit(` %${p}_slotp =l add %${p}_fp, ${text(a2 * 8)}`)
emit(` storel ${v}, %${p}_slotp`)
}
continue
}
@@ -2401,8 +2755,52 @@ var qbe_emit = function(ir, qbe, export_name) {
// --- Array push/pop [G] ---
if (op == "push") {
lhs = s_read(a1)
rhs = s_read(a2)
p = fresh()
emit(` %${p}_ptag =l and ${lhs}, 7`)
emit(` %${p}_is_ptr =w ceql %${p}_ptag, 1`)
emit(` jnz %${p}_is_ptr, @${p}_arr_ptr, @${p}_slow`)
emit(`@${p}_arr_ptr`)
emit(` %${p}_arr_ptr =l and ${lhs}, -8`)
emit(` %${p}_arr_hdr =l loadl %${p}_arr_ptr`)
emit(`@${p}_arr_chase`)
emit(` %${p}_arr_ty =l and %${p}_arr_hdr, 7`)
emit(` %${p}_arr_is_fwd =w ceql %${p}_arr_ty, 7`)
emit(` jnz %${p}_arr_is_fwd, @${p}_arr_follow, @${p}_arr_chk`)
emit(`@${p}_arr_follow`)
emit(` %${p}_arr_ptr =l shr %${p}_arr_hdr, 3`)
emit(` %${p}_arr_hdr =l loadl %${p}_arr_ptr`)
emit(` jmp @${p}_arr_chase`)
emit(`@${p}_arr_chk`)
emit(` %${p}_arr_is_array =w ceql %${p}_arr_ty, 0`)
emit(` jnz %${p}_arr_is_array, @${p}_arr_stone_chk, @${p}_slow`)
emit(`@${p}_arr_stone_chk`)
emit(` %${p}_arr_stone =l and %${p}_arr_hdr, 8`)
emit(` %${p}_arr_is_stone =w cnel %${p}_arr_stone, 0`)
emit(` jnz %${p}_arr_is_stone, @${p}_slow, @${p}_lens`)
emit(`@${p}_lens`)
emit(` %${p}_len_p =l add %${p}_arr_ptr, 8`)
emit(` %${p}_len_l =l loadl %${p}_len_p`)
emit(` %${p}_len_w =w copy %${p}_len_l`)
emit(` %${p}_cap_l =l shr %${p}_arr_hdr, 8`)
emit(` %${p}_cap_w =w copy %${p}_cap_l`)
emit(` %${p}_in_cap =w csltw %${p}_len_w, %${p}_cap_w`)
emit(` jnz %${p}_in_cap, @${p}_store, @${p}_slow`)
emit(`@${p}_store`)
emit(` %${p}_idx_l =l extsw %${p}_len_w`)
emit(` %${p}_idx_off =l shl %${p}_idx_l, 3`)
emit(` %${p}_vals_p =l add %${p}_arr_ptr, 16`)
emit(` %${p}_item_p =l add %${p}_vals_p, %${p}_idx_off`)
emit(` storel ${rhs}, %${p}_item_p`)
emit(` %${p}_next_len_w =w add %${p}_len_w, 1`)
emit(` %${p}_next_len_l =l extsw %${p}_next_len_w`)
emit(` storel %${p}_next_len_l, %${p}_len_p`)
emit(` jmp @${p}_done`)
emit(`@${p}_slow`)
emit(` %fp =l call $__push_ss(l %ctx, l %fp, l ${text(a1)}, l ${text(a2)})`)
emit_exc_check()
emit(`@${p}_done`)
continue
}
if (op == "pop") {