@@ -25406,6 +25406,11 @@ log(mod.toString());`
2540625406 indent++;
2540725407 const declaredVars = /* @__PURE__ */ new Set();
2540825408 collectAssignTargets(node, declaredVars);
25409+ const referencedVars = /* @__PURE__ */ new Set();
25410+ collectReferencedVars(node, referencedVars);
25411+ for (const refVar of referencedVars) {
25412+ declaredVars.add(refVar);
25413+ }
2540925414 const varTypes = /* @__PURE__ */ new Map();
2541025415 collectAssignTypes(node, varTypes);
2541125416 for (const varName of declaredVars) {
@@ -25825,6 +25830,127 @@ log(mod.toString());`
2582525830 break;
2582625831 }
2582725832 }
25833+ function collectReferencedVars(node, refs) {
25834+ function scanExpr(expr) {
25835+ if (expr.kind === "var") {
25836+ refs.add(expr.name);
25837+ }
25838+ if (expr.kind === "binary") {
25839+ scanExpr(expr.left);
25840+ scanExpr(expr.right);
25841+ }
25842+ if (expr.kind === "unary") {
25843+ scanExpr(expr.operand);
25844+ }
25845+ if (expr.kind === "compare") {
25846+ scanExpr(expr.left);
25847+ scanExpr(expr.right);
25848+ }
25849+ if (expr.kind === "load") {
25850+ scanExpr(expr.address);
25851+ }
25852+ if (expr.kind === "call") {
25853+ for (const arg of expr.args) {
25854+ scanExpr(arg);
25855+ }
25856+ }
25857+ if (expr.kind === "call_indirect") {
25858+ scanExpr(expr.tableIndex);
25859+ for (const arg of expr.args) {
25860+ scanExpr(arg);
25861+ }
25862+ }
25863+ if (expr.kind === "select") {
25864+ scanExpr(expr.condition);
25865+ scanExpr(expr.trueVal);
25866+ scanExpr(expr.falseVal);
25867+ }
25868+ if (expr.kind === "convert") {
25869+ scanExpr(expr.operand);
25870+ }
25871+ if (expr.kind === "field_access") {
25872+ scanExpr(expr.base);
25873+ }
25874+ }
25875+ function scanStmt(stmt) {
25876+ if (stmt.kind === "assign") {
25877+ scanExpr(stmt.value);
25878+ }
25879+ if (stmt.kind === "store") {
25880+ scanExpr(stmt.address);
25881+ scanExpr(stmt.value);
25882+ }
25883+ if (stmt.kind === "call") {
25884+ for (const arg of stmt.args) {
25885+ scanExpr(arg);
25886+ }
25887+ }
25888+ if (stmt.kind === "call_indirect") {
25889+ scanExpr(stmt.tableIndex);
25890+ for (const arg of stmt.args) {
25891+ scanExpr(arg);
25892+ }
25893+ }
25894+ if (stmt.kind === "global_set") {
25895+ scanExpr(stmt.value);
25896+ }
25897+ if (stmt.kind === "return" && stmt.value) {
25898+ scanExpr(stmt.value);
25899+ }
25900+ }
25901+ switch (node.kind) {
25902+ case "sequence":
25903+ for (const child of node.children) {
25904+ collectReferencedVars(child, refs);
25905+ }
25906+ break;
25907+ case "block":
25908+ for (const stmt of node.body) {
25909+ scanStmt(stmt);
25910+ }
25911+ break;
25912+ case "if":
25913+ if (node.condition) {
25914+ scanExpr(node.condition);
25915+ }
25916+ collectReferencedVars(node.thenBody, refs);
25917+ if (node.elseBody) {
25918+ collectReferencedVars(node.elseBody, refs);
25919+ }
25920+ break;
25921+ case "while":
25922+ if (node.condition) {
25923+ scanExpr(node.condition);
25924+ }
25925+ collectReferencedVars(node.body, refs);
25926+ break;
25927+ case "do_while":
25928+ collectReferencedVars(node.body, refs);
25929+ scanExpr(node.condition);
25930+ break;
25931+ case "for":
25932+ scanStmt(node.init);
25933+ scanExpr(node.condition);
25934+ scanStmt(node.increment);
25935+ collectReferencedVars(node.body, refs);
25936+ break;
25937+ case "labeled_block":
25938+ collectReferencedVars(node.body, refs);
25939+ break;
25940+ case "switch":
25941+ scanExpr(node.selector);
25942+ for (const c of node.cases) {
25943+ collectReferencedVars(c.body, refs);
25944+ }
25945+ collectReferencedVars(node.defaultBody, refs);
25946+ break;
25947+ case "return":
25948+ if (node.value) {
25949+ scanExpr(node.value);
25950+ }
25951+ break;
25952+ }
25953+ }
2582825954 function alwaysTerminates(node) {
2582925955 switch (node.kind) {
2583025956 case "return":
@@ -26136,13 +26262,22 @@ log(mod.toString());`
2613626262 }
2613726263 }
2613826264 if (statement.value.kind === "binary" && statement.value.op === "-") {
26139- if (statement.value.left.kind === "global" && isStackPointerGlobal(statement.value.left.name) && statement.value.right.kind === "const") {
26140- const frameSize = Number(statement.value.right.value);
26141- return {
26142- stackPointerName: statement.value.left.name,
26143- frameVarName: statement.target,
26144- frameSize
26145- };
26265+ if (statement.value.left.kind === "global" && isStackPointerGlobal(statement.value.left.name)) {
26266+ const rightSide = statement.value.right;
26267+ if (rightSide.kind === "const") {
26268+ return {
26269+ stackPointerName: statement.value.left.name,
26270+ frameVarName: statement.target,
26271+ frameSize: Number(rightSide.value)
26272+ };
26273+ }
26274+ if (rightSide.kind === "string_literal") {
26275+ return {
26276+ stackPointerName: statement.value.left.name,
26277+ frameVarName: statement.target,
26278+ frameSize: rightSide.address
26279+ };
26280+ }
2614626281 }
2614726282 }
2614826283 }
@@ -26154,8 +26289,11 @@ log(mod.toString());`
2615426289 return false;
2615526290 }
2615626291 if (globalSet.value.kind === "binary" && globalSet.value.op === "+") {
26157- if (globalSet.value.left.kind === "var" && globalSet.value.left.name === frameInfo.frameVarName && globalSet.value.right.kind === "const" && Number(globalSet.value.right.value) === frameInfo.frameSize) {
26158- return true;
26292+ if (globalSet.value.left.kind === "var" && globalSet.value.left.name === frameInfo.frameVarName) {
26293+ const rightSide = globalSet.value.right;
26294+ if (rightSide.kind === "const" && Number(rightSide.value) === frameInfo.frameSize || rightSide.kind === "string_literal" && rightSide.address === frameInfo.frameSize) {
26295+ return true;
26296+ }
2615926297 }
2616026298 }
2616126299 if (globalSet.value.kind === "var") {
@@ -26164,10 +26302,10 @@ log(mod.toString());`
2616426302 return false;
2616526303 }
2616626304 function isStackFramePrologue(statement, frameInfo) {
26167- if (statement.kind === "assign" && statement.value.kind === "global" && statement.value.name === frameInfo.stackPointerName ) {
26305+ if (statement.kind === "assign" && statement.value.kind === "global" && isStackPointerGlobal( statement.value.name) ) {
2616826306 return true;
2616926307 }
26170- if (statement.kind === "assign" && statement.target === frameInfo.frameVarName && statement.value.kind === "binary" && statement.value.op === "-" ) {
26308+ if (statement.kind === "assign" && statement.target === frameInfo.frameVarName) {
2617126309 return true;
2617226310 }
2617326311 if (statement.kind === "global_set" && isStackPointerGlobal(statement.name)) {
@@ -26220,6 +26358,38 @@ log(mod.toString());`
2622026358 return node;
2622126359 }
2622226360 }
26361+ function removeBareSPReferences(node) {
26362+ switch (node.kind) {
26363+ case "block": {
26364+ const filtered = node.body.filter((statement) => {
26365+ if (statement.kind === "global_set" && isStackPointerGlobal(statement.name)) {
26366+ return false;
26367+ }
26368+ if (statement.kind === "assign" && statement.value.kind === "global" && isStackPointerGlobal(statement.value.name)) {
26369+ return false;
26370+ }
26371+ return true;
26372+ });
26373+ return { kind: "block", body: filtered };
26374+ }
26375+ case "sequence":
26376+ return { kind: "sequence", children: node.children.map((child) => removeBareSPReferences(child)) };
26377+ case "if":
26378+ return { kind: "if", condition: node.condition, thenBody: removeBareSPReferences(node.thenBody), elseBody: node.elseBody ? removeBareSPReferences(node.elseBody) : null };
26379+ case "while":
26380+ return { kind: "while", condition: node.condition, body: removeBareSPReferences(node.body) };
26381+ case "do_while":
26382+ return { kind: "do_while", body: removeBareSPReferences(node.body), condition: node.condition };
26383+ case "for":
26384+ return { kind: "for", init: node.init, condition: node.condition, increment: node.increment, body: removeBareSPReferences(node.body) };
26385+ case "labeled_block":
26386+ return { kind: "labeled_block", label: node.label, body: removeBareSPReferences(node.body) };
26387+ case "switch":
26388+ return { kind: "switch", selector: node.selector, cases: node.cases.map((c) => ({ values: c.values, body: removeBareSPReferences(c.body) })), defaultBody: removeBareSPReferences(node.defaultBody) };
26389+ default:
26390+ return node;
26391+ }
26392+ }
2622326393 function getFirstBlock(node) {
2622426394 if (node.kind === "block") {
2622526395 return node.body;
@@ -26236,7 +26406,7 @@ log(mod.toString());`
2623626406 }
2623726407 const frameInfo = extractFrameAlloc(firstBlock);
2623826408 if (!frameInfo) {
26239- return { node, frameVarName: null, frameSize: 0 };
26409+ return { node: removeBareSPReferences(node) , frameVarName: null, frameSize: 0 };
2624026410 }
2624126411 return {
2624226412 node: processNode(node, frameInfo),
@@ -30844,6 +31014,17 @@ ${funcEntry.body.length} bytes, ${totalLocals} locals`,
3084431014 }
3084531015 let selectedInstrIdx = -1;
3084631016 const instrRows = [];
31017+ const clearHighlight = () => {
31018+ if (selectedInstrIdx >= 0 && selectedInstrIdx < instrRows.length) {
31019+ instrRows[selectedInstrIdx].classList.remove("hex-instr-active");
31020+ }
31021+ for (const spans of byteSpans.values()) {
31022+ for (const span of spans) {
31023+ span.classList.remove("hex-byte-active");
31024+ }
31025+ }
31026+ selectedInstrIdx = -1;
31027+ };
3084731028 const highlightInstruction = (targetIdx) => {
3084831029 if (selectedInstrIdx >= 0 && selectedInstrIdx < instrRows.length) {
3084931030 instrRows[selectedInstrIdx].classList.remove("hex-instr-active");
@@ -30883,24 +31064,25 @@ ${funcEntry.body.length} bytes, ${totalLocals} locals`,
3088331064 immediates.textContent = instruction.immediates.values.join(", ");
3088431065 row.appendChild(immediates);
3088531066 }
30886- row.addEventListener("click ", () => highlightInstruction(instrIdx));
31067+ row.addEventListener("mouseenter ", () => highlightInstruction(instrIdx));
3088731068 instrList.appendChild(row);
3088831069 instrRows.push(row);
3088931070 }
30890- hexView.addEventListener("click", (event) => {
31071+ instrList.addEventListener("mouseleave", () => clearHighlight());
31072+ hexView.addEventListener("mouseover", (event) => {
3089131073 const target = event.target;
3089231074 if (target.dataset.offset !== void 0) {
30893- const clickedOffset = parseInt(target.dataset.offset, 10);
31075+ const hoveredOffset = parseInt(target.dataset.offset, 10);
3089431076 for (let instrIdx = 0; instrIdx < instructions.length; instrIdx++) {
3089531077 const instruction = instructions[instrIdx];
30896- if (clickedOffset >= instruction.offset && clickedOffset < instruction.offset + instruction.length) {
31078+ if (hoveredOffset >= instruction.offset && hoveredOffset < instruction.offset + instruction.length) {
3089731079 highlightInstruction(instrIdx);
30898- instrRows[instrIdx].scrollIntoView({ block: "nearest" });
3089931080 break;
3090031081 }
3090131082 }
3090231083 }
3090331084 });
31085+ hexView.addEventListener("mouseleave", () => clearHighlight());
3090431086 splitContainer.appendChild(instrList);
3090531087 splitContainer.appendChild(hexView);
3090631088 parent.appendChild(splitContainer);
0 commit comments