Commit Graph

30 Commits

Author SHA1 Message Date
Steven Wu
bb224a3598 [FineGrainedDeps] Fix the non-deterministic .swiftdeps output
Fix the non-deterministic .swiftdeps output. In contrary to the comments
in the `FineGrainedDependencies.h`, the non-determinism is not because
of the use of unordered_* data structure there. Those data structures
are not traversed so removing all the unused traversing methods to avoid
the confusion.

The true reason for the non-determinism is all the DenseSet in the
Evaluator dependency tracking, that causes the FineGrainedDependencies
to see arbitrary ordering. Use `SetVector` instead to keep track of the
insertion order to make dependency output to be deterministic.

rdar://104876331
2025-03-12 11:14:37 -07:00
Slava Pestov
797813fda4 Frontend: Don't record request references in WMO builds
Part of <rdar://problem/72906325>.
2021-01-07 23:52:55 -05:00
Slava Pestov
0bfa868978 AST: Per-request dependency maps
Just as with the result cache, instead of a single DenseMap with
type-erased AnyRequest keys, we can use per-request maps for a
nice performance improvement.
2021-01-05 17:56:39 -05:00
Slava Pestov
f6cd8f2696 AST: Convert some methods on DependencyRecorder to templates
... instead of passing around an ActiveRequest.
2021-01-05 17:56:38 -05:00
Slava Pestov
0314f7314a AST: Use a SmallDenseSet for active request references 2021-01-05 17:56:38 -05:00
Slava Pestov
e675bee26c AST: Split off DependencyCollector.h from EvaluatorDependencies.h
Also remove some unnecessary #includes from DependencyCollector.h,
which necessitated adding #includes in various other files.
2020-12-23 00:00:25 -05:00
Slava Pestov
527ffb5645 AST: Add some comments to EvaluatorDependencies.h 2020-12-22 23:07:06 -05:00
Slava Pestov
161d832140 AST: Refactor request evaluator dependency tracking a bit
Other than simplifying some code, the big improvement here is
that we 'freeze' the reference dependencies for a request down
to a simple vector. We only use a DenseSet to store dependencies
of active requests.
2020-12-22 16:12:04 -05:00
Robert Widmann
1b7c713820 [NFC] Only Register Primaries As Dependency Sources
Now that the top-level source file is the only dependency source that
matters, the only case that matters is when request evaluation enters
a primary file. For non-primaries, there will be no corresponding
swiftdeps file to emit references into, so we're just wasting time and
memory keeping track of anything that happens there.

This is only possible after we removed cascading dependencies because
unqualified lookups had to be charged to the files they originated in.
Now, we charge those lookups to the primary that initiated the request.
2020-09-21 10:42:33 -06:00
Robert Widmann
e37b378d4d Remove DependencyRecorder::Mode 2020-09-21 10:42:33 -06:00
Robert Widmann
8c913e385e Remove LegacyCascadingDependencies 2020-09-21 10:42:33 -06:00
Robert Widmann
9e7964f4a5 Remove Reference::cascades 2020-09-21 10:37:42 -06:00
Robert Widmann
7fb448071c Remove DependencyScope 2020-09-21 10:37:41 -06:00
Robert Widmann
3dd74c1c07 Remove evaluator::getScopeForAccessLevel 2020-09-21 10:37:41 -06:00
Robert Widmann
99ab7db18d [Gardening] Document DependencyRecorder and DependencyCollector 2020-06-10 11:11:22 -07:00
Robert Widmann
3228a5903a [NFC] Rename Flags
-enable-experimental-private-intransitive-dependencies -> -enable-direct-intramodule-dependencies
-disable-experimental-private-intransitive-dependencies -> -disable-direct-intramodule-dependencies

While we're here, rename DependencyCollector::Mode's constants and clean
up the documentation.
2020-06-09 16:00:59 -07:00
Robert Widmann
975ff757bc Perform The Dependency Unioning Step During Replay
In order for private dependencies to be completely correct, it must perform the name lookup unioning step when a cached request is replayed - not just when lookups are first performed. In order to reduce the overhead of this union operation, it is not necessary to walk the entire active request stack, just walk to the nearest cached request in the stack and union into that. When it is popped, its replay step will itself union into the next cached request.

To see why, consider a request graph:

A* -> B -> C*
         |
          -> D*

where A, C, and D are cached.

If a caller were to force C and D, then force A independenty, today we would *only* replay the names looked up by C and D the first time A was evaluated. That is, subsequent evaluations of A do not replay the correct set of names. If we were to perform the union step during replay as well, requests that force A would also see C and D’s lookups.

Without this, callers that force requests like the DeclChecker have to be wary of the way they force the interface type request so other files see the right name sets.

rdar://64008262
2020-06-05 11:42:29 -07:00
Robert Widmann
14ade93594 Fix getActiveDependencySourceOrNull For Private Dependencies
Restore the behavior here of only looking at the topmost dependency source object that was lost when the referenced name tracker was removed.

Oops.
2020-06-04 18:28:43 -07:00
Robert Widmann
9a88bef29d Start Keeping Track of Files With Dependencies in the DependencyCollector
This completely obviates the need for the referenced name trackers

