Skip to content

Commit aa62488

Browse files
committed
Use a linked-list for the stack
Avoids any allocations that may occur with {Contiguous}Array during iteration.
1 parent 2982d82 commit aa62488

File tree

1 file changed

+21
-17
lines changed

1 file changed

+21
-17
lines changed

Sources/PrettyStackTrace/PrettyStackTrace.swift

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,49 +44,53 @@ var numRegisteredSignalInfo = 0
4444
/// a kill signal, this handler will dump all the entries in the tack trace and
4545
/// end the process.
4646
private class PrettyStackTraceManager {
47-
struct RawStackEntry {
47+
struct StackEntry {
48+
var prev: UnsafeMutablePointer<StackEntry>?
4849
let data: UnsafeMutablePointer<Int8>
4950
let count: Int
5051
}
5152

5253
/// Keeps a stack of serialized trace entries in reverse order.
5354
/// - Note: This keeps strings, because it's not safe to
5455
/// construct the strings in the signal handler directly.
55-
var stack = [RawStackEntry]()
56+
var stack: UnsafeMutablePointer<StackEntry>? = nil
5657

57-
private let stackDumpMsg: RawStackEntry
58+
private let stackDumpMsg: StackEntry
5859
init() {
5960
let msg = "Stack dump:\n"
60-
stackDumpMsg = RawStackEntry(data: strndup(msg, msg.count),
61-
count: msg.count)
61+
stackDumpMsg = StackEntry(prev: nil,
62+
data: strndup(msg, msg.count),
63+
count: msg.count)
6264
}
6365

6466
/// Pushes the description of a trace entry to the stack.
6567
func push(_ entry: TraceEntry) {
6668
let str = "\(entry.description)\n"
67-
let entry = RawStackEntry(data: strndup(str, str.count),
69+
let newEntry = StackEntry(prev: stack,
70+
data: strndup(str, str.count),
6871
count: str.count)
69-
stack.insert(entry, at: 0)
72+
let newStack = UnsafeMutablePointer<StackEntry>.allocate(capacity: 1)
73+
newStack.pointee = newEntry
74+
stack = newStack
7075
}
7176

7277
/// Pops the latest trace entry off the stack.
7378
func pop() {
74-
guard !stack.isEmpty else { return }
75-
stack.removeFirst()
79+
guard let stack = stack else { return }
80+
let prev = stack.pointee.prev
81+
stack.deallocate(capacity: 1)
82+
self.stack = prev
7683
}
7784

7885
/// Dumps the stack entries to standard error, starting with the most
7986
/// recent entry.
8087
func dump(_ signal: Int32) {
8188
write(STDERR_FILENO, stackDumpMsg.data, stackDumpMsg.count)
82-
let stackLimit = stack.count
83-
stack.withUnsafeBufferPointer { buffer in
84-
var i = 0
85-
while i < stackLimit {
86-
let bufItem = buffer[i]
87-
write(STDERR_FILENO, bufItem.data, bufItem.count)
88-
i += 1
89-
}
89+
var cur = stack
90+
while cur != nil {
91+
let entry = cur.unsafelyUnwrapped
92+
write(STDERR_FILENO, entry.pointee.data, entry.pointee.count)
93+
cur = entry.pointee.prev
9094
}
9195
}
9296
}

0 commit comments

Comments
 (0)