You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: doc/issues/stacktrace-at-point-of-execution.md
+58-47Lines changed: 58 additions & 47 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -31,88 +31,99 @@ When catching exceptions with `^:sci/error`, you only get the immediate error fr
31
31
32
32
This is because the stack is built during exception **propagation**. When you catch early with `^:sci/error`, propagation stops and you only get the immediate frame.
33
33
34
-
## Solution
34
+
## Why Analysis-Time Only Doesn't Work
35
35
36
-
Maintain a runtime call stack that gets pushed/popped as functions are entered/exited. The**infrastructure** (push/pop code) is generated at analysis time, but executes at runtime - exactly like the existing exception handling try/catch wrappers.
36
+
Each node gets its stack frame embedded at analysis time. However,**function bodies are analyzed once at definition time**, not re-analyzed at each call site.
37
37
38
-
## How Exception Stack Works (for reference)
38
+
Example:
39
+
```clojure
40
+
(defninner [] (current-stacktrace)) ;; analyzed here - don't know who will call inner
41
+
(defnouter [] (inner)) ;; creates call node, but inner's body already analyzed
42
+
(outer)
43
+
```
39
44
40
-
Currently, when an exception occurs:
41
-
1. Each function call is wrapped in try/catch (set up at analysis time)
42
-
2. When exception is thrown, each wrapper catches it, adds its frame via `rethrow-with-location-of-node`, and rethrows
43
-
3. Stack is built up as exception propagates
45
+
When `(current-stacktrace)` inside `inner` is analyzed, `outer` doesn't exist yet. The runtime call chain (`outer` -> `inner`) can only be known at runtime.
44
46
45
-
Example output from `bb`:
46
-
```
47
-
user/inner - /tmp/test.bb:1:16
48
-
user/inner - /tmp/test.bb:1:1
49
-
user/outer - /tmp/test.bb:2:16
50
-
user/outer - /tmp/test.bb:2:1
51
-
user - /tmp/test.bb:3:1
52
-
```
47
+
## Solution: Runtime Tracking with Minimal Overhead
53
48
54
-
## Proposed Approach
49
+
Each node already has its stack frame embedded at analysis time. We add push/pop at runtime, but with **near-zero overhead when not enabled**.
55
50
56
-
Similar to exception handling, but track the stack actively:
51
+
### How It Works
57
52
58
-
1.**At analysis time**: Modify `gen-return-call` to wrap function calls with push/pop logic
59
-
2.**At runtime**: Each call pushes its frame to a thread-local stack, executes, then pops
60
-
3.**`current-stacktrace`**: Simply reads the current stack
53
+
1.**`*call-stack*` dynamic var** (in utils.cljc): `nil` by default
54
+
2.**Push/pop functions** only do work when `*call-stack*` is non-nil:
0 commit comments