Skip to content

Commit 9d308f1

Browse files
committed
Merge 'upstream/main' into windows-toolchain
2 parents 58c6f7a + 5adec4a commit 9d308f1

File tree

9 files changed

+372
-230
lines changed

9 files changed

+372
-230
lines changed

Sources/SwiftDriver/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ add_library(SwiftDriver
4444
"IncrementalCompilation/DependencyGraphDotFileWriter.swift"
4545
"IncrementalCompilation/DependencyKey.swift"
4646
"IncrementalCompilation/DictionaryOfDictionaries.swift"
47+
"IncrementalCompilation/DirectAndTransitiveCollections.swift"
4748
"IncrementalCompilation/ExternalDependencyAndFingerprintEnforcer.swift"
4849
"IncrementalCompilation/IncrementalCompilationState.swift"
4950
"IncrementalCompilation/InitialStateComputer.swift"
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//===------------------ DirectAndTransitiveCollections.swift --------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
// Use the type system to ensure that dependencies are transitively closed
13+
// without doing too much work at the leaves of the call tree
14+
public struct Transitively {}
15+
public struct Directly {}
16+
17+
public struct InvalidatedSet<ClosureLevel, Element: Hashable>: Sequence {
18+
var contents: Set<Element>
19+
20+
init(_ s: Set<Element> = Set()) {
21+
self.contents = s
22+
}
23+
init<Elements: Sequence>(_ elements: Elements)
24+
where Elements.Element == Element
25+
{
26+
self.init(Set(elements))
27+
}
28+
mutating func insert(_ e: Element) {
29+
contents.insert(e)
30+
}
31+
mutating func formUnion<Elements: Sequence>(_ elements: Elements)
32+
where Elements.Element == Element{
33+
contents.formUnion(elements)
34+
}
35+
public func makeIterator() -> Set<Element>.Iterator {
36+
contents.makeIterator()
37+
}
38+
public func map<R>(_ transform: (Element) -> R) -> InvalidatedArray<ClosureLevel, R> {
39+
InvalidatedArray(contents.map(transform))
40+
}
41+
public func compactMap<R>(_ transform: (Element) -> R? ) -> InvalidatedArray<ClosureLevel, R> {
42+
InvalidatedArray(contents.compactMap(transform))
43+
}
44+
}
45+
46+
extension InvalidatedSet where Element: Comparable {
47+
func sorted() -> InvalidatedArray<ClosureLevel, Element> {
48+
InvalidatedArray(contents.sorted())
49+
}
50+
}
51+
52+
public struct InvalidatedArray<ClosureLevel, Element>: Sequence {
53+
var contents: [Element]
54+
55+
init(_ s: [Element] = []) {
56+
self.contents = s
57+
}
58+
init<Elements: Sequence>(_ elements: Elements)
59+
where Elements.Element == Element
60+
{
61+
self.init(Array(elements))
62+
}
63+
public func makeIterator() -> Array<Element>.Iterator {
64+
contents.makeIterator()
65+
}
66+
public mutating func append(_ e: Element) {
67+
contents.append(e)
68+
}
69+
public func reduce<R: Hashable>(
70+
into initialResult: InvalidatedSet<ClosureLevel, R>,
71+
_ updateAccumulatingResult: (inout Set<R>, Element) -> ()
72+
) -> InvalidatedSet<ClosureLevel, R> {
73+
InvalidatedSet(
74+
contents.reduce(into: initialResult.contents, updateAccumulatingResult))
75+
}
76+
public var count: Int { contents.count }
77+
}
78+
79+
public typealias TransitivelyInvalidatedNodeArray = InvalidatedArray<Transitively, ModuleDependencyGraph.Node>
80+
public typealias TransitivelyInvalidatedSourceSet = InvalidatedSet<Transitively, DependencySource>
81+
public typealias TransitivelyInvalidatedInputArray = InvalidatedArray<Transitively, TypedVirtualPath>
82+
public typealias TransitivelyInvalidatedInputSet = InvalidatedSet<Transitively, TypedVirtualPath>
83+
public typealias DirectlyInvalidatedNodeArray = InvalidatedArray<Directly, ModuleDependencyGraph.Node>
84+
public typealias DirectlyInvalidatedNodeSet = InvalidatedSet<Directly, ModuleDependencyGraph.Node>

Sources/SwiftDriver/IncrementalCompilation/IncrementalCompilationState.swift

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,6 @@ extension Diagnostic.Message {
182182
"output file map has no master dependencies entry (\"\(FileType.swiftDeps)\" under \"\")"
183183
)
184184
}
185-
fileprivate static func remark_disabling_incremental_build(because why: String) -> Diagnostic.Message {
186-
return .remark("Disabling incremental build: \(why)")
187-
}
188185

189186
static let remarkDisabled = Diagnostic.Message.remark_incremental_compilation_has_been_disabled
190187

@@ -202,13 +199,6 @@ extension Diagnostic.Message {
202199
}
203200

