wary booleans

This commit is contained in:
2026-02-21 20:42:17 -06:00
parent 8f415fea80
commit 8e96379377
9 changed files with 34034 additions and 36303 deletions

View File

@@ -95,22 +95,9 @@
"nr_close_slots": 0,
"instructions": [
["move", 2, 1, 14, 14],
[
"access",
3,
{
"name": "is_blob",
"kind": "name",
"make": "intrinsic"
},
15,
8
],
["frame", 4, 3, 1, 15, 8],
["setarg", 4, 1, 1, 15, 8],
["invoke", 4, 3, 15, 8],
["is_blob", 3, 1, 15, 16],
"_nop_bl_1",
["jump_true", 3, "if_else_6", 15, 8],
["jump_true", 3, "if_else_6", 15, 16],
[
"access",
3,
@@ -199,7 +186,7 @@
"_nop_ur_1",
"_nop_ur_2"
],
"_write_types": [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "null", "text", "array", null, null, null, "text", null, null, null, null],
"_write_types": [null, null, null, "bool", null, null, null, null, null, null, null, null, null, null, null, null, null, "null", "text", "array", null, null, null, "text", null, null, null, null],
"name": "content_hash",
"filename": ".cell/packages/core/internal/bootstrap.cm",
"nr_args": 1
@@ -222,7 +209,7 @@
8
],
"_nop_bl_1",
["jump_true", 2, "if_else_10", 20, 8],
["wary_true", 2, "if_else_10", 20, 8],
["null", 2, 20, 26],
["return", 2, 20, 26],
"_nop_ur_1",
@@ -345,7 +332,7 @@
8
],
"_nop_bl_1",
["jump_true", 1, "if_else_18", 25, 8],
["wary_true", 1, "if_else_18", 25, 8],
["null", 1, 25, 26],
["return", 1, 25, 26],
"_nop_ur_1",
@@ -427,7 +414,7 @@
["invoke", 5, 3, 27, 8],
"call_done_26",
"_nop_bl_2",
["jump_true", 3, "if_else_23", 27, 8],
["wary_true", 3, "if_else_23", 27, 8],
["get", 2, 11, 1, 27, 24],
["is_proxy", 3, 2, 27, 24],
["jump_false", 3, "record_path_27", 27, 24],
@@ -628,7 +615,7 @@
["invoke", 8, 6, 36, 8],
"call_done_41",
"_nop_bl_1",
["jump_true", 6, "if_else_38", 36, 8],
["wary_true", 6, "if_else_38", 36, 8],
["access", 5, "error: missing seed: ", 37, 14],
"_nop_tc_7",
"_nop_tc_8",
@@ -1026,30 +1013,11 @@
"call_done_63",
"if_end_58",
["access", 3, 1, 66, 17],
"_nop_tc_1",
"_nop_tc_2",
"_nop_tc_3",
"_nop_tc_4",
["add", 5, 5, 3, 66, 17],
["jump", "num_done_65", 66, 17],
"num_err_64",
"_nop_ucfg_1",
"_nop_ucfg_2",
"_nop_ucfg_3",
"_nop_ucfg_4",
"_nop_ucfg_5",
"_nop_ucfg_6",
"_nop_ucfg_7",
"_nop_ucfg_8",
"_nop_ucfg_9",
"_nop_ucfg_10",
"_nop_ucfg_11",
"_nop_ucfg_12",
"num_done_65",
["jump", "while_start_55", 66, 17],
"while_end_56",
["disrupt", 68, 5],
"_nop_ucfg_13",
"_nop_ucfg_1",
"if_else_53",
"if_end_54",
["get", 3, 15, 1, 70, 10],
@@ -1060,7 +1028,7 @@
"_nop_ur_1",
"_nop_ur_2"
],
"_write_types": [null, null, null, "int", null, null, "bool", null, null, null, null, null, null, null, null, null, null, null, "null", "bool", "bool", null, "int", "int", "bool", null, "int", "bool", null, null, null, null, "null", "bool", "bool", null, "null", "bool", null, null, null, null, null, null, null, null, "array", null, "text", null, null, null, null, null, "null", "text", "array", null, null, null, "array", null, "text", null, null, null, null, null, "null", "text", "array", null, null, null, "int", null, null, null, null, null, null, null, null, null, null, null, null, null],
"_write_types": [null, null, null, "int", null, null, "bool", null, null, null, null, null, null, null, null, null, null, null, "null", "bool", "bool", null, "int", "int", "bool", null, "int", "bool", null, null, null, null, "null", "bool", "bool", null, "null", "bool", null, null, null, null, null, null, null, null, "array", null, "text", null, null, null, null, null, "null", "text", "array", null, null, null, "array", null, "text", null, null, null, null, null, "null", "text", "array", null, null, null, "int", null, null, null, null],
"name": "analyze",
"filename": ".cell/packages/core/internal/bootstrap.cm",
"nr_args": 2
@@ -1078,7 +1046,7 @@
"instructions": [
["get", 3, 11, 1, 74, 21],
["is_proxy", 4, 3, 74, 21],
["jump_false", 4, "record_path_66", 74, 21],
["jump_false", 4, "record_path_64", 74, 21],
["null", 4, 74, 21],
["access", 5, "slurp", 74, 21],
["array", 6, 0, 74, 21],
@@ -1089,14 +1057,14 @@
["setarg", 7, 1, 5, 74, 21],
["setarg", 7, 2, 6, 74, 21],
["invoke", 7, 4, 74, 21],
["jump", "call_done_67", 74, 21],
"record_path_66",
["jump", "call_done_65", 74, 21],
"record_path_64",
["load_field", 5, 3, "slurp", 74, 21],
["frame", 6, 5, 1, 74, 21],
["setarg", 6, 0, 3, 74, 21],
["setarg", 6, 1, 2, 74, 21],
["invoke", 6, 4, 74, 21],
"call_done_67",
"call_done_65",
["move", 3, 4, 74, 21],
["get", 5, 4, 1, 75, 14],
["frame", 6, 5, 1, 75, 14],
@@ -1113,10 +1081,10 @@
["null", 8, 79, 20],
["null", 9, 80, 19],
["move", 10, 4, 81, 7],
["jump_false", 4, "and_end_70", 81, 7],
["wary_false", 4, "and_end_68", 81, 7],
["get", 4, 11, 1, 81, 17],
["is_proxy", 11, 4, 81, 17],
["jump_false", 11, "record_path_71", 81, 17],
["jump_false", 11, "record_path_69", 81, 17],
["null", 11, 81, 17],
["access", 12, "is_file", 81, 17],
["array", 13, 0, 81, 17],
@@ -1127,22 +1095,22 @@
["setarg", 14, 1, 12, 81, 17],
["setarg", 14, 2, 13, 81, 17],
["invoke", 14, 11, 81, 17],
["jump", "call_done_72", 81, 17],
"record_path_71",
["jump", "call_done_70", 81, 17],
"record_path_69",
["load_field", 12, 4, "is_file", 81, 17],
["frame", 13, 12, 1, 81, 17],
["setarg", 13, 0, 4, 81, 17],
["setarg", 13, 1, 5, 81, 17],
["invoke", 13, 11, 81, 17],
"call_done_72",
"call_done_70",
["move", 10, 11, 81, 17],
"and_end_70",
["jump_false", 10, "if_else_68", 81, 17],
"and_end_68",
["wary_false", 10, "if_else_66", 81, 17],
["null", 4, 81, 37],
["return", 4, 81, 37],
"_nop_ur_1",
"if_else_68",
"if_end_69",
"if_else_66",
"if_end_67",
[
"access",
4,
@@ -1174,7 +1142,7 @@
["move", 7, 3, 83, 14],
["get", 3, 12, 1, 84, 16],
["is_proxy", 4, 3, 84, 16],
["jump_false", 4, "record_path_73", 84, 16],
["jump_false", 4, "record_path_71", 84, 16],
["null", 4, 84, 16],
["access", 6, "encode", 84, 16],
["array", 10, 0, 84, 16],
@@ -1185,14 +1153,14 @@
["setarg", 11, 1, 6, 84, 16],
["setarg", 11, 2, 10, 84, 16],
["invoke", 11, 4, 84, 16],
["jump", "call_done_74", 84, 16],
"record_path_73",
["jump", "call_done_72", 84, 16],
"record_path_71",
["load_field", 6, 3, "encode", 84, 16],
["frame", 10, 6, 1, 84, 16],
["setarg", 10, 0, 3, 84, 16],
["setarg", 10, 1, 7, 84, 16],
["invoke", 10, 4, 84, 16],
"call_done_74",
"call_done_72",
["move", 8, 4, 84, 16],
[
"access",
@@ -1210,13 +1178,13 @@
["setarg", 6, 2, 4, 85, 15],
["invoke", 6, 3, 85, 15],
["move", 9, 3, 85, 15],
["jump_false", 5, "if_else_75", 86, 7],
["wary_false", 5, "if_else_73", 86, 7],
["get", 3, 6, 1, 87, 5],
["frame", 4, 3, 0, 87, 5],
["invoke", 4, 3, 87, 5],
["get", 3, 11, 1, 88, 5],
["is_proxy", 4, 3, 88, 5],
["jump_false", 4, "record_path_77", 88, 5],
["jump_false", 4, "record_path_75", 88, 5],
["null", 4, 88, 5],
["access", 6, "slurpwrite", 88, 5],
["array", 7, 0, 88, 5],
@@ -1228,18 +1196,18 @@
["setarg", 8, 1, 6, 88, 5],
["setarg", 8, 2, 7, 88, 5],
["invoke", 8, 4, 88, 5],
["jump", "call_done_78", 88, 5],
"record_path_77",
["jump", "call_done_76", 88, 5],
"record_path_75",
["load_field", 6, 3, "slurpwrite", 88, 5],
["frame", 7, 6, 2, 88, 5],
["setarg", 7, 0, 3, 88, 5],
["setarg", 7, 1, 5, 88, 5],
["setarg", 7, 2, 9, 88, 5],
["invoke", 7, 4, 88, 5],
"call_done_78",
["jump", "if_end_76", 88, 5],
"if_else_75",
"if_end_76",
"call_done_76",
["jump", "if_end_74", 88, 5],
"if_else_73",
"if_end_74",
["null", 3, 88, 5],
["return", 3, 88, 5]
],
@@ -1369,10 +1337,10 @@
["move", 1, 22, 99, 26],
["access", 17, 0, 101, 10],
["null", 18, 102, 13],
"while_start_79",
"while_start_77",
["length", 19, 1, 103, 20],
["lt", 20, 17, 19, 103, 20],
["jump_false", 20, "while_end_80", 103, 20],
["jump_false", 20, "while_end_78", 103, 20],
["load_index", 19, 1, 17, 104, 22],
["move", 18, 19, 104, 22],
["load_field", 20, 19, "name", 105, 21],
@@ -1389,19 +1357,19 @@
],
["access", 21, "/", 105, 45],
["is_text", 22, 19, 105, 45],
["jump_false", 22, "add_cn_82", 105, 45],
["jump_false", 22, "add_cn_80", 105, 45],
"_nop_tc_1",
"_nop_tc_2",
["concat", 23, 19, 21, 105, 45],
["jump", "add_done_81", 105, 45],
"add_cn_82",
["jump", "add_done_79", 105, 45],
"add_cn_80",
["is_num", 22, 19, 105, 45],
["jump_false", 22, "add_err_83", 105, 45],
["jump_false", 22, "add_err_81", 105, 45],
"_nop_tc_3",
"_nop_dj_1",
"_nop_ucfg_1",
"_nop_ucfg_2",
"add_err_83",
"add_err_81",
[
"access",
19,
@@ -1426,22 +1394,22 @@
["setarg", 22, 2, 24, 105, 45],
["invoke", 22, 19, 105, 45],
["disrupt", 105, 45],
"add_done_81",
"add_done_79",
["load_field", 19, 18, "path", 105, 51],
"_nop_tc_1",
"_nop_tc_2",
["is_text", 21, 19, 105, 51],
["jump_false", 21, "add_cn_85", 105, 51],
["jump_false", 21, "add_cn_83", 105, 51],
["concat", 21, 23, 19, 105, 51],
["jump", "add_done_84", 105, 51],
"add_cn_85",
["jump", "add_done_82", 105, 51],
"add_cn_83",
"_nop_tc_3",
["jump", "add_err_86", 105, 51],
["jump", "add_err_84", 105, 51],
"_nop_ucfg_1",
"_nop_ucfg_2",
"_nop_ucfg_3",
"_nop_ucfg_4",
"add_err_86",
"add_err_84",
[
"access",
19,
@@ -1466,35 +1434,16 @@
["setarg", 23, 2, 24, 105, 51],
["invoke", 23, 19, 105, 51],
["disrupt", 105, 51],
"add_done_84",
"add_done_82",
["frame", 19, 9, 2, 105, 3],
["setarg", 19, 1, 20, 105, 3],
["stone_text", 21],
["setarg", 19, 2, 21, 105, 3],
["invoke", 19, 20, 105, 3],
["access", 19, 1, 106, 13],
"_nop_tc_4",
"_nop_tc_5",
"_nop_tc_6",
"_nop_tc_7",
["add", 17, 17, 19, 106, 13],
["jump", "num_done_88", 106, 13],
"num_err_87",
"_nop_ucfg_3",
"_nop_ucfg_4",
"_nop_ucfg_5",
"_nop_ucfg_6",
"_nop_ucfg_7",
"_nop_ucfg_8",
"_nop_ucfg_9",
"_nop_ucfg_10",
"_nop_ucfg_11",
"_nop_ucfg_12",
"_nop_ucfg_13",
"_nop_ucfg_14",
"num_done_88",
["jump", "while_start_79", 106, 13],
"while_end_80",
["jump", "while_start_77", 106, 13],
"while_end_78",
["access", 1, "bootstrap: cache seeded\n", 108, 10],
[
"access",
@@ -1508,7 +1457,7 @@
1
],
["is_proxy", 17, 9, 108, 1],
["jump_false", 17, "record_path_89", 108, 1],
["jump_false", 17, "record_path_85", 108, 1],
["null", 17, 108, 1],
["access", 18, "print", 108, 1],
["array", 19, 0, 108, 1],
@@ -1520,18 +1469,18 @@
["setarg", 20, 1, 18, 108, 1],
["setarg", 20, 2, 19, 108, 1],
["invoke", 20, 17, 108, 1],
["jump", "call_done_90", 108, 1],
"record_path_89",
["jump", "call_done_86", 108, 1],
"record_path_85",
["load_field", 18, 9, "print", 108, 1],
["frame", 19, 18, 1, 108, 1],
["setarg", 19, 0, 9, 108, 1],
["stone_text", 1],
["setarg", 19, 1, 1, 108, 1],
["invoke", 19, 17, 108, 1],
"call_done_90",
"call_done_86",
["return", 17, 108, 1]
],
"_write_types": [null, "function", "function", "function", null, "function", null, null, null, null, null, null, null, null, "function", "int", "function", "function", null, "array", "function", "function", "function", "function", "function", "function", "function", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "array", "int", "bool", null, null, null, "text", "text", "bool", null, null, "text", "text", "array", null, null, "null", null, null, "bool", "bool", null, "text", "text", "array", null, null, "null", null, null, "int", null, null, null, null, null, null, null, null, null, "text", null, null, null, "null", "text", "array", null, null, null],
"_write_types": [null, "function", "function", "function", null, "function", null, null, null, null, null, null, null, null, "function", "int", "function", "function", null, "array", "function", "function", "function", "function", "function", "function", "function", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "text", null, null, "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "record", "text", "text", "array", "int", "bool", null, null, null, "text", "text", "bool", null, null, "text", "text", "array", null, null, "null", null, null, "bool", "bool", null, "text", "text", "array", null, null, "null", null, null, "int", "text", null, null, null, "null", "text", "array", null, null, null],
"nr_args": 0
},
"name": ".cell/packages/core/internal/bootstrap.cm",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -1035,7 +1035,7 @@ var mcode = function(ast) {
if (nargs <= 2) {
emit_forward_loop(fwd_L, body_fn)
} else {
emit_jump_cond("jump_true", args.rev, rev_label)
emit_jump_cond("wary_true", args.rev, rev_label)
emit_forward_loop(fwd_L, body_fn)
emit_jump(final_label)
emit_label(rev_label)
@@ -1093,7 +1093,7 @@ var mcode = function(ast) {
emit_3("setarg", f, 1, item)
emit_2("invoke", f, val)
emit_label(call_done_label)
emit_jump_cond("jump_false", val, ret_false)
emit_jump_cond("wary_false", val, ret_false)
emit_3("add", i, i, one)
emit_jump(loop_label)
emit_label(ret_true)
@@ -1146,7 +1146,7 @@ var mcode = function(ast) {
emit_3("setarg", f, 1, item)
emit_2("invoke", f, val)
emit_label(call_done_label)
emit_jump_cond("jump_true", val, ret_true)
emit_jump_cond("wary_true", val, ret_true)
emit_3("add", i, i, one)
emit_jump(loop_label)
emit_label(ret_true)
@@ -1186,7 +1186,7 @@ var mcode = function(ast) {
emit_2("length", fn_arity, fn_slot)
emit_forward_loop(L, function(L) {
emit_arity_call(ctx, [L.item, L.i], 2)
emit_jump_cond("jump_false", val, skip)
emit_jump_cond("wary_false", val, skip)
emit_2("push", result, L.item)
emit_label(skip)
return null
@@ -1240,7 +1240,7 @@ var mcode = function(ast) {
}
var fn_body = function(L) {
emit_arity_call(ctx, [L.item, L.i], 2)
emit_jump_cond("jump_true", val, found_label)
emit_jump_cond("wary_true", val, found_label)
return null
}
emit_2("length", len, arr_slot)
@@ -1253,7 +1253,7 @@ var mcode = function(ast) {
if (nargs <= 2) {
emit_forward_loop(vL, val_body)
} else {
emit_jump_cond("jump_true", args.rev, vrev)
emit_jump_cond("wary_true", args.rev, vrev)
if (nargs >= 4 && args.from >= 0) {
emit_2("move", i, args.from)
}
@@ -1281,7 +1281,7 @@ var mcode = function(ast) {
if (nargs <= 2) {
emit_forward_loop(fL, fn_body)
} else {
emit_jump_cond("jump_true", args.rev, frev)
emit_jump_cond("wary_true", args.rev, frev)
if (nargs >= 4 && args.from >= 0) {
emit_2("move", i, args.from)
}
@@ -1485,7 +1485,7 @@ var mcode = function(ast) {
// No initial
emit_3("lt", check, zero, len)
emit_jump_cond("jump_false", check, null_label)
emit_jump_cond("jump_true", rev_slot, no_init_rev)
emit_jump_cond("wary_true", rev_slot, no_init_rev)
// No initial, forward
emit_3("load_index", acc, arr_slot, zero)
emit_2("move", i, one)
@@ -1507,7 +1507,7 @@ var mcode = function(ast) {
emit_jump(final_label)
// Has initial
emit_label(has_init)
emit_jump_cond("jump_true", rev_slot, init_rev)
emit_jump_cond("wary_true", rev_slot, init_rev)
// Has initial, forward
emit_2("move", acc, init_slot)
emit_2("int", i, 0)
@@ -1554,7 +1554,7 @@ var mcode = function(ast) {
left_slot = gen_expr(left, -1)
dest = alloc_slot()
emit_2("move", dest, left_slot)
emit_jump_cond("jump_false", dest, end_label)
emit_jump_cond("wary_false", dest, end_label)
right_slot = gen_expr(right, -1)
emit_2("move", dest, right_slot)
emit_label(end_label)
@@ -1566,7 +1566,7 @@ var mcode = function(ast) {
left_slot = gen_expr(left, -1)
dest = alloc_slot()
emit_2("move", dest, left_slot)
emit_jump_cond("jump_true", dest, end_label)
emit_jump_cond("wary_true", dest, end_label)
right_slot = gen_expr(right, -1)
emit_2("move", dest, right_slot)
emit_label(end_label)
@@ -2361,7 +2361,7 @@ var mcode = function(ast) {
else_label = gen_label("tern_else")
end_label = gen_label("tern_end")
cond_slot = gen_expr(cond, -1)
emit_jump_cond("jump_false", cond_slot, else_label)
emit_jump_cond("wary_false", cond_slot, else_label)
dest = alloc_slot()
then_slot = gen_expr(then_expr, -1)
emit_2("move", dest, then_slot)
@@ -2586,7 +2586,7 @@ var mcode = function(ast) {
else_label = gen_label("if_else")
end_label = gen_label("if_end")
cond_slot = gen_expr(cond, -1)
emit_jump_cond("jump_false", cond_slot, else_label)
emit_jump_cond("wary_false", cond_slot, else_label)
_i = 0
while (_i < length(then_stmts)) {
gen_statement(then_stmts[_i])
@@ -2627,7 +2627,7 @@ var mcode = function(ast) {
}
emit_label(start_label)
cond_slot = gen_expr(cond, -1)
emit_jump_cond("jump_false", cond_slot, end_label)
emit_jump_cond("wary_false", cond_slot, end_label)
_i = 0
while (_i < length(stmts)) {
gen_statement(stmts[_i])
@@ -2662,7 +2662,7 @@ var mcode = function(ast) {
}
emit_label(cond_label)
cond_slot = gen_expr(cond, -1)
emit_jump_cond("jump_true", cond_slot, start_label)
emit_jump_cond("wary_true", cond_slot, start_label)
emit_label(end_label)
s_loop_break = old_break
s_loop_continue = old_continue
@@ -2696,7 +2696,7 @@ var mcode = function(ast) {
emit_label(start_label)
if (test != null) {
test_slot = gen_expr(test, -1)
emit_jump_cond("jump_false", test_slot, end_label)
emit_jump_cond("wary_false", test_slot, end_label)
}
_i = 0
while (_i < length(stmts)) {

View File

@@ -88,7 +88,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,9 @@ typedef enum MachOpcode {
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;
@@ -407,6 +410,9 @@ static const char *mach_opcode_names[MACH_OP_COUNT] = {
[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 ---- */
@@ -1429,6 +1435,7 @@ vm_dispatch:
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
@@ -2088,12 +2095,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) {
@@ -2114,12 +2116,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) {
@@ -2888,6 +2885,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;
@@ -3387,6 +3445,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));

View File

@@ -69,12 +69,19 @@ var streamline = function(ir, log) {
var no_clear_ops = {
int: true, access: true, true: true, false: true, move: true, null: true,
jump: true, jump_true: true, jump_false: true, jump_not_null: true,
wary_true: true, wary_false: true, jump_null: true, jump_empty: true,
return: true, disrupt: true,
store_field: true, store_index: true, store_dynamic: true,
push: true, setarg: true, invoke: true, tail_invoke: true,
stone_text: true
}
var is_cond_jump = function(op) {
return op == "jump_true" || op == "jump_false" || op == "jump_not_null"
|| op == "wary_true" || op == "wary_false"
|| op == "jump_null" || op == "jump_empty"
}
// --- Logging support ---
var ir_stats = null
@@ -376,7 +383,12 @@ var streamline = function(ir, log) {
abs: T_NUM, floor: T_NUM, ceiling: T_NUM,
round: T_NUM, trunc: T_NUM, fraction: T_NUM,
integer: T_NUM, whole: T_NUM, sign: T_NUM,
max: T_NUM, min: T_NUM, remainder: T_NUM, modulo: T_NUM
max: T_NUM, min: T_NUM, remainder: T_NUM, modulo: T_NUM,
is_integer: T_BOOL, is_text: T_BOOL, is_number: T_BOOL,
is_null: T_BOOL, is_array: T_BOOL, is_function: T_BOOL,
is_object: T_BOOL, is_logical: T_BOOL, is_stone: T_BOOL,
is_blob: T_BOOL, starts_with: T_BOOL, ends_with: T_BOOL,
some: T_BOOL, every: T_BOOL
}
var narrow_arith_type = function(write_types, param_types, instr, typ) {
@@ -676,7 +688,49 @@ var streamline = function(ir, log) {
if (is_array(next)) {
next_op = next[0]
if (next_op == "jump_false" && next[1] == dest) {
// is_null + jump fusion: replace with jump_null / jump_not_null
if (op == "is_null" && (next_op == "jump_true" || next_op == "wary_true") && next[1] == dest) {
jlen = length(next)
nc = nc + 1
instructions[i] = "_nop_tc_" + text(nc)
instructions[i + 1] = ["jump_null", src, next[2], next[jlen - 2], next[jlen - 1]]
if (events != null) {
events[] = {
event: "rewrite",
pass: "eliminate_type_checks",
rule: "is_null_jump_fusion",
at: i,
before: [instr, next],
after: [instructions[i], instructions[i + 1]],
why: {slot: src, fused_to: "jump_null"}
}
}
slot_types[dest] = T_BOOL
i = i + 2
continue
}
if (op == "is_null" && (next_op == "jump_false" || next_op == "wary_false") && next[1] == dest) {
jlen = length(next)
nc = nc + 1
instructions[i] = "_nop_tc_" + text(nc)
instructions[i + 1] = ["jump_not_null", src, next[2], next[jlen - 2], next[jlen - 1]]
if (events != null) {
events[] = {
event: "rewrite",
pass: "eliminate_type_checks",
rule: "is_null_jump_fusion",
at: i,
before: [instr, next],
after: [instructions[i], instructions[i + 1]],
why: {slot: src, fused_to: "jump_not_null"}
}
}
slot_types[dest] = T_BOOL
i = i + 2
continue
}
if ((next_op == "jump_false" || next_op == "wary_false") && next[1] == dest) {
target_label = next[2]
if (slot_is(slot_types, src, checked_type)) {
nc = nc + 1
@@ -752,7 +806,7 @@ var streamline = function(ir, log) {
continue
}
if (next_op == "jump_true" && next[1] == dest) {
if ((next_op == "jump_true" || next_op == "wary_true") && next[1] == dest) {
target_label = next[2]
if (slot_is(slot_types, src, checked_type)) {
nc = nc + 1
@@ -891,6 +945,32 @@ var streamline = function(ir, log) {
continue
}
// Wary-to-certain: if slot type is T_BOOL, downgrade wary to certain jump
if (op == "wary_true" && slot_is(slot_types, instr[1], T_BOOL)) {
instr[0] = "jump_true"
if (events != null) {
events[] = {
event: "rewrite",
pass: "eliminate_type_checks",
rule: "wary_to_certain",
at: i, before: "wary_true", after: "jump_true",
why: {slot: instr[1], known_type: T_BOOL}
}
}
}
if (op == "wary_false" && slot_is(slot_types, instr[1], T_BOOL)) {
instr[0] = "jump_false"
if (events != null) {
events[] = {
event: "rewrite",
pass: "eliminate_type_checks",
rule: "wary_to_certain",
at: i, before: "wary_false", after: "jump_false",
why: {slot: instr[1], known_type: T_BOOL}
}
}
}
track_types(slot_types, instr)
i = i + 1
}
@@ -1048,11 +1128,12 @@ var streamline = function(ir, log) {
next_op = next[0]
nlen = length(next)
// not d, x; jump_false d, label → jump_true x, label
// not d, x; jump_false d, label → wary_true x, label
// (removing `not` removes coercion, so result must be wary)
if (next_op == "jump_false" && next[1] == instr[1]) {
nc = nc + 1
instructions[i] = "_nop_bl_" + text(nc)
instructions[i + 1] = ["jump_true", instr[2], next[2], next[nlen - 2], next[nlen - 1]]
instructions[i + 1] = ["wary_true", instr[2], next[2], next[nlen - 2], next[nlen - 1]]
if (events != null) {
events[] = {
event: "rewrite", pass: "simplify_booleans",
@@ -1065,11 +1146,11 @@ var streamline = function(ir, log) {
continue
}
// not d, x; jump_true d, label → jump_false x, label
// not d, x; jump_true d, label → wary_false x, label
if (next_op == "jump_true" && next[1] == instr[1]) {
nc = nc + 1
instructions[i] = "_nop_bl_" + text(nc)
instructions[i + 1] = ["jump_false", instr[2], next[2], next[nlen - 2], next[nlen - 1]]
instructions[i + 1] = ["wary_false", instr[2], next[2], next[nlen - 2], next[nlen - 1]]
if (events != null) {
events[] = {
event: "rewrite", pass: "simplify_booleans",
@@ -1082,6 +1163,40 @@ var streamline = function(ir, log) {
continue
}
// not d, x; wary_false d, label → wary_true x, label
if (next_op == "wary_false" && next[1] == instr[1]) {
nc = nc + 1
instructions[i] = "_nop_bl_" + text(nc)
instructions[i + 1] = ["wary_true", instr[2], next[2], next[nlen - 2], next[nlen - 1]]
if (events != null) {
events[] = {
event: "rewrite", pass: "simplify_booleans",
rule: "not_wary_false_fusion", at: i,
before: [instr, next],
after: [instructions[i], instructions[i + 1]]
}
}
i = i + 2
continue
}
// not d, x; wary_true d, label → wary_false x, label
if (next_op == "wary_true" && next[1] == instr[1]) {
nc = nc + 1
instructions[i] = "_nop_bl_" + text(nc)
instructions[i + 1] = ["wary_false", instr[2], next[2], next[nlen - 2], next[nlen - 1]]
if (events != null) {
events[] = {
event: "rewrite", pass: "simplify_booleans",
rule: "not_wary_true_fusion", at: i,
before: [instr, next],
after: [instructions[i], instructions[i + 1]]
}
}
i = i + 2
continue
}
// not d1, x; not d2, d1 → move d2, x
if (next_op == "not" && next[2] == instr[1]) {
nc = nc + 1
@@ -1169,7 +1284,7 @@ var streamline = function(ir, log) {
}
// Control flow with a read at position 1: substitute then clear
if (op == "return" || op == "jump_true" || op == "jump_false" || op == "jump_not_null") {
if (op == "return" || is_cond_jump(op)) {
actual = copies[text(instr[1])]
if (actual != null) {
instr[1] = actual
@@ -1351,7 +1466,7 @@ var streamline = function(ir, log) {
op = instr[0]
if (op == "jump") {
target = instr[1]
} else if (op == "jump_true" || op == "jump_false" || op == "jump_not_null") {
} else if (is_cond_jump(op)) {
target = instr[2]
}
if (target != null && is_text(target)) {
@@ -1558,7 +1673,7 @@ var streamline = function(ir, log) {
if (is_number(tgt)) stack[] = tgt
continue
}
if (op == "jump_true" || op == "jump_false" || op == "jump_not_null") {
if (is_cond_jump(op)) {
tgt = label_map[instr[2]]
if (is_number(tgt)) stack[] = tgt
stack[] = idx + 1
@@ -1663,6 +1778,7 @@ var streamline = function(ir, log) {
frame: [1, 2], goframe: [1, 2],
jump: [], disrupt: [],
jump_true: [1], jump_false: [1], jump_not_null: [1],
wary_true: [1], wary_false: [1], jump_null: [1], jump_empty: [1],
return: [1],
stone_text: [1]
}
@@ -1693,6 +1809,7 @@ var streamline = function(ir, log) {
setarg: [], store_field: [], store_index: [], store_dynamic: [],
push: [], set_var: [], stone_text: [],
jump: [], jump_true: [], jump_false: [], jump_not_null: [],
wary_true: [], wary_false: [], jump_null: [], jump_empty: [],
return: [], disrupt: []
}
@@ -1706,6 +1823,7 @@ var streamline = function(ir, log) {
store_dynamic: [1, 2, 3],
push: [1, 2], set_var: [1], stone_text: [1],
jump: [], jump_true: [1], jump_false: [1], jump_not_null: [1],
wary_true: [1], wary_false: [1], jump_null: [1], jump_empty: [1],
return: [1], disrupt: []
}
@@ -1843,7 +1961,7 @@ var streamline = function(ir, log) {
target = null
if (op == "jump") {
target = instr[1]
} else if (op == "jump_true" || op == "jump_false" || op == "jump_not_null") {
} else if (is_cond_jump(op)) {
target = instr[2]
}
if (target == null || !is_text(target)) {
@@ -2909,7 +3027,7 @@ var streamline = function(ir, log) {
// Remap labels in jump instructions
if (cop == "jump" && is_text(cinstr[1]) && !starts_with(cinstr[1], "_nop_")) {
new_instr[1] = label_prefix + cinstr[1]
} else if ((cop == "jump_true" || cop == "jump_false" || cop == "jump_not_null")
} else if (is_cond_jump(cop)
&& is_text(cinstr[2]) && !starts_with(cinstr[2], "_nop_")) {
new_instr[2] = label_prefix + cinstr[2]
}