Skip to content

Commit 4d7d64e

Browse files
committed
Improve BumpPointerAllocator performance
Eliminate unnecessary slab array access when allocating from the current slab. Also factored out "allocate from the current slab" to a function.
1 parent 9c8ee38 commit 4d7d64e

File tree

1 file changed

+37
-22
lines changed

1 file changed

+37
-22
lines changed

Sources/SwiftSyntax/BumpPtrAllocator.swift

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,27 @@ public class BumpPtrAllocator {
2020
static private var SLAB_ALIGNMENT: Int = 8
2121

2222
private var slabs: [Slab]
23-
/// Points to the next unused address in `slabs.last`.
24-
private var currentPtr: UnsafeMutableRawPointer?
25-
/// Points to the end address of `slabs.last`. If `slabs` is not empty, this
26-
/// is equivalent to `slabs.last!.baseAddress! + slabs.last!.count`
27-
private var endPtr: UnsafeMutableRawPointer?
23+
/// Pair of pointers in the current slab.
24+
/// - pointer: Points to the next unused address in `slabs.last`.
25+
/// - end: Points to the end address of `slabs.last`. This is equivalent to
26+
/// `slabs.last!.baseAddress! + slabs.last!.count`
27+
/// 'nil' if `slabs` is empty.
28+
private var current: (pointer: UnsafeMutableRawPointer,
29+
end: UnsafeMutableRawPointer)?
2830
private var customSizeSlabs: [Slab]
2931
private var _totalBytesAllocated: Int
3032

3133
public init() {
3234
slabs = []
33-
currentPtr = nil
34-
endPtr = nil
35+
current = nil
3536
customSizeSlabs = []
3637
_totalBytesAllocated = 0
3738
}
3839

3940
deinit {
4041
/// Deallocate all memory.
4142
_totalBytesAllocated = 0
42-
currentPtr = nil
43-
endPtr = nil
43+
current = nil
4444
while let slab = slabs.popLast() {
4545
slab.deallocate()
4646
}
@@ -59,9 +59,28 @@ public class BumpPtrAllocator {
5959
let newSlabSize = Self.slabSize(at: slabs.count)
6060
let newSlab = Slab.allocate(
6161
byteCount: newSlabSize, alignment: Self.SLAB_ALIGNMENT)
62+
let pointer = newSlab.baseAddress!
63+
current = (pointer, pointer.advanced(by: newSlabSize))
6264
slabs.append(newSlab)
63-
currentPtr = newSlab.baseAddress!
64-
endPtr = currentPtr!.advanced(by: newSlabSize)
65+
}
66+
67+
/// Allocate 'byteCount' of memory from the current slab if available.
68+
private func allocateFromCurrentSlab(
69+
_ byteCount: Int,
70+
_ alignment: Int
71+
) -> UnsafeMutableRawBufferPointer? {
72+
guard let current = self.current else {
73+
return nil
74+
}
75+
76+
let aligned = current.pointer.alignedUp(toMultipleOf: alignment)
77+
guard byteCount <= aligned.distance(to: current.end) else {
78+
return nil
79+
}
80+
81+
// Bump the pointer, and return the allocated buffer.
82+
self.current = (aligned + byteCount, current.end)
83+
return .init(start: aligned, count: byteCount)
6584
}
6685

6786
/// Allocate 'byteCount' of memory.
@@ -70,7 +89,7 @@ public class BumpPtrAllocator {
7089
/// Clients should never call `deallocate()` on the returned buffer.
7190
public func allocate(byteCount: Int, alignment: Int) -> UnsafeMutableRawBufferPointer {
7291

73-
precondition(alignment <= Self.SLAB_ALIGNMENT)
92+
assert(alignment <= Self.SLAB_ALIGNMENT)
7493
guard byteCount > 0 else {
7594
return .init(start: nil, count: 0)
7695
}
@@ -79,12 +98,8 @@ public class BumpPtrAllocator {
7998
_totalBytesAllocated += byteCount
8099

81100
// Check if the current slab has enough space.
82-
if !slabs.isEmpty {
83-
let aligned = currentPtr!.alignedUp(toMultipleOf: alignment)
84-
if aligned + byteCount <= endPtr! {
85-
currentPtr = aligned + byteCount
86-
return .init(start: aligned, count: byteCount)
87-
}
101+
if let allocated = allocateFromCurrentSlab(byteCount, alignment) {
102+
return allocated
88103
}
89104

90105
// If the size is too big, allocate a dedicated slab for it.
@@ -97,10 +112,10 @@ public class BumpPtrAllocator {
97112

98113
// Otherwise, start a new slab and try again.
99114
startNewSlab()
100-
let aligned = currentPtr!.alignedUp(toMultipleOf: alignment)
101-
assert(aligned + byteCount <= endPtr!, "Unable to allocate memory!")
102-
currentPtr = aligned + byteCount
103-
return .init(start: aligned, count: byteCount)
115+
if let allocated = allocateFromCurrentSlab(byteCount, alignment) {
116+
return allocated
117+
}
118+
fatalError("Unable to allocate memory!")
104119
}
105120

106121
/// Allocate a chunk of bound memory of `MemoryLayout<T>.stride * count'.

0 commit comments

Comments
 (0)