@@ -12,35 +12,8 @@ import Foundation
12
12
import TSCBasic
13
13
14
14
extension Bitcode {
15
- /// Parse a bitstream from data.
16
- @available ( * , deprecated, message: " Use Bitcode.init(bytes:) instead " )
17
- public init ( data: Data ) throws {
18
- precondition ( data. count > 4 )
19
- try self . init ( bytes: ByteString ( data) )
20
- }
21
-
22
- public init ( bytes: ByteString ) throws {
23
- precondition ( bytes. count > 4 )
24
- var reader = BitstreamReader ( buffer: bytes)
25
- let signature = try reader. readSignature ( )
26
- var visitor = CollectingVisitor ( )
27
- try reader. readBlock ( id: BitstreamReader . fakeTopLevelBlockID,
28
- abbrevWidth: 2 ,
29
- abbrevInfo: [ ] ,
30
- visitor: & visitor)
31
- self . init ( signature: signature,
32
- elements: visitor. finalizeTopLevelElements ( ) ,
33
- blockInfo: reader. blockInfo)
34
- }
35
-
36
15
/// Traverse a bitstream using the specified `visitor`, which will receive
37
16
/// callbacks when blocks and records are encountered.
38
- @available ( * , deprecated, message: " Use Bitcode.read(bytes:using:) instead " )
39
- public static func read< Visitor: BitstreamVisitor > ( stream data: Data , using visitor: inout Visitor ) throws {
40
- precondition ( data. count > 4 )
41
- try Self . read ( bytes: ByteString ( data) , using: & visitor)
42
- }
43
-
44
17
public static func read< Visitor: BitstreamVisitor > ( bytes: ByteString , using visitor: inout Visitor ) throws {
45
18
precondition ( bytes. count > 4 )
46
19
var reader = BitstreamReader ( buffer: bytes)
@@ -52,36 +25,6 @@ extension Bitcode {
52
25
}
53
26
}
54
27
55
- /// A basic visitor that collects all the blocks and records in a stream.
56
- private struct CollectingVisitor : BitstreamVisitor {
57
- var stack : [ ( UInt64 , [ BitcodeElement ] ) ] = [ ( BitstreamReader . fakeTopLevelBlockID, [ ] ) ]
58
-
59
- func validate( signature: Bitcode . Signature ) throws { }
60
-
61
- mutating func shouldEnterBlock( id: UInt64 ) throws -> Bool {
62
- stack. append ( ( id, [ ] ) )
63
- return true
64
- }
65
-
66
- mutating func didExitBlock( ) throws {
67
- guard let ( id, elements) = stack. popLast ( ) else {
68
- fatalError ( " Unbalanced calls to shouldEnterBlock/didExitBlock " )
69
- }
70
-
71
- let block = BitcodeElement . Block ( id: id, elements: elements)
72
- stack [ stack. endIndex- 1 ] . 1 . append ( . block( block) )
73
- }
74
-
75
- mutating func visit( record: BitcodeElement . Record ) throws {
76
- stack [ stack. endIndex- 1 ] . 1 . append ( . record( record) )
77
- }
78
-
79
- func finalizeTopLevelElements( ) -> [ BitcodeElement ] {
80
- assert ( stack. count == 1 )
81
- return stack [ 0 ] . 1
82
- }
83
- }
84
-
85
28
private extension Bits . Cursor {
86
29
enum BitcodeError : Swift . Error {
87
30
case vbrOverflow
@@ -161,6 +104,7 @@ private struct BitstreamReader {
161
104
guard numOps > 0 else { throw Error . invalidAbbrev }
162
105
163
106
var operands : [ Bitstream . Abbreviation . Operand ] = [ ]
107
+ operands. reserveCapacity ( numOps)
164
108
for i in 0 ..< numOps {
165
109
operands. append ( try readAbbrevOp ( ) )
166
110
@@ -204,15 +148,29 @@ private struct BitstreamReader {
204
148
}
205
149
}
206
150
207
- mutating func readAbbreviatedRecord( _ abbrev: Bitstream . Abbreviation ) throws -> BitcodeElement . Record {
151
+ /// Computes a non-owning view of a `BitcodeElement.Record` that is valid for
152
+ /// the lifetime of the call to `body`.
153
+ ///
154
+ /// - Warning: If this function throws, the `body` block will not be called.
155
+ mutating func withAbbreviatedRecord(
156
+ _ abbrev: Bitstream . Abbreviation ,
157
+ body: ( BitcodeElement . Record ) throws -> Void
158
+ ) throws {
208
159
let code = try readSingleAbbreviatedRecordOperand ( abbrev. operands. first!)
209
160
210
161
let lastOperand = abbrev. operands. last!
211
162
let lastRegularOperandIndex : Int = abbrev. operands. endIndex - ( lastOperand. isPayload ? 1 : 0 )
212
163
213
- var fields = [ UInt64] ( )
214
- for op in abbrev. operands [ 1 ..< lastRegularOperandIndex] {
215
- fields. append ( try readSingleAbbreviatedRecordOperand ( op) )
164
+ // Safety: `lastRegularOperandIndex` is always at least 1. An abbreviation
165
+ // is required by the format to contain at least one operand. If that last
166
+ // operand is a payload (and thus we subtracted one from the total number of
167
+ // operands above), then that must mean it is either a trailing array
168
+ // or trailing blob. Both of these are preceded by their length field.
169
+ let fields = UnsafeMutableBufferPointer< UInt64> . allocate( capacity: lastRegularOperandIndex - 1 )
170
+ defer { fields. deallocate ( ) }
171
+
172
+ for (idx, op) in abbrev. operands [ 1 ..< lastRegularOperandIndex] . enumerated ( ) {
173
+ fields [ idx] = try readSingleAbbreviatedRecordOperand ( op)
216
174
}
217
175
218
176
let payload : BitcodeElement . Record . Payload
@@ -222,26 +180,42 @@ private struct BitstreamReader {
222
180
switch lastOperand {
223
181
case . array( let element) :
224
182
let length = try cursor. readVBR ( 6 )
225
- var elements = [ UInt64] ( )
226
- for _ in 0 ..< length {
227
- elements. append ( try readSingleAbbreviatedRecordOperand ( element) )
228
- }
229
183
if case . char6 = element {
230
- payload = . char6String( String ( String . UnicodeScalarView ( elements. map { UnicodeScalar ( UInt8 ( $0) ) } ) ) )
184
+ // FIXME: Once the minimum deployment target bumps to macOS 11, use
185
+ // the more ergonomic stdlib API everywhere.
186
+ if #available( macOS 11 . 0 , * ) {
187
+ payload = try . char6String( String ( unsafeUninitializedCapacity: Int ( length) ) { buffer in
188
+ for i in 0 ..< Int ( length) {
189
+ buffer [ i] = try UInt8 ( readSingleAbbreviatedRecordOperand ( element) )
190
+ }
191
+ return Int ( length)
192
+ } )
193
+ } else {
194
+ let buffer = UnsafeMutableBufferPointer< UInt8> . allocate( capacity: Int ( length) )
195
+ defer { buffer. deallocate ( ) }
196
+ for i in 0 ..< Int ( length) {
197
+ buffer [ i] = try UInt8 ( readSingleAbbreviatedRecordOperand ( element) )
198
+ }
199
+ payload = . char6String( String ( decoding: buffer, as: UTF8 . self) )
200
+ }
231
201
} else {
202
+ var elements = [ UInt64] ( )
203
+ for _ in 0 ..< length {
204
+ elements. append ( try readSingleAbbreviatedRecordOperand ( element) )
205
+ }
232
206
payload = . array( elements)
233
207
}
234
208
case . blob:
235
209
let length = Int ( try cursor. readVBR ( 6 ) )
236
210
try cursor. advance ( toBitAlignment: 32 )
237
- payload = . blob( try Data ( cursor. read ( bytes: length) ) )
211
+ payload = . blob( try cursor. read ( bytes: length) )
238
212
try cursor. advance ( toBitAlignment: 32 )
239
213
default :
240
214
fatalError ( )
241
215
}
242
216
}
243
217
244
- return . init( id: code, fields: fields, payload: payload)
218
+ return try body ( . init( id: code, fields: UnsafeBufferPointer ( fields) , payload: payload) )
245
219
}
246
220
247
221
mutating func readBlockInfoBlock( abbrevWidth: Int ) throws {
@@ -341,17 +315,20 @@ private struct BitstreamReader {
341
315
case Bitstream . AbbreviationID. unabbreviatedRecord. rawValue:
342
316
let code = try cursor. readVBR ( 6 )
343
317
let numOps = try cursor. readVBR ( 6 )
344
- var operands = [ UInt64] ( )
345
- for _ in 0 ..< numOps {
346
- operands. append ( try cursor. readVBR ( 6 ) )
318
+ let operands = UnsafeMutableBufferPointer< UInt64> . allocate( capacity: Int ( numOps) )
319
+ defer { operands. deallocate ( ) }
320
+ for i in 0 ..< Int ( numOps) {
321
+ operands [ i] = try cursor. readVBR ( 6 )
347
322
}
348
- try visitor. visit ( record: . init( id: code, fields: operands, payload: . none) )
323
+ try visitor. visit ( record: . init( id: code, fields: UnsafeBufferPointer ( operands) , payload: . none) )
349
324
350
325
case let abbrevID:
351
326
guard Int ( abbrevID) - 4 < abbrevInfo. count else {
352
327
throw Error . noSuchAbbrev ( blockID: id, abbrevID: Int ( abbrevID) )
353
328
}
354
- try visitor. visit ( record: try readAbbreviatedRecord ( abbrevInfo [ Int ( abbrevID) - 4 ] ) )
329
+ try withAbbreviatedRecord ( abbrevInfo [ Int ( abbrevID) - 4 ] ) { record in
330
+ try visitor. visit ( record: record)
331
+ }
355
332
}
356
333
}
357
334
0 commit comments