1010//
1111//===----------------------------------------------------------------------===//
1212import Foundation
13+ import TSCUtility
1314
1415@_spi ( Testing) public struct SourceFileDependencyGraph {
1516 public static let sourceFileProvidesInterfaceSequenceNumber : Int = 0
@@ -91,8 +92,6 @@ extension SourceFileDependencyGraph {
9192}
9293
9394extension SourceFileDependencyGraph {
94- private static let recordBlockId = 8
95-
9695 private enum RecordKind : UInt64 {
9796 case metadata = 1
9897 case sourceFileDepGraphNode
@@ -116,8 +115,9 @@ extension SourceFileDependencyGraph {
116115 case bogusNameOrContext
117116 case unknownKind
118117 }
119-
120- public static func read( from swiftDeps: ModuleDependencyGraph . SwiftDeps
118+
119+ // FIXME: This should accept a FileSystem parameter.
120+ static func read( from swiftDeps: ModuleDependencyGraph . SwiftDeps
121121 ) throws -> Self {
122122 guard let path = swiftDeps. file. absolutePath
123123 else {
@@ -132,93 +132,133 @@ extension SourceFileDependencyGraph {
132132 compilerVersionString = " "
133133 allNodes = nodesForTesting
134134 }
135-
136- public init ( pathString: String ) throws {
135+
136+ // FIXME: This should accept a FileSystem parameter.
137+ @_spi ( Testing) public init ( pathString: String ) throws {
137138 let data = try Data ( contentsOf: URL ( fileURLWithPath: pathString) )
138139 try self . init ( data: data)
139140 }
140-
141- public init ( data: Data ) throws {
142- // FIXME: visit blocks and records incrementally instead of reading the
143- // entire file up front.
144- let bitcode = try Bitcode ( data: data)
145- guard bitcode. signature == . init( string: " DEPS " ) else { throw ReadError . badMagic }
146-
147- guard bitcode. elements. count == 1 ,
148- case . block( let recordBlock) = bitcode. elements. first,
149- recordBlock. id == Self . recordBlockId else { throw ReadError . noRecordBlock }
150-
151- guard case . record( let metadataRecord) = recordBlock. elements. first,
152- RecordKind ( rawValue: metadataRecord. id) == . metadata,
153- metadataRecord. fields. count == 2 ,
154- case . blob( let compilerVersionBlob) = metadataRecord. payload,
155- let compilerVersionString = String ( data: compilerVersionBlob, encoding: . utf8)
156- else { throw ReadError . malformedMetadataRecord }
157-
158- self . majorVersion = metadataRecord. fields [ 0 ]
159- self . minorVersion = metadataRecord. fields [ 1 ]
160- self . compilerVersionString = compilerVersionString
161-
162- var nodes : [ Node ] = [ ]
163- var node : Node ? = nil
164- var identifiers : [ String ] = [ " " ] // The empty string is hardcoded as identifiers[0]
165- var sequenceNumber = 0
166- for element in recordBlock. elements. dropFirst ( ) {
167- guard case . record( let record) = element else { throw ReadError . unexpectedSubblock }
168- guard let kind = RecordKind ( rawValue: record. id) else { throw ReadError . unknownRecord }
169- switch kind {
170- case . metadata:
171- throw ReadError . unexpectedMetadataRecord
172- case . sourceFileDepGraphNode:
173- if let node = node {
174- nodes. append ( node)
141+
142+ @_spi ( Testing) public init ( data: Data ,
143+ fromSwiftModule extractFromSwiftModule: Bool = false ) throws {
144+ struct Visitor : BitstreamVisitor {
145+ let extractFromSwiftModule : Bool
146+
147+ init ( extractFromSwiftModule: Bool ) {
148+ self . extractFromSwiftModule = extractFromSwiftModule
149+ }
150+
151+ var nodes : [ Node ] = [ ]
152+ var majorVersion : UInt64 ?
153+ var minorVersion : UInt64 ?
154+ var compilerVersionString : String ?
155+
156+ private var node : Node ? = nil
157+ private var identifiers : [ String ] = [ " " ] // The empty string is hardcoded as identifiers[0]
158+ private var sequenceNumber = 0
159+
160+ func validate( signature: Bitcode . Signature ) throws {
161+ if extractFromSwiftModule {
162+ guard signature == . init( value: 0x0EA89CE2 ) else { throw ReadError . badMagic }
163+ } else {
164+ guard signature == . init( string: " DEPS " ) else { throw ReadError . badMagic }
175165 }
176- let kindCode = record. fields [ 0 ]
177- guard record. fields. count == 5 ,
178- let declAspect = DependencyKey . DeclAspect ( record. fields [ 1 ] ) ,
179- record. fields [ 2 ] < identifiers. count,
180- record. fields [ 3 ] < identifiers. count else {
181- throw ReadError . malformedSourceFileDepGraphNodeRecord
166+ }
167+
168+ mutating func shouldEnterBlock( id: UInt64 ) throws -> Bool {
169+ if extractFromSwiftModule {
170+ // Enter the top-level module block, and the incremental info
171+ // subblock, ignoring the rest of the file.
172+ return id == /*Module block*/ 8 || id == /*Incremental record block*/ 196
173+ } else {
174+ guard id == /*Incremental record block*/ 8 else {
175+ throw ReadError . unexpectedSubblock
176+ }
177+ return true
182178 }
183- let context = identifiers [ Int ( record. fields [ 2 ] ) ]
184- let identifier = identifiers [ Int ( record. fields [ 3 ] ) ]
185- let isProvides = record. fields [ 4 ] != 0
186- let designator = try DependencyKey . Designator (
187- kindCode: kindCode, context: context, name: identifier)
188- let key = DependencyKey ( aspect: declAspect, designator: designator)
189- node = Node ( key: key,
190- fingerprint: nil ,
191- sequenceNumber: sequenceNumber,
192- defsIDependUpon: [ ] ,
193- isProvides: isProvides)
194- sequenceNumber += 1
195- case . fingerprintNode:
196- guard node != nil ,
197- record. fields. count == 0 ,
198- case . blob( let fingerprintBlob) = record. payload,
199- let fingerprint = String ( data: fingerprintBlob, encoding: . utf8) else {
200- throw ReadError . malformedFingerprintRecord
179+ }
180+
181+ mutating func didExitBlock( ) throws {
182+ // Finalize the current node if needed.
183+ if let node = node {
184+ nodes. append ( node)
185+ self . node = nil
201186 }
202- node? . fingerprint = fingerprint
203- case . dependsOnDefinitionNode:
204- guard node != nil ,
205- record. fields. count == 1 else { throw ReadError . malformedDependsOnDefinitionRecord }
206- node? . defsIDependUpon. append ( Int ( record. fields [ 0 ] ) )
207- case . identifierNode:
208- guard record. fields. count == 0 ,
209- case . blob( let identifierBlob) = record. payload,
210- let identifier = String ( data: identifierBlob, encoding: . utf8) else {
211- throw ReadError . malformedIdentifierRecord
187+ }
188+
189+ mutating func visit( record: BitcodeElement . Record ) throws {
190+ guard let kind = RecordKind ( rawValue: record. id) else { throw ReadError . unknownRecord }
191+ switch kind {
192+ case . metadata:
193+ // If we've already read metadata, this is an unexpected duplicate.
194+ guard majorVersion == nil , minorVersion == nil , compilerVersionString == nil else {
195+ throw ReadError . unexpectedMetadataRecord
196+ }
197+ guard record. fields. count == 2 ,
198+ case . blob( let compilerVersionBlob) = record. payload,
199+ let compilerVersionString = String ( data: compilerVersionBlob, encoding: . utf8)
200+ else { throw ReadError . malformedMetadataRecord }
201+
202+ self . majorVersion = record. fields [ 0 ]
203+ self . minorVersion = record. fields [ 1 ]
204+ self . compilerVersionString = compilerVersionString
205+ case . sourceFileDepGraphNode:
206+ if let node = node {
207+ nodes. append ( node)
208+ }
209+ let kindCode = record. fields [ 0 ]
210+ guard record. fields. count == 5 ,
211+ let declAspect = DependencyKey . DeclAspect ( record. fields [ 1 ] ) ,
212+ record. fields [ 2 ] < identifiers. count,
213+ record. fields [ 3 ] < identifiers. count else {
214+ throw ReadError . malformedSourceFileDepGraphNodeRecord
215+ }
216+ let context = identifiers [ Int ( record. fields [ 2 ] ) ]
217+ let identifier = identifiers [ Int ( record. fields [ 3 ] ) ]
218+ let isProvides = record. fields [ 4 ] != 0
219+ let designator = try DependencyKey . Designator (
220+ kindCode: kindCode, context: context, name: identifier)
221+ let key = DependencyKey ( aspect: declAspect, designator: designator)
222+ node = Node ( key: key,
223+ fingerprint: nil ,
224+ sequenceNumber: sequenceNumber,
225+ defsIDependUpon: [ ] ,
226+ isProvides: isProvides)
227+ sequenceNumber += 1
228+ case . fingerprintNode:
229+ guard node != nil ,
230+ record. fields. count == 0 ,
231+ case . blob( let fingerprintBlob) = record. payload,
232+ let fingerprint = String ( data: fingerprintBlob, encoding: . utf8) else {
233+ throw ReadError . malformedFingerprintRecord
234+ }
235+ node? . fingerprint = fingerprint
236+ case . dependsOnDefinitionNode:
237+ guard node != nil ,
238+ record. fields. count == 1 else { throw ReadError . malformedDependsOnDefinitionRecord }
239+ node? . defsIDependUpon. append ( Int ( record. fields [ 0 ] ) )
240+ case . identifierNode:
241+ guard record. fields. count == 0 ,
242+ case . blob( let identifierBlob) = record. payload,
243+ let identifier = String ( data: identifierBlob, encoding: . utf8) else {
244+ throw ReadError . malformedIdentifierRecord
245+ }
246+ identifiers. append ( identifier)
212247 }
213- identifiers. append ( identifier)
214248 }
215249 }
216-
217- if let node = node {
218- nodes. append ( node)
250+
251+ var visitor = Visitor ( extractFromSwiftModule: extractFromSwiftModule)
252+ try Bitcode . read ( stream: data, using: & visitor)
253+ guard let major = visitor. majorVersion,
254+ let minor = visitor. minorVersion,
255+ let versionString = visitor. compilerVersionString else {
256+ throw ReadError . malformedMetadataRecord
219257 }
220-
221- self . allNodes = nodes
258+ self . majorVersion = major
259+ self . minorVersion = minor
260+ self . compilerVersionString = versionString
261+ self . allNodes = visitor. nodes
222262 }
223263}
224264
0 commit comments