@@ -451,6 +451,9 @@ class ASTBuildOperation
451
451
// / consumer, removes it from the \c Consumers severed by this build operation
452
452
// / and, if no consumers are left, cancels the AST build of this operation.
453
453
void requestConsumerCancellation (SwiftASTConsumerRef Consumer);
454
+
455
+ // / Cancels all consumers for the given operation.
456
+ void cancelAllConsumers ();
454
457
};
455
458
456
459
using ASTBuildOperationRef = std::shared_ptr<ASTBuildOperation>;
@@ -517,6 +520,9 @@ class ASTProducer : public std::enable_shared_from_this<ASTProducer> {
517
520
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem,
518
521
SwiftASTManagerRef Mgr);
519
522
523
+ // / Cancel all currently running build operations.
524
+ void cancelAllBuilds ();
525
+
520
526
size_t getMemoryCost () const {
521
527
size_t Cost = sizeof (*this );
522
528
for (auto &BuildOp : BuildOperations) {
@@ -631,7 +637,16 @@ struct SwiftASTManager::Implementation {
631
637
});
632
638
}
633
639
634
- ASTProducerRef getASTProducer (SwiftInvocationRef InvokRef);
640
+ // / Retrieve the ASTProducer for a given invocation, creating one if needed.
641
+ ASTProducerRef getOrCreateASTProducer (SwiftInvocationRef InvokRef);
642
+
643
+ // / Retrieve the ASTProducer for a given invocation, returning \c nullopt if
644
+ // / not present.
645
+ std::optional<ASTProducerRef> getASTProducer (SwiftInvocationRef Invok);
646
+
647
+ // / Updates the cache entry to account for any changes to the ASTProducer
648
+ // / for the given invocation.
649
+ void updateASTProducer (SwiftInvocationRef Invok);
635
650
636
651
FileContent
637
652
getFileContent (StringRef FilePath, bool IsPrimary,
@@ -780,7 +795,7 @@ void SwiftASTManager::processASTAsync(
780
795
const void *OncePerASTToken, SourceKitCancellationToken CancellationToken,
781
796
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fileSystem) {
782
797
assert (fileSystem);
783
- ASTProducerRef Producer = Impl.getASTProducer (InvokRef);
798
+ ASTProducerRef Producer = Impl.getOrCreateASTProducer (InvokRef);
784
799
785
800
Impl.cleanDeletedConsumers ();
786
801
{
@@ -816,12 +831,39 @@ void SwiftASTManager::processASTAsync(
816
831
});
817
832
}
818
833
834
+ std::optional<ASTProducerRef>
835
+ SwiftASTManager::Implementation::getASTProducer (SwiftInvocationRef Invok) {
836
+ llvm::sys::ScopedLock L (CacheMtx);
837
+ return ASTCache.get (Invok->Impl .Key );
838
+ }
839
+
840
+ void SwiftASTManager::Implementation::updateASTProducer (
841
+ SwiftInvocationRef Invok) {
842
+ llvm::sys::ScopedLock L (CacheMtx);
843
+
844
+ // Get and set the producer to update its cost in the cache. If we don't
845
+ // have a value, then this is a race where we've removed the cached AST, but
846
+ // still have a build waiting to complete after cancellation, we don't need
847
+ // to do anything in that case.
848
+ if (auto Producer = ASTCache.get (Invok->Impl .Key ))
849
+ ASTCache.set (Invok->Impl .Key , *Producer);
850
+ }
851
+
819
852
void SwiftASTManager::removeCachedAST (SwiftInvocationRef Invok) {
853
+ llvm::sys::ScopedLock L (Impl.CacheMtx );
820
854
Impl.ASTCache .remove (Invok->Impl .Key );
821
855
}
822
856
823
- ASTProducerRef
824
- SwiftASTManager::Implementation::getASTProducer (SwiftInvocationRef InvokRef) {
857
+ void SwiftASTManager::cancelBuildsForCachedAST (SwiftInvocationRef Invok) {
858
+ auto Result = Impl.getASTProducer (Invok);
859
+ if (!Result)
860
+ return ;
861
+
862
+ (*Result)->cancelAllBuilds ();
863
+ }
864
+
865
+ ASTProducerRef SwiftASTManager::Implementation::getOrCreateASTProducer (
866
+ SwiftInvocationRef InvokRef) {
825
867
llvm::sys::ScopedLock L (CacheMtx);
826
868
std::optional<ASTProducerRef> OptProducer = ASTCache.get (InvokRef->Impl .Key );
827
869
if (OptProducer.has_value ())
@@ -978,6 +1020,24 @@ void ASTBuildOperation::requestConsumerCancellation(
978
1020
});
979
1021
}
980
1022
1023
+ void ASTBuildOperation::cancelAllConsumers () {
1024
+ if (isFinished ())
1025
+ return ;
1026
+
1027
+ llvm::sys::ScopedLock L (ConsumersAndResultMtx);
1028
+ CancellationFlag->store (true , std::memory_order_relaxed);
1029
+
1030
+ // Take the consumers, and notify them of the cancellation.
1031
+ decltype (this ->Consumers ) Consumers;
1032
+ std::swap (Consumers, this ->Consumers );
1033
+
1034
+ ASTManager->Impl .ConsumerNotificationQueue .dispatch (
1035
+ [Consumers = std::move (Consumers)] {
1036
+ for (auto &Consumer : Consumers)
1037
+ Consumer->cancelled ();
1038
+ });
1039
+ }
1040
+
981
1041
static void collectModuleDependencies (ModuleDecl *TopMod,
982
1042
llvm::SmallPtrSetImpl<ModuleDecl *> &Visited,
983
1043
SmallVectorImpl<std::string> &Filenames) {
@@ -1302,6 +1362,15 @@ ASTBuildOperationRef ASTProducer::getBuildOperationForConsumer(
1302
1362
return LatestUsableOp;
1303
1363
}
1304
1364
1365
+ void ASTProducer::cancelAllBuilds () {
1366
+ // Cancel all build operations, cleanup will happen when each operation
1367
+ // terminates.
1368
+ BuildOperationsQueue.dispatch ([This = shared_from_this ()] {
1369
+ for (auto &BuildOp : This->BuildOperations )
1370
+ BuildOp->cancelAllConsumers ();
1371
+ });
1372
+ }
1373
+
1305
1374
void ASTProducer::enqueueConsumer (
1306
1375
SwiftASTConsumerRef Consumer,
1307
1376
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem,
@@ -1342,7 +1411,7 @@ void ASTProducer::enqueueConsumer(
1342
1411
[This]() { This->cleanBuildOperations (); });
1343
1412
// Re-register the object with the cache to update its memory
1344
1413
// cost.
1345
- Mgr->Impl .ASTCache . set (This->InvokRef -> Impl . Key , This );
1414
+ Mgr->Impl .updateASTProducer (This->InvokRef );
1346
1415
}
1347
1416
};
1348
1417
0 commit comments