File: IncrementalCompilationState.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (113 lines) | stat: -rw-r--r-- 4,429 bytes parent folder | download
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")
  }
}