13
13
#if canImport(Darwin)
14
14
import Darwin
15
15
16
- class ScopeGuard {
17
- private var lock : os_unfair_lock
18
- init ( ) {
19
- self . lock = os_unfair_lock ( )
16
+ struct ScopeGuard {
17
+ private let lock : os_unfair_lock_t
18
+ init ( allocator: BumpPtrAllocator ) {
19
+ let storage = allocator. allocate ( os_unfair_lock. self, count: 1 ) . baseAddress!
20
+ storage. initialize ( to: os_unfair_lock ( ) )
21
+ self . lock = os_unfair_lock_t ( storage)
20
22
}
23
+
24
+ func deinitialize( ) { }
25
+
21
26
func withGuard< T> ( body: ( ) throws -> T ) rethrows -> T {
22
- os_unfair_lock_lock ( & lock)
23
- defer { os_unfair_lock_unlock ( & lock) }
27
+ os_unfair_lock_lock ( lock)
28
+ defer { os_unfair_lock_unlock ( lock) }
24
29
return try body ( )
25
30
}
26
31
}
27
32
28
33
#elseif canImport(Glibc)
29
34
import Glibc
30
35
31
- class ScopeGuard {
32
- var lock : pthread_mutex_t
33
- init ( ) {
34
- self . lock = pthread_mutex_t ( )
35
- pthread_mutex_init ( & self . lock, nil )
36
+ struct ScopeGuard {
37
+ private let lock : UnsafeMutablePointer < pthread_mutex_t >
38
+ init ( allocator: BumpPtrAllocator ) {
39
+ let storage = allocator. allocate ( pthread_mutex_t. self, count: 1 ) . baseAddress!
40
+ storage. initialize ( to: pthread_mutex_t ( ) )
41
+ pthread_mutex_init ( storage, nil )
42
+ self . lock = storage
36
43
}
37
- deinit {
38
- pthread_mutex_destroy ( & self . lock)
44
+ func deinitialize ( ) {
45
+ pthread_mutex_destroy ( self . lock)
39
46
}
40
47
func withGuard< T> ( body: ( ) throws -> T ) rethrows -> T {
41
- pthread_mutex_lock ( & lock)
42
- defer { pthread_mutex_unlock ( & lock) }
48
+ pthread_mutex_lock ( self . lock)
49
+ defer { pthread_mutex_unlock ( self . lock) }
43
50
return try body ( )
44
51
}
45
52
}
53
+
46
54
#else
47
55
// FIXME: Support other platforms.
48
56
49
57
/// Dummy mutex that doesn't actually guard at all.
50
58
class ScopeGuard {
51
59
init ( ) { }
60
+ func deinitialize( ) { }
52
61
func withGuard< T> ( body: ( ) throws -> T ) rethrows -> T {
53
62
return try body ( )
54
63
}
@@ -79,20 +88,28 @@ public class SyntaxArena {
79
88
80
89
@_spi ( RawSyntax)
81
90
public init ( parseTriviaFunction: @escaping ParseTriviaFunction ) {
82
- lock = ScopeGuard ( )
91
+ let allocator = BumpPtrAllocator ( )
92
+ self . lock = ScopeGuard ( allocator: allocator)
83
93
self . singleThreadMode = false
84
- allocator = BumpPtrAllocator ( )
94
+ self . allocator = allocator
85
95
children = [ ]
86
96
sourceBuffer = . init( start: nil , count: 0 )
87
97
hasParent = false
88
98
self . parseTriviaFunction = parseTriviaFunction
89
99
}
90
100
101
+ deinit {
102
+ // NOTE: We don't make `ScopeGuard` a class and `deinit` in it to
103
+ // deinitialize it because the actual lock value is in `allocator`, and we
104
+ // want to make sure to deinitialize the lock before destroying the allocator.
105
+ lock. deinitialize ( )
106
+ }
107
+
91
108
public convenience init ( ) {
92
109
self . init ( parseTriviaFunction: _defaultParseTriviaFunction ( _: _: ) )
93
110
}
94
111
95
- private func withGuard< R> ( body: ( ) throws -> R ) rethrows -> R {
112
+ private func withGuard< R> ( _ body: ( ) throws -> R ) rethrows -> R {
96
113
if self . singleThreadMode {
97
114
return try body ( )
98
115
} else {
@@ -114,7 +131,7 @@ public class SyntaxArena {
114
131
/// `contains(address _:)` is faster if the address is inside the memory
115
132
/// range this function returned.
116
133
public func internSourceBuffer( _ buffer: UnsafeBufferPointer < UInt8 > ) -> UnsafeBufferPointer < UInt8 > {
117
- let allocated = lock . withGuard {
134
+ let allocated = self . withGuard {
118
135
allocator. allocate ( UInt8 . self, count: buffer. count + /* for NULL */1 )
119
136
}
120
137
precondition ( sourceBuffer. baseAddress == nil , " SourceBuffer should only be set once. " )
@@ -189,7 +206,7 @@ public class SyntaxArena {
189
206
/// Copies a `RawSyntaxData` to the memory this arena manages, and retuns the
190
207
/// pointer to the destination.
191
208
func intern( _ value: RawSyntaxData ) -> UnsafePointer < RawSyntaxData > {
192
- let allocated = lock . withGuard {
209
+ let allocated = self . withGuard {
193
210
allocator. allocate ( RawSyntaxData . self, count: 1 ) . baseAddress!
194
211
}
195
212
allocated. initialize ( to: value)
@@ -236,7 +253,7 @@ public class SyntaxArena {
236
253
public func contains( text: SyntaxText ) -> Bool {
237
254
return ( text. isEmpty ||
238
255
sourceBufferContains ( text. baseAddress!) ||
239
- allocator. contains ( address: text. baseAddress!) )
256
+ self . withGuard ( { allocator. contains ( address: text. baseAddress!) } ) )
240
257
}
241
258
242
259
@_spi ( RawSyntax)
0 commit comments