<commit_before>//===--------------- 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 TSCBasic
import Foundation
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
/// `IncrementalCompilationState.collectJobsDiscoveredToBeNeededAfterFinishing(job:)`
/// to both update the incremental state and recieve 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 {

  /// The oracle for deciding what depends on what. Applies to this whole module.
  @_spi(Testing) public let moduleDependencyGraph: ModuleDependencyGraph

  /// If non-null outputs information for `-driver-show-incremental` for input path
  public let reporter: Reporter?

  /// 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]

  /// Can compare input mod times against this.
  private let buildStartTime: Date

  /// In order to decide while postCompile jobs to run, need to compare their outputs against the build time
  private let buildEndTime: Date

  private let fileSystem: FileSystem

  /// A  high-priority confinement queue that must be used to protect the incremental compilation state.
  private let confinementQueue: DispatchQueue = DispatchQueue(label: "com.apple.swift-driver.incremental-compilation-state", qos: .userInteractive)

  /// Sadly, has to be `var` for formBatchedJobs
  ///
  /// After initialization, mutating accesses to the driver must be protected by
  /// the confinement queue.
  private var driver: Driver

  /// Keyed by primary input. As required compilations are discovered after the first wave, these shrink.
  ///
  /// This state is modified during the incremental build. All accesses must
  /// be protected by the confinement queue.
  private var skippedCompileGroups = [TypedVirtualPath: CompileJobGroup]()

  // MARK: - Creating IncrementalCompilationState
  /// Return nil if not compiling incrementally
  internal init(
    driver: inout Driver,
    jobsInPhases: JobsInPhases,
    initialState: InitialStateForPlanning
  ) throws {
    if initialState.incrementalOptions.contains(.showIncremental) {
      self.reporter = Reporter(diagnosticEngine: driver.diagnosticEngine,
                               outputFileMap: driver.outputFileMap)
    } else {
      self.reporter = nil
    }

    let enablingOrDisabling =
      initialState.incrementalOptions.contains(.enableCrossModuleIncrementalBuild)
      ? "Enabling"
      : "Disabling"
    reporter?.report(
      "\(enablingOrDisabling) incremental cross-module building")

    let firstWave =
      try FirstWaveComputer(initialState: initialState, jobsInPhases: jobsInPhases,
                            driver: driver, reporter: reporter).compute(batchJobFormer: &driver)

    self.skippedCompileGroups = firstWave.initiallySkippedCompileGroups
    self.mandatoryJobsInOrder = firstWave.mandatoryJobsInOrder
    self.jobsAfterCompiles = jobsInPhases.afterCompiles
    self.moduleDependencyGraph = initialState.graph
    self.buildStartTime = initialState.buildStartTime
    self.buildEndTime = initialState.buildEndTime
    self.fileSystem = driver.fileSystem
    self.driver = driver
  }
}

// MARK: - Initial State
extension IncrementalCompilationState {
  /// The initial state of an incremental compilation plan that consists of the module dependency graph
  /// and computes which inputs were invalidated by external changes.
  /// This set of incremental information is used during planning - job-generation, and is computed early.
  @_spi(Testing) public struct InitialStateForPlanning {
    /// The dependency graph.
    ///
    /// In a status quo build, the dependency graph is derived from the state
    /// of the build record, which points to all files built in the prior build.
    /// When this information is combined with the output file map, swiftdeps
    /// files can be located and loaded into the graph.
    ///
    /// In a cross-module build, the dependency graph is derived from prior
    /// state that is serialized alongside the build record.<commit_msg>remove unused instance variables<commit_after>//===--------------- 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 TSCBasic
import Foundation
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
/// `IncrementalCompilationState.collectJobsDiscoveredToBeNeededAfterFinishing(job:)`
/// to both update the incremental state and recieve 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 {

  /// The oracle for deciding what depends on what. Applies to this whole module.
  @_spi(Testing) public let moduleDependencyGraph: ModuleDependencyGraph

  /// If non-null outputs information for `-driver-show-incremental` for input path
  public let reporter: Reporter?

  /// 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]

  private let fileSystem: FileSystem

  /// A  high-priority confinement queue that must be used to protect the incremental compilation state.
  private let confinementQueue: DispatchQueue = DispatchQueue(label: "com.apple.swift-driver.incremental-compilation-state", qos: .userInteractive)

  /// Sadly, has to be `var` for formBatchedJobs
  ///
  /// After initialization, mutating accesses to the driver must be protected by
  /// the confinement queue.
  private var driver: Driver

  /// Keyed by primary input. As required compilations are discovered after the first wave, these shrink.
  ///
  /// This state is modified during the incremental build. All accesses must
  /// be protected by the confinement queue.
  private var skippedCompileGroups = [TypedVirtualPath: CompileJobGroup]()

  // MARK: - Creating IncrementalCompilationState
  /// Return nil if not compiling incrementally
  internal init(
    driver: inout Driver,
    jobsInPhases: JobsInPhases,
    initialState: InitialStateForPlanning
  ) throws {
    if initialState.incrementalOptions.contains(.showIncremental) {
      self.reporter = Reporter(diagnosticEngine: driver.diagnosticEngine,
                               outputFileMap: driver.outputFileMap)
    } else {
      self.reporter = nil
    }

    let enablingOrDisabling =
      initialState.incrementalOptions.contains(.enableCrossModuleIncrementalBuild)
      ? "Enabling"
      : "Disabling"
    reporter?.report(
      "\(enablingOrDisabling) incremental cross-module building")

    let firstWave =
      try FirstWaveComputer(initialState: initialState, jobsInPhases: jobsInPhases,
                            driver: driver, reporter: reporter).compute(batchJobFormer: &driver)

    self.skippedCompileGroups = firstWave.initiallySkippedCompileGroups
    self.mandatoryJobsInOrder = firstWave.mandatoryJobsInOrder
    self.jobsAfterCompiles = jobsInPhases.afterCompiles
    self.moduleDependencyGraph = initialState.graph
    self.fileSystem = driver.fileSystem
    self.driver = driver
  }
}

// MARK: - Initial State
extension IncrementalCompilationState {
  /// The initial state of an incremental compilation plan that consists of the module dependency graph
  /// and computes which inputs were invalidated by external changes.
  /// This set of incremental information is used during planning - job-generation, and is computed early.
  @_spi(Testing) public struct InitialStateForPlanning {
    /// The dependency graph.
    ///
    /// In a status quo build, the dependency graph is derived from the state
    /// of the build record, which points to all files built in the prior build.
    /// When this information is combined with the output file map, swiftdeps
    /// files can be located and loaded into the graph.
    ///
    /// In a cross-module build, the dependency graph is derived from prior
    /// state that is serialized alongside the build record.
{'fraction_non_alphanumeric': 0.10194642513008287, 'fraction_numerical': 0.002119868953555598, 'mean_word_length': 3.141660015961692, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4557890', 'n_tokens_mistral': 2688, 'n_tokens_neox': 2508, 'n_words': 1051}