fix stone crash

This commit is contained in:
2026-02-20 23:18:19 -06:00
parent bcc9bdac83
commit 50a2d67c90
3 changed files with 36 additions and 82 deletions

View File

@@ -1369,7 +1369,7 @@ JSValue gc_copy_value (JSContext *ctx, JSValue v, uint8_t *from_base, uint8_t *f
/* Frame shortening: returned frames (caller == JS_NULL) only need
[this][args][closure_locals] — shrink during copy. */
if (type == OBJ_FRAME) {
if (0 && type == OBJ_FRAME) {
JSFrame *f = (JSFrame *)hdr_ptr;
if (JS_IsNull (f->caller) && JS_IsPtr (f->function)) {
/* fn may be forwarded, but kind (offset 18) and u.cell.code (offset 24)

View File

@@ -1308,25 +1308,18 @@ var streamline = function(ir, log) {
var insert_stone_text = function(func, log) {
var instructions = func.instructions
var nr_slots = func.nr_slots
var dpc = func.disruption_pc
var events = null
var slot_types = null
var result = null
var i = 0
var j = 0
var s = 0
var n = 0
var instr = null
var op = null
var esc = null
var slot = 0
var nc = 0
var limit = 0
var first_ref = null
var last_ref = null
var label_map = null
var changed = false
var target = null
var tpos = 0
var shift = 0
if (instructions == null || length(instructions) == 0) {
return null
@@ -1336,72 +1329,10 @@ var streamline = function(ir, log) {
events = log.events
}
// Build first_ref / last_ref for liveness (needed for move)
first_ref = array(nr_slots, -1)
last_ref = array(nr_slots, -1)
n = length(instructions)
i = 0
while (i < n) {
instr = instructions[i]
if (is_array(instr)) {
j = 1
limit = length(instr) - 2
while (j < limit) {
if (is_number(instr[j]) && instr[j] >= 0 && instr[j] < nr_slots) {
if (first_ref[instr[j]] < 0) first_ref[instr[j]] = i
last_ref[instr[j]] = i
}
j = j + 1
}
}
i = i + 1
}
// Extend for backward jumps (loops)
label_map = {}
i = 0
while (i < n) {
instr = instructions[i]
if (is_text(instr) && !starts_with(instr, "_nop_")) {
label_map[instr] = i
}
i = i + 1
}
changed = true
while (changed) {
changed = false
i = 0
while (i < n) {
instr = instructions[i]
if (is_array(instr)) {
target = null
op = instr[0]
if (op == "jump") {
target = instr[1]
} else if (op == "jump_true" || op == "jump_false" || op == "jump_not_null") {
target = instr[2]
}
if (target != null && is_text(target)) {
tpos = label_map[target]
if (tpos != null && tpos < i) {
s = 0
while (s < nr_slots) {
if (first_ref[s] >= 0 && first_ref[s] < tpos && last_ref[s] >= tpos && last_ref[s] < i) {
last_ref[s] = i
changed = true
}
s = s + 1
}
}
}
}
i = i + 1
}
}
// Walk instructions, tracking types, inserting stone_text
slot_types = array(nr_slots, T_UNKNOWN)
result = []
n = length(instructions)
i = 0
while (i < n) {
instr = instructions[i]
@@ -1413,6 +1344,7 @@ var streamline = function(ir, log) {
if (is_number(slot) && slot_is(slot_types, slot, T_TEXT)) {
result[] = ["stone_text", slot]
nc = nc + 1
if (is_number(dpc) && i < dpc) shift = shift + 1
if (events != null) {
events[] = {
event: "insert", pass: "insert_stone_text",
@@ -1421,12 +1353,12 @@ var streamline = function(ir, log) {
}
}
} else if (op == "move") {
// Stone source before move only if source is provably text
// AND source slot is still live after this instruction
// Conservatively stone source before move if provably text
slot = instr[2]
if (is_number(slot) && slot_is(slot_types, slot, T_TEXT) && last_ref[slot] > i) {
if (is_number(slot) && slot_is(slot_types, slot, T_TEXT)) {
result[] = ["stone_text", slot]
nc = nc + 1
if (is_number(dpc) && i < dpc) shift = shift + 1
if (events != null) {
events[] = {
event: "insert", pass: "insert_stone_text",
@@ -1443,6 +1375,9 @@ var streamline = function(ir, log) {
if (nc > 0) {
func.instructions = result
if (is_number(dpc) && shift > 0) {
func.disruption_pc = dpc + shift
}
}
return null
}
@@ -2538,12 +2473,6 @@ var streamline = function(ir, log) {
})
if (verify_fn) verify_fn(func, "after " + name)
name = "insert_stone_text" + suffix
run_pass(func, name, function() {
return insert_stone_text(func, log)
})
if (verify_fn) verify_fn(func, "after " + name)
name = "eliminate_unreachable" + suffix
run_pass(func, name, function() {
return eliminate_unreachable(func)
@@ -2590,6 +2519,7 @@ var streamline = function(ir, log) {
// Process main function
if (ir.main != null) {
optimize_function(ir.main, log)
insert_stone_text(ir.main, log)
}
// Process all sub-functions (resolve closure types from parent first)
@@ -2599,6 +2529,7 @@ var streamline = function(ir, log) {
while (fi < length(ir.functions)) {
resolve_closure_types(ir.functions[fi], fi, ir)
optimize_function(ir.functions[fi], log)
insert_stone_text(ir.functions[fi], log)
fi = fi + 1
}
}

View File

@@ -103,6 +103,29 @@ run("string concatenation empty", function() {
if ("" + "world" != "world") fail("empty + string failed")
})
run("string concat does not mutate alias", function() {
var a = "hello world"
var b = a
a = a + " appended"
if (a != "hello world appended") fail("a wrong, got " + a)
if (b != "hello world") fail("b should still be hello world, got " + b)
})
run("string concat in loop preserves aliases", function() {
var a = "starting value"
var copies = [a]
var i = 0
while (i < 5) {
a = a + " more"
copies[] = a
i = i + 1
}
if (copies[0] != "starting value") fail("copies[0] wrong, got " + copies[0])
if (copies[1] != "starting value more") fail("copies[1] wrong, got " + copies[1])
if (copies[5] != "starting value more more more more more") fail("copies[5] wrong, got " + copies[5])
if (a != "starting value more more more more more") fail("a wrong, got " + a)
})
// ============================================================================
// TYPE MIXING SHOULD DISRUPT
// ============================================================================