EXAMPLE 04 • closures-hidden.ts

Closures & Hidden Compiler Frames

Unpack tuple-compressed closure state (_c[0..3]) across nested scopes while hiding internal compiler trampolines (isHidden: true).

Nested Scope Chain (Module -> Closure Function -> Inner Function -> Block)Hidden Stack Frame Ranges (isStackFrame: true, isHidden: true)Tuple-Packed Closure Capture Bindings (_c[0] -> endpointName, _c[3] -> usedTokens)Synthesized Boolean Guard Bindings (rem >= 0 -> allowed)
OPEN CHROME DEVTOOLS (F12) FIRST, THEN TRIGGER:
Ready. Click "Run & Pause in Debugger" with DevTools open.

How This Example Works

Compilers frequently transform closures by packing captured outer variables (endpointName, maxBurst, windowSeconds, usedTokens) into a flat heap array _c = ["/api/v2/inference", 50, 60, 12], and wrap calls in internal runtime trampolines like __withCompilerTrampoline(cb).

This example demonstrates two key features of the Scopes proposal:
1) Marking __withCompilerTrampoline's range with isHidden: true (and retaining the definition scope pointer on wrappers that contain authored code) so Chrome DevTools automatically strips internal compiler frames from the Call Stack.
2) Reconstructing the outer createEndpointHandler closure scope from _c[0..3] alongside the inner handleRequest function scope and if (allowed) block scope.

What to Try & Verify in DevTools

Call Stack

Try:Click "Run & Pause in Debugger" to pause inside handleRequest in closures-hidden.ts and inspect the Call Stack pane.

  • Clean Call Stack: handleRequest appears called directly by executeRateLimitCheck (line 45).
  • Hidden Runtime Wrappers: Both __withCompilerTrampoline and its anonymous callback (isHidden: true) are automatically omitted from the stack trace.
Scope View

Try:While paused at debugger; on line 19 of closures-hidden.ts, expand each section in the Scope sidebar.

  • Block Scope (if (allowed)): Shows burstUtilization: 40.
  • Local Scope (handleRequest): Shows clientIp: "192.0.2.44", requestWeight: 8, remainingTokens: 30, and synthesized allowed: true.
  • Closure Scope (createEndpointHandler): Unpacks tuple _c[0..3] into endpointName: "/api/v2/inference", maxBurst: 50, windowSeconds: 60, and usedTokens: 20. executeRateLimitCheck's variables (limiter, handler) must not show up: it is not a lexical parent of handleRequest.
  • Module Scope: Shows DEFAULT_REGION: "us-central1" (and RateLimiter as <unavailable>).
Autocomplete

Try:Open the Console (Esc) while paused and type prefixes from different scope levels: burst, rem, endp, usedT, and DEFAULT_.

  • Full Lexical Chain Aggregation: Autocomplete merges variables from the Block, Function, outer Closure, and Module scopes.
Conditional Breakpoints

Try:Right-click line 20 (return { region: DEFAULT_REGION, ... }), add a conditional breakpoint burstUtilization >= 40 && usedTokens === 20, resume (F8), and re-run.

  • Cross-Scope Condition Rewriting: DevTools rewrites burstUtilization to util and usedTokens to _c[3], pausing cleanly at the return statement.
Debug Evaluate

Try:Run the expressions below in the Console while paused at debugger;.

  • Multi-Scope Substitution: A single expression can seamlessly combine DEFAULT_REGION (Module), endpointName / usedTokens / maxBurst (Closure), remainingTokens / allowed (Function), and burstUtilization (Block).
Other things to try
  • Step Out (Shift+F11) of handleRequest: you should never land in __withCompilerTrampoline.
  • Add Watch expressions using closure variables (usedTokens, maxBurst), then select another frame.
  • Hover DEFAULT_REGION, endpointName and usedTokens in the editor with different frames selected.

Not sure if it's a DevTools bug? Tab 4. Decoded Scopes shows what the source map actually encodes.

Try in the Console While Paused

While paused, select a frame and evaluate these in the Console (Esc opens the drawer) using the authored names:

`${DEFAULT_REGION}:${endpointName} -> ${usedTokens}/${maxBurst} tokens (${burstUtilization}%)`
Expected Result: "us-central1:/api/v2/inference -> 20/50 tokens (40%)"
Combines variables from 4 different scope levels (Module, Closure, and Block) into a single template string.
usedTokens + remainingTokens === maxBurst
Expected Result: true
Substitutes _c[3] + rem === _c[1] (20 + 30 === 50).
allowed && windowSeconds === 60
Expected Result: true
Substitutes synthesized boolean rem >= 0 for allowed and tuple slot _c[2] for windowSeconds.