@@ -14,6 +14,7 @@ import SwiftOptions
14
14
15
15
import protocol TSCBasic. FileSystem
16
16
import struct TSCBasic. ByteString
17
+ import struct TSCBasic. SHA256
17
18
import class Dispatch. DispatchQueue
18
19
import struct Foundation. TimeInterval
19
20
@@ -63,11 +64,12 @@ import struct Foundation.TimeInterval
63
64
_ phase: Phase ,
64
65
_ internedStringTable: InternedStringTable ,
65
66
_ nodeFinder: NodeFinder ,
66
- _ fingerprintedExternalDependencies: Set < FingerprintedExternalDependency >
67
+ _ fingerprintedExternalDependencies: Set < FingerprintedExternalDependency > ,
68
+ _ externalDependencyFileHashes: Dictionary < ExternalDependency , String >
67
69
) {
68
70
self . buildRecord = buildRecord
69
71
self . currencyCache = ExternalDependencyCurrencyCache (
70
- info. fileSystem, buildStartTime: buildRecord. buildStartTime)
72
+ info. fileSystem, buildStartTime: buildRecord. buildStartTime, externalDependencyFileHashes : externalDependencyFileHashes , useFileHashes : info . useFileHashesInModuleDependencyGraph )
71
73
self . info = info
72
74
self . dotFileWriter = info. emitDependencyDotFileAfterEveryImport
73
75
? DependencyGraphDotFileWriter ( info)
@@ -88,22 +90,24 @@ import struct Foundation.TimeInterval
88
90
" If updating from prior, should be supplying more ingredients " )
89
91
self . init ( buildRecord, info, phase, InternedStringTable ( info. incrementalCompilationQueue) ,
90
92
NodeFinder ( ) ,
91
- Set ( ) )
93
+ Set ( ) , Dictionary ( ) )
92
94
}
93
95
94
96
public static func createFromPrior(
95
97
_ buildRecord: BuildRecord ,
96
98
_ info: IncrementalCompilationState . IncrementalDependencyAndInputSetup ,
97
99
_ internedStringTable: InternedStringTable ,
98
100
_ nodeFinder: NodeFinder ,
99
- _ fingerprintedExternalDependencies: Set < FingerprintedExternalDependency >
101
+ _ fingerprintedExternalDependencies: Set < FingerprintedExternalDependency > ,
102
+ _ externalDependencyFileHashes: Dictionary < ExternalDependency , String >
100
103
) -> Self {
101
104
self . init ( buildRecord,
102
105
info,
103
106
. updatingFromAPrior,
104
107
internedStringTable,
105
108
nodeFinder,
106
- fingerprintedExternalDependencies)
109
+ fingerprintedExternalDependencies,
110
+ externalDependencyFileHashes)
107
111
}
108
112
109
113
public static func createForBuildingFromSwiftDeps(
@@ -567,10 +571,24 @@ extension ModuleDependencyGraph {
567
571
private let fileSystem : FileSystem
568
572
private let buildStartTime : TimePoint
569
573
private var currencyCache = [ ExternalDependency: Bool] ( )
574
+ public internal( set) var externalDependencyFileHashes : [ ExternalDependency : String ]
575
+ private let useFileHashes : Bool
570
576
571
- init ( _ fileSystem: FileSystem , buildStartTime: TimePoint ) {
577
+ init ( _ fileSystem: FileSystem , buildStartTime: TimePoint , externalDependencyFileHashes : Dictionary < ExternalDependency , String > , useFileHashes : Bool ) {
572
578
self . fileSystem = fileSystem
573
579
self . buildStartTime = buildStartTime
580
+ self . externalDependencyFileHashes = externalDependencyFileHashes
581
+ self . useFileHashes = useFileHashes
582
+ }
583
+
584
+ mutating func updateHash( _ externalDependency: ExternalDependency ) {
585
+ guard useFileHashes else {
586
+ return
587
+ }
588
+ if let depFile = externalDependency. path,
589
+ let data = try ? fileSystem. readFileContents ( depFile) {
590
+ externalDependencyFileHashes [ externalDependency] = SHA256 ( ) . hash ( data) . hexadecimalRepresentation
591
+ }
574
592
}
575
593
576
594
mutating func beCurrent( _ externalDependency: ExternalDependency ) {
@@ -581,11 +599,31 @@ extension ModuleDependencyGraph {
581
599
if let cachedResult = self . currencyCache [ externalDependency] {
582
600
return cachedResult
583
601
}
584
- let uncachedResult = isCurrentWRTFileSystem ( externalDependency)
602
+ var uncachedResult = isCurrentWRTFileSystem ( externalDependency)
603
+ if useFileHashes && !uncachedResult {
604
+ uncachedResult = isCurrentWRTFileHash ( externalDependency)
605
+ }
585
606
self . currencyCache [ externalDependency] = uncachedResult
607
+ if !uncachedResult {
608
+ self . updateHash ( externalDependency)
609
+ }
586
610
return uncachedResult
587
611
}
588
612
613
+ mutating func ensureHash( _ externalDependency: ExternalDependency ) {
614
+ if ( self . externalDependencyFileHashes [ externalDependency] ?? " " ) . isEmpty {
615
+ self . updateHash ( externalDependency)
616
+ }
617
+ }
618
+
619
+ private func isCurrentWRTFileHash( _ externalDependency: ExternalDependency ) -> Bool {
620
+ if let depFile = externalDependency. path,
621
+ let data = try ? fileSystem. readFileContents ( depFile) {
622
+ return self . externalDependencyFileHashes [ externalDependency] == SHA256 ( ) . hash ( data) . hexadecimalRepresentation
623
+ }
624
+ return false
625
+ }
626
+
589
627
private func isCurrentWRTFileSystem( _ externalDependency: ExternalDependency ) -> Bool {
590
628
if let depFile = externalDependency. path,
591
629
let fileModTime = try ? self . fileSystem. lastModificationTime ( for: depFile) ,
@@ -753,6 +791,7 @@ extension ModuleDependencyGraph {
753
791
private var currentDefKey : DependencyKey ? = nil
754
792
private var nodeUses : [ ( DependencyKey , Int ) ] = [ ]
755
793
private var fingerprintedExternalDependencies = Set < FingerprintedExternalDependency > ( )
794
+ private var externalDependencyFileHashes = Dictionary < ExternalDependency , String > ( )
756
795
757
796
/// Deserialized nodes, in order appearing in the priors file. If `nil`, the node is for a removed source file.
758
797
///
@@ -789,7 +828,8 @@ extension ModuleDependencyGraph {
789
828
info,
790
829
internedStringTable,
791
830
nodeFinder,
792
- fingerprintedExternalDependencies)
831
+ fingerprintedExternalDependencies,
832
+ externalDependencyFileHashes)
793
833
for (dependencyKey, useID) in self . nodeUses {
794
834
guard let use = self . potentiallyUsedNodes [ useID] else {
795
835
// Don't record uses of defs of removed files.
@@ -982,16 +1022,19 @@ extension ModuleDependencyGraph {
982
1022
}
983
1023
self . nodeUses. append ( ( key, Int ( record. fields [ 0 ] ) ) )
984
1024
case . externalDepNode:
985
- guard record. fields. count == 2
1025
+ guard record. fields. count == 2 ,
1026
+ case . blob( let hashBlob) = record. payload
986
1027
else {
987
1028
throw malformedError
988
1029
}
989
1030
let path = try internedString ( field: 0 )
990
1031
let fingerprint = try nonemptyInternedString ( field: 1 )
1032
+ let hash = String ( decoding: hashBlob, as: UTF8 . self)
1033
+ let externalDependency = ExternalDependency ( fileName: path, internedStringTable)
1034
+
991
1035
fingerprintedExternalDependencies. insert (
992
- FingerprintedExternalDependency (
993
- ExternalDependency ( fileName: path, internedStringTable) ,
994
- fingerprint) )
1036
+ FingerprintedExternalDependency ( externalDependency, fingerprint) )
1037
+ externalDependencyFileHashes [ externalDependency] = hash
995
1038
case . identifierNode:
996
1039
guard record. fields. count == 0 ,
997
1040
case . blob( let identifierBlob) = record. payload
@@ -1170,7 +1213,7 @@ extension ModuleDependencyGraph {
1170
1213
$0. append ( inputInfo. previousModTime)
1171
1214
$0. append ( inputInfo. status. code)
1172
1215
$0. append ( pathID)
1173
- } , blob: inputInfo. hash)
1216
+ } , blob: inputInfo. hash ?? " " )
1174
1217
}
1175
1218
}
1176
1219
@@ -1282,6 +1325,8 @@ extension ModuleDependencyGraph {
1282
1325
. vbr( chunkBitWidth: 13 ) ,
1283
1326
// fingerprint ID
1284
1327
. vbr( chunkBitWidth: 13 ) ,
1328
+ // file hash
1329
+ . blob,
1285
1330
] )
1286
1331
self . abbreviate ( . identifierNode, [
1287
1332
. literal( RecordID . identifierNode. rawValue) ,
@@ -1356,13 +1401,15 @@ extension ModuleDependencyGraph {
1356
1401
}
1357
1402
}
1358
1403
for fingerprintedExternalDependency in graph. fingerprintedExternalDependencies {
1359
- serializer. stream. writeRecord ( serializer. abbreviations [ . externalDepNode] !) {
1404
+ graph. currencyCache. ensureHash ( fingerprintedExternalDependency. externalDependency)
1405
+ serializer. stream. writeRecord ( serializer. abbreviations [ . externalDepNode] !, {
1360
1406
$0. append ( RecordID . externalDepNode)
1361
1407
$0. append ( serializer. lookupIdentifierCode (
1362
1408
for: fingerprintedExternalDependency. externalDependency. fileName) )
1363
1409
$0. append ( serializer. lookupIdentifierCode (
1364
1410
for: fingerprintedExternalDependency. fingerprint) )
1365
- }
1411
+ } ,
1412
+ blob: graph. currencyCache. externalDependencyFileHashes [ fingerprintedExternalDependency. externalDependency] ?? " " )
1366
1413
}
1367
1414
}
1368
1415
return ByteString ( serializer. stream. data)
0 commit comments