1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
|
//===--------------- IncrementalCompilation.swift - Incremental -----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import Dispatch
import SwiftOptions
/// An instance of `IncrementalCompilationState` encapsulates the data necessary
/// to make incremental build scheduling decisions.
///
/// The primary form of interaction with the incremental compilation state is
/// using it as an oracle to discover the jobs to execute as the incremental
/// build progresses. After a job completes, call
/// `protectedState.collectJobsDiscoveredToBeNeededAfterFinishing(job:)`
/// to both update the incremental state and receive an array of jobs that
/// need to be executed in response.
///
/// Jobs become "unstuck" as their inputs become available, or may be discovered
/// by this class as fresh dependency information is integrated.
///
/// Threading Considerations
/// ========================
///
/// The public API surface of this class is thread safe, but not re-entrant.
/// FIXME: This should be an actor.
public final class IncrementalCompilationState {
/// State needed for incremental compilation that can change during a run and must be protected from
/// concurrent mutation and access. Concurrent accesses are OK.
private var protectedState: ProtectedState
/// All of the pre-compile or compilation job (groups) known to be required (i.e. in 1st wave).
/// Already batched, and in order of input files.
public let mandatoryJobsInOrder: [Job]
/// Jobs to run *after* the last compile, for instance, link-editing.
public let jobsAfterCompiles: [Job]
public let info: IncrementalCompilationState.IncrementalDependencyAndInputSetup
internal let upToDateInterModuleDependencyGraph: InterModuleDependencyGraph?
// MARK: - Creating IncrementalCompilationState
/// Return nil if not compiling incrementally
internal init(
driver: inout Driver,
jobsInPhases: JobsInPhases,
initialState: InitialStateForPlanning
) throws {
let reporter = initialState.incrementalOptions.contains(.showIncremental)
? Reporter(diagnosticEngine: driver.diagnosticEngine,
outputFileMap: driver.outputFileMap)
: nil
reporter?.reportOnIncrementalImports(
initialState.incrementalOptions.contains(.enableCrossModuleIncrementalBuild))
let firstWave = try FirstWaveComputer(
initialState: initialState,
jobsInPhases: jobsInPhases,
driver: driver,
interModuleDependencyGraph: driver.interModuleDependencyGraph,
reporter: reporter)
.compute(batchJobFormer: &driver)
self.info = initialState.graph.info
self.upToDateInterModuleDependencyGraph = driver.interModuleDependencyGraph
self.protectedState = ProtectedState(
skippedCompileGroups: firstWave.initiallySkippedCompileGroups,
initialState.graph,
jobsInPhases.allJobs.first(where: {$0.kind == .generatePCH}),
&driver)
self.mandatoryJobsInOrder = firstWave.mandatoryJobsInOrder
self.jobsAfterCompiles = jobsInPhases.afterCompiles
}
/// Allow concurrent access to while preventing mutation of ``IncrementalCompilationState/protectedState``
public func blockingConcurrentMutationToProtectedState<R>(
_ fn: (ProtectedState) throws -> R
) rethrows -> R {
try blockingConcurrentMutation {try fn(protectedState)}
}
/// Block any other threads from doing anything to or observing `protectedState`.
public func blockingConcurrentAccessOrMutationToProtectedState<R>(
_ fn: (inout ProtectedState) throws -> R
) rethrows -> R {
try blockingConcurrentAccessOrMutation {
try fn(&protectedState)
}
}
}
extension IncrementalCompilationState: IncrementalCompilationSynchronizer {
public var incrementalCompilationQueue: DispatchQueue {
info.incrementalCompilationQueue
}
}
fileprivate extension IncrementalCompilationState.Reporter {
func reportOnIncrementalImports(_ enabled: Bool) {
report(
"\(enabled ? "Enabling" : "Disabling") incremental cross-module building")
}
}
|