rdar://59076016
2020-05-21 18:54:14 -07:00
Robert Widmann
21e6bad4fc [Gardening] Add an alias for a commonly-used set type 2020-05-21 18:48:47 -07:00
Robert Widmann
3e76ea74f7 Add the "cascading" bit to Reference
We'll be able to delete this once we cut over to private dependencies
2020-05-21 18:46:08 -07:00
Robert Widmann
d5d3ff9e2d Fixup Tombstone Reference Kind
Have to find a way to hide these implementation details from clients if possible...
2020-05-21 18:44:19 -07:00
Robert Widmann
0a7929e80f Refine Naive Dependency Collection Algorithm
Split off the notion of "recording" dependencies from the notion of
"collecting" dependencies. This corrects an oversight in the previous
design where dependency replay and recording were actually not "free" in
WMO where we actually never track dependencies. This architecture also
lays the groundwork for the removal of the referenced name trackers.

The algorithm builds upon the infrastructure for dependency sources and
sinks laid down during the cut over to request-based dependency tracking
in #30723.

The idea of the naive algorithm is this:

For a chain of requests A -> B* -> C -> D* -> ... -> L where L is a lookup
request and all starred requests are cached, once L writes into the
dependency collector, the active stack is walked and at each cache-point
the results of dependency collection are associated with the request
itself (in this example, B* and D* have all the names L found associated
with them). Subsequent evaluations of these cached requests (B* and D*
et al) will then *replay* the previous lookup results from L into the
active referenced name tracker. One complication is, suppose the
evaluation of a cached request involves multiple downstream name
lookups. More concretely, suppose we have the following request trace:

A* -> B -> L
      |
       -> C -> L
          |
           -> D -> L
              |
               -> ...

Then A* must see the union of the results of each L. If this reminds
anyone of a union-find, that is no accident! A persistent union-find
a la Conchon and Filliatre is probably in order to help bring down peak
heap usage...
2020-05-20 16:08:05 -07:00
Robert Widmann
115bd2855b Naive Dependency Replay
Finish off private intransitive dependencies with an implementation of
dependency replay.

For the sake of illustration, imagine a chain of requests

A -> B -> C -> ...

Supposing each request is never cached, then every invocation of the
compiler with the same inputs will always kick off the exact same set of
requests. For the purposes of dependency tracking, that also means every
single lookup request will run without issue, and all dependencies will
be accurately reported. But we live in a world with cached requests.
Suppose request B* is cached. The first time we encounter that request,
its evaluation order looks identical:

A -> B* -> C -> ...

If we are in a mode that compiles single primaries, this is not
a problem because every request graph will look like this.
But if we are in a mode where we are compiling multiple primaries, then
subsequent request graphs will *actually* hit the cache and never
execute request C or any of its dependent computations!

A -> B*

Supposing C was a lookup request, that means the name(s) looked up
downstream of B* will *never* be recorded in the referenced name tracker
which can lead to miscompilation. Note that this is not a problem
inherent to the design of the request evaluator - caches in the compiler
have *always* hidden dependent lookups. In fact, the request evaluator
provides us our first opportunity to resolve this correctness bug!
2020-05-20 10:41:19 -07:00
Saleem Abdulrasool
09975d1253 sprinkle llvm_unreachable for covered switches (NFC)
Annotate the covered switches with `llvm_unreachable` to avoid the MSVC
warning which does not recognise the covered switches.  This allows us
to avoid a spew of warnings.
2020-05-07 11:05:35 -07:00
Robert Widmann
b06211eac4 Initial plumbing for private dependencies
Add a mode bit to the dependency collector that respects the frontend flag in the previous commit.

Notably, we now write over the dependency files at the end of the compiler pipeline when this flag is on so that dependency from SILGen and IRGen are properly written to disk.
2020-05-05 13:48:25 -07:00
Robert Widmann
7a724b1477 [NFC] Extract Dependency Registration to DependencyCollector
Define a new type DependencyCollector that abstracts over the
incremental dependency gathering logic. This will insulate the
request-based name tracking code from future work on private,
intransitive dependencies.
2020-04-22 21:01:20 -07:00
Robert Widmann
ee723cd953 Document Some Whys
* Document a number of legacy conditions and edge cases

* Add lexicon definitions for "dependency source", "dependency sink",
"cascading dependency" and "private dependency"
2020-03-31 16:19:13 -07:00
Robert Widmann
8c69814f5c Define Dependency Sinks
Convert most of the name lookup requests and a few other ancillary typechecking requests into dependency sinks.

Some requests are also combined sinks and sources in order to emulate the current scheme, which performs scope changes based on lookup flags. This is generally undesirable, since it means those requests cannot immediately be generalized to a purely context-based scheme because they depend on some client-provided entropy source. In particular, the few callers that are providing the "known private" name lookup flag need to be converted to perform lookups in the appropriate private context.

Clients that are passing "no known dependency" are currently considered universally incorrect and are outside the scope of the compatibility guarantees. This means that request-based dependency tracking registers strictly more edges than manual dependency tracking. It also means that once we fixup the clients that are passing "known private", we can completely remove these name lookup flags.

Finally, some tests had to change to accomodate the new scheme. Currently, we go out of our way to register a dependency edge for extensions that declare protocol conformances. However, we were also asserting in at least one test that extensions without protocol conformances weren't registering dependency edges. This is blatantly incorrect and has been undone now that the request-based scheme is automatically registering this edge.
2020-03-31 16:16:53 -07:00
Robert Widmann
3f8f3a89cb Teach the Evaluator about Incremental Dependencies
Formalize DependencyScope, DependencySource, and the incremental dependency stack.

Also specialize SimpleRequest to formalize dependency sources and dependency sinks. This allows the evaluator's internal entrypoints to specalize away the incremental dependency tracking infrastructure if a request is not actually dependency-relevant.
2020-03-31 15:40:04 -07:00