import { joinType } from "./type-support.js";
export function handleSlotInstruction(ins, stack, locals, args, statics, aliases, pointerTargets, unk) {
const m = ins.opcode.mnemonic;
if (m === "INITSSLOT") {
if (ins.operand?.kind === "U8" && ins.operand.value > 0) {
ensure(statics, ins.operand.value - 1);
ensureAliases(aliases.statics, ins.operand.value - 1);
ensurePointerTargets(pointerTargets.statics, ins.operand.value - 1);
}
return true;
}
if (m === "INITSLOT") {
const operand = ins.operand;
if (operand?.kind === "Bytes" && operand.value.length >= 2) {
if (operand.value[0] > 0) {
ensure(locals, operand.value[0] - 1);
ensureAliases(aliases.locals, operand.value[0] - 1);
ensurePointerTargets(pointerTargets.locals, operand.value[0] - 1);
}
if (operand.value[1] > 0) {
ensure(args, operand.value[1] - 1);
ensureAliases(aliases.args, operand.value[1] - 1);
ensurePointerTargets(pointerTargets.args, operand.value[1] - 1);
}
}
return true;
}
const slotMatch = /^(LD|ST)(LOC|ARG|SFLD)(\d*)$/u.exec(m);
if (!slotMatch) return false;
const slots = slotMatch[2] === "LOC" ? locals : slotMatch[2] === "ARG" ? args : statics;
const aliasSlots = slotMatch[2] === "LOC" ? aliases.locals : slotMatch[2] === "ARG" ? aliases.args : aliases.statics;
const pointerTargetSlots =
slotMatch[2] === "LOC"
? pointerTargets.locals
: slotMatch[2] === "ARG"
? pointerTargets.args
: pointerTargets.statics;
const kind = slotMatch[2] === "LOC" ? "local" : slotMatch[2] === "ARG" ? "argument" : "static";
const index = slotMatch[3] !== "" ? Number(slotMatch[3]) : ins.operand?.kind === "U8" ? ins.operand.value : null;
if (slotMatch[1] === "LD") {
loadSlot(stack, slots, aliasSlots, pointerTargetSlots, kind, index, unk);
} else {
storeSlot(stack, slots, aliasSlots, pointerTargetSlots, kind, index, unk);
}
return true;
}
function loadSlot(stack, slots, aliasSlots, pointerTargetSlots, kind, index, unk) {
if (index === null) {
stack.push(unk());
return;
}
ensure(slots, index);
ensureAliases(aliasSlots, index);
ensurePointerTargets(pointerTargetSlots, index);
stack.push({
ty: slots[index],
lit: null,
ptr: pointerTargetSlots[index] ?? null,
origins: slotOrigins(aliasSlots, index, { kind, index }),
});
}
function storeSlot(stack, slots, aliasSlots, pointerTargetSlots, kind, index, unk) {
const value = stack.pop() ?? unk();
if (index === null) {
return;
}
ensure(slots, index);
ensureAliases(aliasSlots, index);
ensurePointerTargets(pointerTargetSlots, index);
slots[index] = joinType(slots[index], value.ty);
pointerTargetSlots[index] = value.ptr ?? null;
aliasSlots[index] = [];
const destination = { kind, index };
for (const origin of value.origins ?? []) {
if (!sameOrigin(origin, destination)) pushUniqueOrigin(aliasSlots[index], origin);
}
}
function ensure(slots, index) {
while (slots.length <= index) slots.push("unknown");
}
function ensureAliases(aliasSlots, index) {
while (aliasSlots.length <= index) aliasSlots.push([]);
}
function ensurePointerTargets(targetSlots, index) {
while (targetSlots.length <= index) targetSlots.push(null);
}
function sameOrigin(a, b) {
return a.kind === b.kind && a.index === b.index;
}
function pushUniqueOrigin(origins, origin) {
if (!origins.some((existing) => sameOrigin(existing, origin))) origins.push(origin);
}
function slotOrigins(aliasSlots, index, origin) {
const origins = [];
pushUniqueOrigin(origins, origin);
for (const alias of aliasSlots[index] ?? []) pushUniqueOrigin(origins, alias);
return origins;
}