Skip to content

Commit 34b5ff7

Browse files
authored
Merge pull request #455 from CodaFi/spirograph
Finish Up Driver Dependency Graph Serialization
2 parents c155e8d + 5f4a479 commit 34b5ff7

File tree

8 files changed

+198
-64
lines changed

8 files changed

+198
-64
lines changed

Sources/SwiftDriver/IncrementalCompilation/BidirectionalMap.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
/// Like a two-way dictionary, only works for accessing present members
14-
public struct BidirectionalMap<T1: Hashable, T2: Hashable> {
14+
public struct BidirectionalMap<T1: Hashable, T2: Hashable>: Equatable {
1515
private var map1: [T1: T2] = [:]
1616
private var map2: [T2: T1] = [:]
1717

Sources/SwiftDriver/IncrementalCompilation/DictionaryOfDictionaries.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,7 @@ extension DictionaryOfDictionaries {
135135
return old
136136
}
137137
}
138+
139+
// MARK: - identity
140+
141+
extension DictionaryOfDictionaries: Equatable where Value: Equatable {}

Sources/SwiftDriver/IncrementalCompilation/ModuleDependencyGraph.swift

Lines changed: 180 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,10 @@ extension ModuleDependencyGraph {
279279
fileprivate enum RecordID: UInt64 {
280280
case metadata = 1
281281
case moduleDepGraphNode = 2
282-
case identifierNode = 3
282+
case dependsOnNode = 3
283+
case useIDNode = 4
284+
case externalDepNode = 5
285+
case identifierNode = 6
283286

284287
/// The human-readable name of this record.
285288
///
@@ -292,6 +295,12 @@ extension ModuleDependencyGraph {
292295
return "METADATA"
293296
case .moduleDepGraphNode:
294297
return "MODULE_DEP_GRAPH_NODE"
298+
case .dependsOnNode:
299+
return "DEPENDS_ON_NODE"
300+
case .useIDNode:
301+
return "USE_ID_NODE"
302+
case .externalDepNode:
303+
return "EXTERNAL_DEP_NODE"
295304
case .identifierNode:
296305
return "IDENTIFIER_NODE"
297306
}
@@ -306,6 +315,8 @@ extension ModuleDependencyGraph {
306315
case malformedFingerprintRecord
307316
case malformedIdentifierRecord
308317
case malformedModuleDepGraphNodeRecord
318+
case malformedDependsOnRecord
319+
case malformedExternalDepNodeRecord
309320
case unknownRecord
310321
case unexpectedSubblock
311322
case bogusNameOrContext
@@ -330,15 +341,16 @@ extension ModuleDependencyGraph {
330341
let data = try fileSystem.readFileContents(path)
331342

332343
struct Visitor: BitstreamVisitor {
333-
let graph: ModuleDependencyGraph
344+
private let graph: ModuleDependencyGraph
334345
var majorVersion: UInt64?
335346
var minorVersion: UInt64?
336347
var compilerVersionString: String?
337348

338-
private var node: Node? = nil
339349
// The empty string is hardcoded as identifiers[0]
340350
private var identifiers: [String] = [""]
341-
private var sequenceNumber = 0
351+
private var currentDefKey: DependencyKey? = nil
352+
private var nodeUses: [DependencyKey: [Int]] = [:]
353+
private var allNodes: [Node] = []
342354

343355
init(
344356
diagnosticEngine: DiagnosticsEngine,
@@ -350,23 +362,31 @@ extension ModuleDependencyGraph {
350362
verifyDependencyGraphAfterEveryImport: false)
351363
}
352364

365+
func finalizeGraph() -> ModuleDependencyGraph {
366+
for (dependencyKey, useIDs) in self.nodeUses {
367+
for useID in useIDs {
368+
let isNewUse = self.graph.nodeFinder
369+
.record(def: dependencyKey, use: self.allNodes[useID])
370+
assert(isNewUse, "Duplicate use def-use arc in graph?")
371+
}
372+
}
373+
return self.graph
374+
}
375+
353376
func validate(signature: Bitcode.Signature) throws {
354-
guard signature == .init(string: ModuleDependencyGraph.signature) else { throw ReadError.badMagic }
377+
guard signature == .init(string: ModuleDependencyGraph.signature) else {
378+
throw ReadError.badMagic
379+
}
355380
}
356381

357382
mutating func shouldEnterBlock(id: UInt64) throws -> Bool {
358383
return true
359384
}
360385

361-
mutating func didExitBlock() throws {
362-
// Finalize the current node if needed.
363-
guard let newNode = node else {
364-
return
365-
}
366-
self.finalize(node: newNode)
367-
}
386+
mutating func didExitBlock() throws {}
368387

369-
private func finalize(node newNode: Node) {
388+
private mutating func finalize(node newNode: Node) {
389+
self.allNodes.append(newNode)
370390
let oldNode = self.graph.nodeFinder.insert(newNode)
371391
assert(oldNode == nil,
372392
"Integrated the same node twice: \(oldNode!), \(newNode)")
@@ -392,9 +412,6 @@ extension ModuleDependencyGraph {
392412
self.minorVersion = record.fields[1]
393413
self.compilerVersionString = compilerVersionString
394414
case .moduleDepGraphNode:
395-
if let node = node {
396-
self.finalize(node: node)
397-
}
398415
let kindCode = record.fields[0]
399416
guard record.fields.count == 7,
400417
let declAspect = DependencyKey.DeclAspect(record.fields[1]),
@@ -417,10 +434,36 @@ extension ModuleDependencyGraph {
417434
let swiftDeps = try swiftDepsStr
418435
.map({ try VirtualPath(path: $0) })
419436
.map(ModuleDependencyGraph.SwiftDeps.init)
420-
node = Node(key: key,
421-
fingerprint: fingerprint,
422-
swiftDeps: swiftDeps)
423-
sequenceNumber += 1
437+
self.finalize(node: Node(key: key,
438+
fingerprint: fingerprint,
439+
swiftDeps: swiftDeps))
440+
case .dependsOnNode:
441+
let kindCode = record.fields[0]
442+
guard record.fields.count == 4,
443+
let declAspect = DependencyKey.DeclAspect(record.fields[1]),
444+
record.fields[2] < identifiers.count,
445+
record.fields[3] < identifiers.count
446+
else {
447+
throw ReadError.malformedDependsOnRecord
448+
}
449+
let context = identifiers[Int(record.fields[2])]
450+
let identifier = identifiers[Int(record.fields[3])]
451+
let designator = try DependencyKey.Designator(
452+
kindCode: kindCode, context: context, name: identifier)
453+
self.currentDefKey = DependencyKey(aspect: declAspect, designator: designator)
454+
case .useIDNode:
455+
guard let key = self.currentDefKey, record.fields.count == 1 else {
456+
throw ReadError.malformedDependsOnRecord
457+
}
458+
self.nodeUses[key, default: []].append(Int(record.fields[0]))
459+
case .externalDepNode:
460+
guard record.fields.count == 1,
461+
record.fields[0] < identifiers.count
462+
else {
463+
throw ReadError.malformedExternalDepNodeRecord
464+
}
465+
let path = identifiers[Int(record.fields[0])]
466+
self.graph.externalDependencies.insert(ExternalDependency(path))
424467
case .identifierNode:
425468
guard record.fields.count == 0,
426469
case .blob(let identifierBlob) = record.payload,
@@ -448,7 +491,7 @@ extension ModuleDependencyGraph {
448491
else {
449492
throw ReadError.malformedMetadataRecord
450493
}
451-
return visitor.graph
494+
return visitor.finalizeGraph()
452495
}
453496
}
454497
}
@@ -491,6 +534,8 @@ extension ModuleDependencyGraph {
491534
private var identifiersToWrite = [String]()
492535
private var identifierIDs = [String: Int]()
493536
private var lastIdentifierID: Int = 1
537+
fileprivate private(set) var nodeIDs = [Node: Int]()
538+
private var lastNodeID: Int = 0
494539

495540
private init(compilerVersion: String) {
496541
self.compilerVersion = compilerVersion
@@ -529,6 +574,8 @@ extension ModuleDependencyGraph {
529574
self.emitBlockID(.firstApplicationID, "RECORD_BLOCK")
530575
self.emitRecordID(.metadata)
531576
self.emitRecordID(.moduleDepGraphNode)
577+
self.emitRecordID(.useIDNode)
578+
self.emitRecordID(.externalDepNode)
532579
self.emitRecordID(.identifierNode)
533580
}
534581
}
@@ -562,8 +609,15 @@ extension ModuleDependencyGraph {
562609
return UInt32(self.identifierIDs[string]!)
563610
}
564611

565-
private func writeStrings(in graph: ModuleDependencyGraph) {
612+
private func cacheNodeID(for node: Node) {
613+
defer { self.lastNodeID += 1 }
614+
nodeIDs[node] = self.lastNodeID
615+
}
616+
617+
private func populateCaches(from graph: ModuleDependencyGraph) {
566618
graph.nodeFinder.forEachNode { node in
619+
self.cacheNodeID(for: node)
620+
567621
if let swiftDeps = node.swiftDeps?.file.name {
568622
self.addIdentifier(swiftDeps)
569623
}
@@ -575,13 +629,84 @@ extension ModuleDependencyGraph {
575629
}
576630
}
577631

632+
for key in graph.nodeFinder.usesByDef.keys {
633+
if let context = key.designator.context {
634+
self.addIdentifier(context)
635+
}
636+
if let name = key.designator.name {
637+
self.addIdentifier(name)
638+
}
639+
}
640+
641+
for path in graph.externalDependencies {
642+
self.addIdentifier(path.fileName)
643+
}
644+
578645
for str in self.identifiersToWrite {
579646
self.stream.writeRecord(self.abbreviations[.identifierNode]!, {
580647
$0.append(RecordID.identifierNode)
581648
}, blob: str)
582649
}
583650
}
584651

652+
private func registerAbbreviations() {
653+
self.abbreviate(.metadata, [
654+
.literal(RecordID.metadata.rawValue),
655+
// Major version
656+
.fixed(bitWidth: 16),
657+
// Minor version
658+
.fixed(bitWidth: 16),
659+
// Frontend version
660+
.blob,
661+
])
662+
self.abbreviate(.moduleDepGraphNode, [
663+
.literal(RecordID.moduleDepGraphNode.rawValue),
664+
// dependency kind discriminator
665+
.fixed(bitWidth: 3),
666+
// dependency decl aspect discriminator
667+
.fixed(bitWidth: 1),
668+
// dependency context
669+
.vbr(chunkBitWidth: 13),
670+
// dependency name
671+
.vbr(chunkBitWidth: 13),
672+
// swiftdeps?
673+
.fixed(bitWidth: 1),
674+
// swiftdeps path
675+
.vbr(chunkBitWidth: 13),
676+
// fingerprint?
677+
.fixed(bitWidth: 1),
678+
// fingerprint bytes
679+
.blob,
680+
])
681+
self.abbreviate(.dependsOnNode, [
682+
.literal(RecordID.dependsOnNode.rawValue),
683+
// dependency kind discriminator
684+
.fixed(bitWidth: 3),
685+
// dependency decl aspect discriminator
686+
.fixed(bitWidth: 1),
687+
// dependency context
688+
.vbr(chunkBitWidth: 13),
689+
// dependency name
690+
.vbr(chunkBitWidth: 13),
691+
])
692+
693+
self.abbreviate(.useIDNode, [
694+
.literal(RecordID.useIDNode.rawValue),
695+
// node ID
696+
.vbr(chunkBitWidth: 13),
697+
])
698+
self.abbreviate(.externalDepNode, [
699+
.literal(RecordID.externalDepNode.rawValue),
700+
// path ID
701+
.vbr(chunkBitWidth: 13),
702+
])
703+
self.abbreviate(.identifierNode, [
704+
.literal(RecordID.identifierNode.rawValue),
705+
// identifier data
706+
.blob
707+
])
708+
}
709+
585710
private func abbreviate(
586711
_ record: RecordID,
587712
_ operands: [Bitstream.Abbreviation.Operand]
@@ -599,43 +724,11 @@ extension ModuleDependencyGraph {
599724
serializer.writeBlockInfoBlock()
600725

601726
serializer.stream.withSubBlock(.firstApplicationID, abbreviationBitWidth: 8) {
602-
serializer.abbreviate(.metadata, [
603-
.literal(RecordID.metadata.rawValue),
604-
// Major version
605-
.fixed(bitWidth: 16),
606-
// Minor version
607-
.fixed(bitWidth: 16),
608-
// Frontend version
609-
.blob,
610-
])
611-
serializer.abbreviate(.moduleDepGraphNode, [
612-
.literal(RecordID.moduleDepGraphNode.rawValue),
613-
// dependency kind discriminator
614-
.fixed(bitWidth: 3),
615-
// dependency decl aspect discriminator
616-
.fixed(bitWidth: 1),
617-
// dependency context
618-
.vbr(chunkBitWidth: 13),
619-
// dependency name
620-
.vbr(chunkBitWidth: 13),
621-
// swiftdeps?
622-
.fixed(bitWidth: 1),
623-
// swiftdeps path
624-
.vbr(chunkBitWidth: 13),
625-
// fingerprint?
626-
.fixed(bitWidth: 1),
627-
// fingerprint bytes
628-
.blob,
629-
])
630-
serializer.abbreviate(.identifierNode, [
631-
.literal(RecordID.identifierNode.rawValue),
632-
// identifier data
633-
.blob
634-
])
727+
serializer.registerAbbreviations()
635728

636729
serializer.writeMetadata()
637730

638-
serializer.writeStrings(in: graph)
731+
serializer.populateCaches(from: graph)
639732

640733
graph.nodeFinder.forEachNode { node in
641734
serializer.stream.writeRecord(serializer.abbreviations[.moduleDepGraphNode]!, {
@@ -652,6 +745,35 @@ extension ModuleDependencyGraph {
652745
$0.append((node.fingerprint != nil) ? UInt32(1) : UInt32(0))
653746
}, blob: node.fingerprint ?? "")
654747
}
748+
749+
for key in graph.nodeFinder.usesByDef.keys {
750+
serializer.stream.writeRecord(serializer.abbreviations[.dependsOnNode]!) {
751+
$0.append(RecordID.dependsOnNode)
752+
$0.append(key.designator.code)
753+
$0.append(key.aspect.code)
754+
$0.append(serializer.lookupIdentifierCode(
755+
for: key.designator.context ?? ""))
756+
$0.append(serializer.lookupIdentifierCode(
757+
for: key.designator.name ?? ""))
758+
}
759+
for use in graph.nodeFinder.usesByDef[key]?.values ?? [] {
760+
guard let useID = serializer.nodeIDs[use] else {
761+
fatalError("Node ID was not registered! \(use)")
762+
}
763+
764+
serializer.stream.writeRecord(serializer.abbreviations[.useIDNode]!) {
765+
$0.append(RecordID.useIDNode)
766+
$0.append(UInt32(useID))
767+
}
768+
}
769+
}
770+
771+
for dep in graph.externalDependencies {
772+
serializer.stream.writeRecord(serializer.abbreviations[.externalDepNode]!) {
773+
$0.append(RecordID.externalDepNode)
774+
$0.append(serializer.lookupIdentifierCode(for: dep.fileName))
775+
}
776+
}
655777
}
656778
return ByteString(serializer.stream.data)
657779
}
@@ -765,11 +887,11 @@ fileprivate extension DependencyKey.Designator {
765887
case .dynamicLookup(name: let name):
766888
return name
767889
case .externalDepend(let path):
768-
return path.file?.basename
890+
return path.fileName
769891
case .sourceFileProvide(name: let name):
770892
return name
771893
case .incrementalExternalDependency(let path):
772-
return path.file?.basename
894+
return path.fileName
773895
case .member(context: _, name: let name):
774896
return name
775897
case .nominal(context: _):

Sources/SwiftDriver/IncrementalCompilation/ModuleDependencyGraphParts/Integrator.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,7 @@ extension ModuleDependencyGraph.Integrator {
193193
_ sourceFileUseNode: SourceFileDependencyGraph.Node,
194194
_ moduleUseNode: Graph.Node
195195
) {
196-
source.forEachDefDependedUpon(by: sourceFileUseNode) {
197-
def in
196+
source.forEachDefDependedUpon(by: sourceFileUseNode) { def in
198197
let isNewUse = destination.nodeFinder.record(def: def.key,
199198
use: moduleUseNode)
200199
if let externalDependency = def.key.designator.externalDependency,

0 commit comments

Comments
 (0)