respsect array and object length requests

This commit is contained in:
2026-02-14 15:42:19 -06:00
parent 356c51bde3
commit e75596ce30
18 changed files with 54250 additions and 62692 deletions

View File

@@ -123,45 +123,45 @@ var streamline = function(ir, log) {
var op = instr[0]
var src_type = null
if (op == "access") {
slot_types[text(instr[1])] = access_value_type(instr[2])
slot_types[instr[1]] = access_value_type(instr[2])
} else if (op == "int") {
slot_types[text(instr[1])] = T_INT
slot_types[instr[1]] = T_INT
} else if (op == "true" || op == "false") {
slot_types[text(instr[1])] = T_BOOL
slot_types[instr[1]] = T_BOOL
} else if (op == "null") {
slot_types[text(instr[1])] = T_NULL
slot_types[instr[1]] = T_NULL
} else if (op == "move") {
src_type = slot_types[text(instr[2])]
slot_types[text(instr[1])] = src_type != null ? src_type : T_UNKNOWN
src_type = slot_types[instr[2]]
slot_types[instr[1]] = src_type != null ? src_type : T_UNKNOWN
} else if (op == "concat") {
slot_types[text(instr[1])] = T_TEXT
slot_types[instr[1]] = T_TEXT
} else if (bool_result_ops[op] == true) {
slot_types[text(instr[1])] = T_BOOL
slot_types[instr[1]] = T_BOOL
} else if (op == "load_field" || op == "load_index" || op == "load_dynamic") {
slot_types[text(instr[1])] = T_UNKNOWN
slot_types[instr[1]] = T_UNKNOWN
} else if (op == "invoke" || op == "tail_invoke") {
slot_types[text(instr[2])] = T_UNKNOWN
slot_types[instr[2]] = T_UNKNOWN
} else if (op == "pop" || op == "get") {
slot_types[text(instr[1])] = T_UNKNOWN
slot_types[instr[1]] = T_UNKNOWN
} else if (op == "array") {
slot_types[text(instr[1])] = T_ARRAY
slot_types[instr[1]] = T_ARRAY
} else if (op == "record") {
slot_types[text(instr[1])] = T_RECORD
slot_types[instr[1]] = T_RECORD
} else if (op == "function") {
slot_types[text(instr[1])] = T_FUNCTION
slot_types[instr[1]] = T_FUNCTION
} else if (op == "length") {
slot_types[text(instr[1])] = T_INT
slot_types[instr[1]] = T_INT
} else if (op == "negate" || numeric_ops[op] == true) {
slot_types[text(instr[1])] = T_UNKNOWN
slot_types[instr[1]] = T_UNKNOWN
} else if (op == "bitnot" || op == "bitand" || op == "bitor" ||
op == "bitxor" || op == "shl" || op == "shr" || op == "ushr") {
slot_types[text(instr[1])] = T_INT
slot_types[instr[1]] = T_INT
}
return null
}
var slot_is = function(slot_types, slot, typ) {
var known = slot_types[text(slot)]
var known = slot_types[slot]
if (known == null) {
return false
}
@@ -175,24 +175,22 @@ var streamline = function(ir, log) {
}
var merge_backward = function(backward_types, slot, typ) {
var sk = null
var existing = null
if (!is_number(slot)) {
return null
}
sk = text(slot)
existing = backward_types[sk]
existing = backward_types[slot]
if (existing == null) {
backward_types[sk] = typ
backward_types[slot] = typ
} else if (existing != typ && existing != T_UNKNOWN) {
if ((existing == T_INT || existing == T_FLOAT) && typ == T_NUM) {
// Keep more specific
} else if (existing == T_NUM && (typ == T_INT || typ == T_FLOAT)) {
backward_types[sk] = typ
backward_types[slot] = typ
} else if ((existing == T_INT && typ == T_FLOAT) || (existing == T_FLOAT && typ == T_INT)) {
backward_types[sk] = T_NUM
backward_types[slot] = T_NUM
} else {
backward_types[sk] = T_UNKNOWN
backward_types[slot] = T_UNKNOWN
}
}
return null
@@ -201,8 +199,8 @@ var streamline = function(ir, log) {
var seed_params = function(slot_types, param_types, nr_args) {
var j = 1
while (j <= nr_args) {
if (param_types[text(j)] != null) {
slot_types[text(j)] = param_types[text(j)]
if (param_types[j] != null) {
slot_types[j] = param_types[j]
}
j = j + 1
}
@@ -210,10 +208,11 @@ var streamline = function(ir, log) {
}
var seed_writes = function(slot_types, write_types) {
var keys = array(write_types)
var k = 0
while (k < length(keys)) {
slot_types[keys[k]] = write_types[keys[k]]
while (k < length(write_types)) {
if (write_types[k] != null) {
slot_types[k] = write_types[k]
}
k = k + 1
}
return null
@@ -236,11 +235,11 @@ var streamline = function(ir, log) {
var bt = null
if (instructions == null || nr_args == 0) {
return {}
return array(func.nr_slots)
}
num_instr = length(instructions)
backward_types = {}
backward_types = array(func.nr_slots)
i = 0
while (i < num_instr) {
instr = instructions[i]
@@ -296,12 +295,12 @@ var streamline = function(ir, log) {
i = i + 1
}
param_types = {}
param_types = array(func.nr_slots)
j = 1
while (j <= nr_args) {
bt = backward_types[text(j)]
bt = backward_types[j]
if (bt != null && bt != T_UNKNOWN) {
param_types[text(j)] = bt
param_types[j] = bt
}
j = j + 1
}
@@ -319,22 +318,19 @@ var streamline = function(ir, log) {
var nr_args = func.nr_args != null ? func.nr_args : 0
var num_instr = 0
var write_types = null
var result = null
var keys = null
var i = 0
var k = 0
var instr = null
var op = null
var slot = 0
var typ = null
var wt = null
if (instructions == null) {
return {}
return array(func.nr_slots)
}
num_instr = length(instructions)
write_types = {}
write_types = array(func.nr_slots)
i = 0
while (i < num_instr) {
instr = instructions[i]
@@ -410,17 +406,14 @@ var streamline = function(ir, log) {
}
// Filter to only slots with known (non-unknown) types
result = {}
keys = array(write_types)
k = 0
while (k < length(keys)) {
wt = write_types[keys[k]]
if (wt != null && wt != T_UNKNOWN) {
result[keys[k]] = wt
while (k < length(write_types)) {
if (write_types[k] == T_UNKNOWN) {
write_types[k] = null
}
k = k + 1
}
return result
return write_types
}
// =========================================================
@@ -462,14 +455,14 @@ var streamline = function(ir, log) {
num_instr = length(instructions)
j = 1
while (j <= nr_args) {
if (param_types[text(j)] != null) {
if (param_types[j] != null) {
has_params = true
}
j = j + 1
}
has_writes = length(array(write_types)) > 0
has_writes = some(write_types, function(x) { return x != null })
slot_types = {}
slot_types = array(func.nr_slots)
if (has_params) {
seed_params(slot_types, param_types, nr_args)
}
@@ -482,7 +475,7 @@ var streamline = function(ir, log) {
instr = instructions[i]
if (is_text(instr)) {
slot_types = {}
slot_types = array(func.nr_slots)
if (has_params) {
seed_params(slot_types, param_types, nr_args)
}
@@ -525,14 +518,14 @@ var streamline = function(ir, log) {
at: i,
before: [instr, next],
after: [instructions[i], instructions[i + 1]],
why: {slot: src, known_type: slot_types[text(src)], checked_type: checked_type}
why: {slot: src, known_type: slot_types[src], checked_type: checked_type}
}
}
slot_types[text(dest)] = T_BOOL
slot_types[dest] = T_BOOL
i = i + 2
continue
}
src_known = slot_types[text(src)]
src_known = slot_types[src]
if (src_known != null && src_known != T_UNKNOWN && src_known != checked_type) {
if (checked_type == T_NUM && (src_known == T_INT || src_known == T_FLOAT)) {
nc = nc + 1
@@ -550,7 +543,7 @@ var streamline = function(ir, log) {
why: {slot: src, known_type: src_known, checked_type: checked_type}
}
}
slot_types[text(dest)] = T_BOOL
slot_types[dest] = T_BOOL
i = i + 2
continue
}
@@ -569,12 +562,12 @@ var streamline = function(ir, log) {
why: {slot: src, known_type: src_known, checked_type: checked_type}
}
}
slot_types[text(dest)] = T_UNKNOWN
slot_types[dest] = T_UNKNOWN
i = i + 2
continue
}
slot_types[text(dest)] = T_BOOL
slot_types[text(src)] = checked_type
slot_types[dest] = T_BOOL
slot_types[src] = checked_type
i = i + 2
continue
}
@@ -594,14 +587,14 @@ var streamline = function(ir, log) {
at: i,
before: [instr, next],
after: [instructions[i], instructions[i + 1]],
why: {slot: src, known_type: slot_types[text(src)], checked_type: checked_type}
why: {slot: src, known_type: slot_types[src], checked_type: checked_type}
}
}
slot_types[text(dest)] = T_BOOL
slot_types[dest] = T_BOOL
i = i + 2
continue
}
src_known = slot_types[text(src)]
src_known = slot_types[src]
if (src_known != null && src_known != T_UNKNOWN && src_known != checked_type) {
if (checked_type == T_NUM && (src_known == T_INT || src_known == T_FLOAT)) {
nc = nc + 1
@@ -619,7 +612,7 @@ var streamline = function(ir, log) {
why: {slot: src, known_type: src_known, checked_type: checked_type}
}
}
slot_types[text(dest)] = T_BOOL
slot_types[dest] = T_BOOL
i = i + 2
continue
}
@@ -638,17 +631,17 @@ var streamline = function(ir, log) {
why: {slot: src, known_type: src_known, checked_type: checked_type}
}
}
slot_types[text(dest)] = T_BOOL
slot_types[dest] = T_BOOL
i = i + 2
continue
}
slot_types[text(dest)] = T_BOOL
slot_types[dest] = T_BOOL
i = i + 2
continue
}
}
slot_types[text(dest)] = T_BOOL
slot_types[dest] = T_BOOL
i = i + 1
continue
}
@@ -664,7 +657,7 @@ var streamline = function(ir, log) {
pass: "eliminate_type_checks",
rule: "dynamic_to_field",
at: i, before: old_op, after: instr[0],
why: {slot: instr[3], known_type: slot_types[text(instr[3])]}
why: {slot: instr[3], known_type: slot_types[instr[3]]}
}
}
} else if (slot_is(slot_types, instr[3], T_INT)) {
@@ -675,11 +668,11 @@ var streamline = function(ir, log) {
pass: "eliminate_type_checks",
rule: "dynamic_to_index",
at: i, before: old_op, after: instr[0],
why: {slot: instr[3], known_type: slot_types[text(instr[3])]}
why: {slot: instr[3], known_type: slot_types[instr[3]]}
}
}
}
slot_types[text(instr[1])] = T_UNKNOWN
slot_types[instr[1]] = T_UNKNOWN
i = i + 1
continue
}
@@ -693,7 +686,7 @@ var streamline = function(ir, log) {
pass: "eliminate_type_checks",
rule: "dynamic_to_field",
at: i, before: old_op, after: instr[0],
why: {slot: instr[3], known_type: slot_types[text(instr[3])]}
why: {slot: instr[3], known_type: slot_types[instr[3]]}
}
}
} else if (slot_is(slot_types, instr[3], T_INT)) {
@@ -704,7 +697,7 @@ var streamline = function(ir, log) {
pass: "eliminate_type_checks",
rule: "dynamic_to_index",
at: i, before: old_op, after: instr[0],
why: {slot: instr[3], known_type: slot_types[text(instr[3])]}
why: {slot: instr[3], known_type: slot_types[instr[3]]}
}
}
}
@@ -745,14 +738,14 @@ var streamline = function(ir, log) {
}
num_instr = length(instructions)
slot_values = {}
slot_values = array(func.nr_slots)
i = 0
while (i < num_instr) {
instr = instructions[i]
if (is_text(instr)) {
slot_values = {}
slot_values = array(func.nr_slots)
i = i + 1
continue
}
@@ -766,19 +759,19 @@ var streamline = function(ir, log) {
// Track known constant values
if (op == "int") {
slot_values[text(instr[1])] = instr[2]
slot_values[instr[1]] = instr[2]
} else if (op == "access" && is_number(instr[2])) {
slot_values[text(instr[1])] = instr[2]
slot_values[instr[1]] = instr[2]
} else if (op == "true") {
slot_values[text(instr[1])] = true
slot_values[instr[1]] = true
} else if (op == "false") {
slot_values[text(instr[1])] = false
slot_values[instr[1]] = false
} else if (op == "move") {
sv = slot_values[text(instr[2])]
sv = slot_values[instr[2]]
if (sv != null) {
slot_values[text(instr[1])] = sv
slot_values[instr[1]] = sv
} else {
slot_values[text(instr[1])] = null
slot_values[instr[1]] = null
}
}
@@ -797,7 +790,7 @@ var streamline = function(ir, log) {
why: {op: op, slot: instr[2]}
}
}
slot_values[text(instr[1])] = true
slot_values[instr[1]] = true
i = i + 1
continue
}
@@ -814,7 +807,7 @@ var streamline = function(ir, log) {
why: {op: op, slot: instr[2]}
}
}
slot_values[text(instr[1])] = false
slot_values[instr[1]] = false
i = i + 1
continue
}
@@ -822,7 +815,7 @@ var streamline = function(ir, log) {
// Clear value tracking for dest-producing ops (not reads-only)
if (op == "invoke" || op == "tail_invoke") {
slot_values[text(instr[2])] = null
slot_values[instr[2]] = null
} else if (op != "int" && op != "access" && op != "true" &&
op != "false" && op != "move" && op != "null" &&
op != "jump" && op != "jump_true" && op != "jump_false" &&
@@ -830,7 +823,7 @@ var streamline = function(ir, log) {
op != "store_field" && op != "store_index" &&
op != "store_dynamic" && op != "push" && op != "setarg") {
if (is_number(instr[1])) {
slot_values[text(instr[1])] = null
slot_values[instr[1]] = null
}
}