import {
isLoadLocal,
isLoadStatic,
slotIndex,
} from "./call-graph-slots.js";
import { valueToPointer } from "./call-graph-values.js";
export function relativePointerTarget(instruction) {
const target = instruction.offset + instruction.operand.value;
return target >= 0 ? target : null;
}
export function pointerTargetBeforeIndex(instructions, index, localValues, staticValues) {
let cursor = index - 1;
while (cursor >= 0) {
const previous = instructions[cursor];
if (!previous) {
return null;
}
if (previous.opcode.mnemonic === "NOP" || previous.opcode.mnemonic === "DUP") {
cursor -= 1;
continue;
}
if (previous.opcode.mnemonic === "PUSHA" && previous.operand?.kind === "I32") {
return relativePointerTarget(previous);
}
const local = isLoadLocal(previous.opcode.mnemonic)
? slotIndex(previous.opcode.mnemonic, previous)
: null;
if (local !== null) {
return valueToPointer(localValues.get(local) ?? null);
}
const staticSlot = isLoadStatic(previous.opcode.mnemonic)
? slotIndex(previous.opcode.mnemonic, previous)
: null;
if (staticSlot !== null) {
return valueToPointer(staticValues.get(staticSlot) ?? null);
}
return null;
}
return null;
}
export function pointerTargetFromSlotFlow(previous, localValues, staticValues) {
if (!previous) {
return null;
}
const local = isLoadLocal(previous.opcode.mnemonic)
? slotIndex(previous.opcode.mnemonic, previous)
: null;
if (local !== null) {
return valueToPointer(localValues.get(local) ?? null);
}
const staticSlot = isLoadStatic(previous.opcode.mnemonic)
? slotIndex(previous.opcode.mnemonic, previous)
: null;
if (staticSlot !== null) {
return valueToPointer(staticValues.get(staticSlot) ?? null);
}
return null;
}