str stone; concat
This commit is contained in:
169
streamline.cm
169
streamline.cm
@@ -78,7 +78,8 @@ var streamline = function(ir, log) {
|
||||
jump: true, jump_true: true, jump_false: true, jump_not_null: true,
|
||||
return: true, disrupt: true,
|
||||
store_field: true, store_index: true, store_dynamic: true,
|
||||
push: true, setarg: true, invoke: true, tail_invoke: true
|
||||
push: true, setarg: true, invoke: true, tail_invoke: true,
|
||||
stone_text: true
|
||||
}
|
||||
|
||||
// --- Logging support ---
|
||||
@@ -1097,6 +1098,163 @@ var streamline = function(ir, log) {
|
||||
return null
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// Pass: insert_stone_text — freeze mutable text at escape points
|
||||
// Only inserts stone_text when the slot is provably T_TEXT.
|
||||
// Escape points: setfield, setindex, store_field, store_index,
|
||||
// store_dynamic, push, setarg, put (value leaving its slot).
|
||||
// move: stone source only if source is still live after the move.
|
||||
// =========================================================
|
||||
|
||||
// Map: escape opcode → index of the escaping slot in the instruction
|
||||
var escape_slot_index = {
|
||||
setfield: 3, setindex: 3,
|
||||
store_field: 3, store_index: 3, store_dynamic: 3,
|
||||
push: 2, setarg: 3, put: 1
|
||||
}
|
||||
|
||||
var insert_stone_text = function(func, log) {
|
||||
var instructions = func.instructions
|
||||
var nr_slots = func.nr_slots
|
||||
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
|
||||
|
||||
if (instructions == null || length(instructions) == 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (log != null && log.events != null) {
|
||||
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 = []
|
||||
i = 0
|
||||
while (i < n) {
|
||||
instr = instructions[i]
|
||||
if (is_array(instr)) {
|
||||
op = instr[0]
|
||||
esc = escape_slot_index[op]
|
||||
if (esc != null) {
|
||||
slot = instr[esc]
|
||||
if (is_number(slot) && slot_is(slot_types, slot, T_TEXT)) {
|
||||
result[] = ["stone_text", slot]
|
||||
nc = nc + 1
|
||||
if (events != null) {
|
||||
events[] = {
|
||||
event: "insert", pass: "insert_stone_text",
|
||||
rule: "escape_stone", at: i, slot: slot, op: op
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (op == "move") {
|
||||
// Stone source before move only if source is provably text
|
||||
// AND source slot is still live after this instruction
|
||||
slot = instr[2]
|
||||
if (is_number(slot) && slot_is(slot_types, slot, T_TEXT) && last_ref[slot] > i) {
|
||||
result[] = ["stone_text", slot]
|
||||
nc = nc + 1
|
||||
if (events != null) {
|
||||
events[] = {
|
||||
event: "insert", pass: "insert_stone_text",
|
||||
rule: "move_alias_stone", at: i, slot: slot
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
track_types(slot_types, instr)
|
||||
}
|
||||
result[] = instr
|
||||
i = i + 1
|
||||
}
|
||||
|
||||
if (nc > 0) {
|
||||
func.instructions = result
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// Pass: eliminate_unreachable — nop code after return/disrupt
|
||||
// =========================================================
|
||||
@@ -1299,7 +1457,8 @@ var streamline = function(ir, log) {
|
||||
frame: [1, 2], goframe: [1, 2],
|
||||
jump: [], disrupt: [],
|
||||
jump_true: [1], jump_false: [1], jump_not_null: [1],
|
||||
return: [1]
|
||||
return: [1],
|
||||
stone_text: [1]
|
||||
}
|
||||
|
||||
var get_slot_refs = function(instr) {
|
||||
@@ -2116,6 +2275,12 @@ 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)
|
||||
|
||||
Reference in New Issue
Block a user