204201

205-
// MARK: - Scheduling the first wave, i.e. the mandatory pre- and compile jobs
206-
207-
extension IncrementalCompilationState {
208-
209-
210-
}
211-
212202
// MARK: - Scheduling the 2nd wave
213203
extension IncrementalCompilationState {
214204
/// Remember a job (group) that is before a compile or a compile itself.
@@ -259,13 +249,13 @@ extension IncrementalCompilationState {
259249
}
260250

261251
private func collectInputsInvalidated(byCompiling input: TypedVirtualPath)
262-
-> Set<TypedVirtualPath> {
252+
-> TransitivelyInvalidatedInputSet {
263253
if let found = moduleDependencyGraph.collectInputsRequiringCompilation(byCompiling: input) {
264254
return found
265255
}
266256
self.reporter?.report(
267257
"Failed to read some dependencies source; compiling everything", input)
268-
return Set<TypedVirtualPath>(skippedCompileGroups.keys)
258+
return TransitivelyInvalidatedInputSet(skippedCompileGroups.keys)
269259
}
270260

271261
/// Find the jobs that now must be run that were not originally known to be needed.

Sources/SwiftDriver/IncrementalCompilation/InitialStateComputer.swift

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ extension IncrementalCompilationState.InitialStateComputer {
116116
/// For inputs with swiftDeps in OFM, but no readable file, puts input in graph map, but no nodes in graph:
117117
/// caller must ensure scheduling of those
118118
private func computeGraphAndInputsInvalidatedByExternals()
119-
-> (ModuleDependencyGraph, Set<TypedVirtualPath>)? {
119+
-> (ModuleDependencyGraph, TransitivelyInvalidatedInputSet)? {
120120
precondition(sourceFiles.disappeared.isEmpty,
121121
"Would have to remove nodes from the graph if reading prior")
122122
if readPriorsFromModuleDependencyGraph {
@@ -128,7 +128,7 @@ extension IncrementalCompilationState.InitialStateComputer {
128128
}
129129

130130
private func readPriorGraphAndCollectInputsInvalidatedByChangedOrAddedExternals(
131-
) -> (ModuleDependencyGraph, Set<TypedVirtualPath>)?
131+
) -> (ModuleDependencyGraph, TransitivelyInvalidatedInputSet)?
132132
{
133133
let dependencyGraphPath = buildRecordInfo.dependencyGraphPath
134134
let graphIfPresent: ModuleDependencyGraph?
@@ -152,8 +152,10 @@ extension IncrementalCompilationState.InitialStateComputer {
152152

153153
// Any externals not already in graph must be additions which should trigger
154154
// recompilation. Thus, `ChangedOrAdded`.
155-
let nodesInvalidatedByExternals = graph.collectNodesInvalidatedByChangedOrAddedExternals()
156-
let inputsInvalidatedByExternals = graph.collectInputsUsingTransitivelyInvalidated(nodes: nodesInvalidatedByExternals)
155+
let nodesDirectlyInvalidatedByExternals = graph.collectNodesInvalidatedByChangedOrAddedExternals()
156+
// Wait till the last minute to do the transitive closure as an optimization.
157+
let inputsInvalidatedByExternals = graph.collectInputsUsingInvalidated(
158+
nodes: nodesDirectlyInvalidatedByExternals)
157159
return (graph, inputsInvalidatedByExternals)
158160
}
159161

@@ -165,17 +167,15 @@ extension IncrementalCompilationState.InitialStateComputer {
165167
/// For externalDependencies, puts then in graph.fingerprintedExternalDependencies, but otherwise
166168
/// does nothing special.
167169
private func buildInitialGraphFromSwiftDepsAndCollectInputsInvalidatedByChangedExternals(
168-
) -> (ModuleDependencyGraph, Set<TypedVirtualPath>)?
170+
) -> (ModuleDependencyGraph, TransitivelyInvalidatedInputSet)?
169171
{
170-
let graph = ModuleDependencyGraph(self)
172+
let graph = ModuleDependencyGraph(self, .buildingWithoutAPrior)
171173
assert(outputFileMap.onlySourceFilesHaveSwiftDeps())
172174
guard graph.populateInputDependencySourceMap() else {
173175
return nil
174176
}
175177

176-
// Every external will be an addition to the graph, but may not cause
177-
// a recompile, so includeAddedExternals is false.
178-
var inputsInvalidatedByChangedExternals = Set<TypedVirtualPath>()
178+
var inputsInvalidatedByChangedExternals = TransitivelyInvalidatedInputSet()
179179
for input in sourceFiles.currentInOrder {
180180
guard let invalidatedInputs = graph.collectInputsRequiringCompilationFromExternalsFoundByCompiling(input: input)
181181
else {
@@ -195,7 +195,7 @@ extension IncrementalCompilationState.InitialStateComputer {
195195
/// listed in fingerprintExternalDependencies.
196196
private func computeInputsAndGroups(
197197
_ moduleDependencyGraph: ModuleDependencyGraph,
198-
_ inputsInvalidatedByExternals: Set<TypedVirtualPath>,
198+
_ inputsInvalidatedByExternals: TransitivelyInvalidatedInputSet,
199199
batchJobFormer: inout Driver
200200
) throws -> (skippedCompileGroups: [TypedVirtualPath: CompileJobGroup],
201201
mandatoryJobsInOrder: [Job])
@@ -215,9 +215,13 @@ extension IncrementalCompilationState.InitialStateComputer {
215215
batchJobFormer.formBatchedJobs(
216216
mandatoryCompileGroupsInOrder.flatMap {$0.allJobs()},
217217
showJobLifecycle: showJobLifecycle)
218+
219+
moduleDependencyGraph.phase = .buildingAfterEachCompilation
218220
return (skippedCompileGroups: [:],
219221
mandatoryJobsInOrder: mandatoryJobsInOrder)
220222
}
223+
moduleDependencyGraph.phase = .updatingAfterCompilation
224+
221225

222226
let skippedInputs = computeSkippedCompilationInputs(
223227
inputsInvalidatedByExternals: inputsInvalidatedByExternals,
@@ -245,7 +249,7 @@ extension IncrementalCompilationState.InitialStateComputer {
245249

246250
/// Figure out which compilation inputs are *not* mandatory
247251
private func computeSkippedCompilationInputs(
248-
inputsInvalidatedByExternals: Set<TypedVirtualPath>,
252+
inputsInvalidatedByExternals: TransitivelyInvalidatedInputSet,
249253
_ moduleDependencyGraph: ModuleDependencyGraph,
250254
_ buildRecord: BuildRecord
251255
) -> Set<TypedVirtualPath> {
@@ -281,7 +285,7 @@ extension IncrementalCompilationState.InitialStateComputer {
281285
// as each first wave job finished.
282286
let speculativeInputs = collectInputsToBeSpeculativelyRecompiled(
283287
changedInputs: changedInputs,
284-
externalDependents: Array(inputsInvalidatedByExternals),
288+
externalDependents: inputsInvalidatedByExternals,
285289
inputsMissingOutputs: Set(inputsMissingOutputs),
286290
moduleDependencyGraph)
287291
.subtracting(definitelyRequiredInputs)
@@ -367,28 +371,28 @@ extension IncrementalCompilationState.InitialStateComputer {
367371
/// before the whole frontend job finished.
368372
private func collectInputsToBeSpeculativelyRecompiled(
369373
changedInputs: [ChangedInput],
370-
externalDependents: [TypedVirtualPath],
374+
externalDependents: TransitivelyInvalidatedInputSet,
371375
inputsMissingOutputs: Set<TypedVirtualPath>,
372376
_ moduleDependencyGraph: ModuleDependencyGraph
373377
) -> Set<TypedVirtualPath> {
374378
let cascadingChangedInputs = computeCascadingChangedInputs(
375379
from: changedInputs,
376380
inputsMissingOutputs: inputsMissingOutputs)
377-
let cascadingExternalDependents = alwaysRebuildDependents ? externalDependents : []
378-
// Collect the dependent files to speculatively schedule
379-
var dependentFiles = Set<TypedVirtualPath>()
380-
let cascadingFileSet = Set(cascadingChangedInputs).union(cascadingExternalDependents)
381-
for cascadingFile in cascadingFileSet {
382-
let dependentsOfOneFile = moduleDependencyGraph
383-
.collectInputsTransitivelyInvalidatedBy(input: cascadingFile)
384-
for dep in dependentsOfOneFile where !cascadingFileSet.contains(dep) {
385-
if dependentFiles.insert(dep).0 {
381+
382+
var inputsToBeCertainlyRecompiled = alwaysRebuildDependents ? externalDependents : TransitivelyInvalidatedInputSet()
383+
inputsToBeCertainlyRecompiled.formUnion(cascadingChangedInputs)
384+
385+
return inputsToBeCertainlyRecompiled.reduce(into: Set()) {
386+
speculativelyRecompiledInputs, certainlyRecompiledInput in
387+
let speculativeDependents = moduleDependencyGraph.collectInputsInvalidatedBy(input: certainlyRecompiledInput)
388+
for speculativeDependent in speculativeDependents
389+
where !inputsToBeCertainlyRecompiled.contains(speculativeDependent) {
390+
if speculativelyRecompiledInputs.insert(speculativeDependent).inserted {
386391
reporter?.report(
387-
"Immediately scheduling dependent on \(cascadingFile.file.basename)", dep)
392+
"Immediately scheduling dependent on \(certainlyRecompiledInput.file.basename)", speculativeDependent)
388393
}
389394
}
390395
}
391-
return dependentFiles
392396
}
393397

394398
// Collect the files that will be compiled whose dependents should be schedule

0 commit comments

Comments
 (0)