Skip to content

Commit 81edf17

Browse files
committed
Show always-visible call stack and fix duplicate frame bug
- Call stack bar now always visible with "(top level)" empty state so users know the feature exists - Fix duplicate call stack frames: compiler emits invoke context on both the caller JUMP and callee entry JUMPDEST, so skip push if top frame already matches the same call - Applied fix to both TraceDrawer and programs-react utility
1 parent 9ac5703 commit 81edf17

3 files changed

Lines changed: 53 additions & 16 deletions

File tree

packages/programs-react/src/utils/mockTrace.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -263,11 +263,21 @@ export function buildCallStack(
263263
}
264264

265265
if (callInfo.kind === "invoke") {
266-
stack.push({
267-
identifier: callInfo.identifier,
268-
stepIndex: i,
269-
callType: callInfo.callType,
270-
});
266+
// The compiler emits invoke on both the caller JUMP and
267+
// callee entry JUMPDEST. Skip if the top frame already
268+
// matches this call.
269+
const top = stack[stack.length - 1];
270+
if (
271+
!top ||
272+
top.identifier !== callInfo.identifier ||
273+
top.callType !== callInfo.callType
274+
) {
275+
stack.push({
276+
identifier: callInfo.identifier,
277+
stepIndex: i,
278+
callType: callInfo.callType,
279+
});
280+
}
271281
} else if (callInfo.kind === "return" || callInfo.kind === "revert") {
272282
// Pop the matching frame
273283
if (stack.length > 0) {

packages/web/src/theme/ProgramExample/TraceDrawer.css

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,20 @@
140140
flex-shrink: 0;
141141
}
142142

143+
.call-stack-label {
144+
font-size: 11px;
145+
font-weight: 600;
146+
text-transform: uppercase;
147+
letter-spacing: 0.05em;
148+
color: var(--ifm-color-content-secondary);
149+
margin-right: 4px;
150+
}
151+
152+
.call-stack-toplevel {
153+
color: var(--ifm-color-content-secondary);
154+
font-style: italic;
155+
}
156+
143157
.call-stack-sep {
144158
color: var(--ifm-color-content-secondary);
145159
padding: 0 2px;

packages/web/src/theme/ProgramExample/TraceDrawer.tsx

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,21 @@ function TraceDrawerContent(): JSX.Element {
116116
if (!info) continue;
117117

118118
if (info.kind === "invoke") {
119-
frames.push({
120-
identifier: info.identifier,
121-
stepIndex: i,
122-
callType: info.callType,
123-
});
119+
// The compiler emits invoke on both the caller
120+
// JUMP and callee entry JUMPDEST. Skip if the
121+
// top frame already matches this call.
122+
const top = frames[frames.length - 1];
123+
if (
124+
!top ||
125+
top.identifier !== info.identifier ||
126+
top.callType !== info.callType
127+
) {
128+
frames.push({
129+
identifier: info.identifier,
130+
stepIndex: i,
131+
callType: info.callType,
132+
});
133+
}
124134
} else if (info.kind === "return" || info.kind === "revert") {
125135
if (frames.length > 0) {
126136
frames.pop();
@@ -344,9 +354,12 @@ function TraceDrawerContent(): JSX.Element {
344354
</button>
345355
</div>
346356

347-
{callStack.length > 0 && (
348-
<div className="call-stack-bar">
349-
{callStack.map((frame, i) => (
357+
<div className="call-stack-bar">
358+
<span className="call-stack-label">Call Stack:</span>
359+
{callStack.length === 0 ? (
360+
<span className="call-stack-toplevel">(top level)</span>
361+
) : (
362+
callStack.map((frame, i) => (
350363
<React.Fragment key={frame.stepIndex}>
351364
{i > 0 && (
352365
<span className="call-stack-sep">&#x203A;</span>
@@ -359,9 +372,9 @@ function TraceDrawerContent(): JSX.Element {
359372
{frame.identifier || "(anonymous)"}
360373
</button>
361374
</React.Fragment>
362-
))}
363-
</div>
364-
)}
375+
))
376+
)}
377+
</div>
365378

366379
{currentCallInfo && (
367380
<div

0 commit comments

Comments
 (0)