[sourcekit] Synchronize cursor-info requests on generated interfaces

Cursor info requires access to the underlying AST, which is not
thread-safe. This manifest as crashes when performing concurrent
cursor-info requests on the same generated interface. We already
prevented concurrent cursor-infos on regular Swift files by using the
ASTManager, but generated interfaces use the InterfaceGenContext which
may use either an ASTUnit or its own internal CompilerInstance.

rdar://problem/27311624
This commit is contained in:
Ben Langmuir
2016-07-13 16:22:04 -07:00
parent 8e0ff518d1
commit 18be066651
6 changed files with 76 additions and 18 deletions

View File

@@ -79,6 +79,10 @@ public:
SourceTextInfo Info;
// This is the non-typechecked AST for the generated interface source.
CompilerInstance TextCI;
// Syncronize access to the embedded compiler instance (if we don't have an
// ASTUnit).
WorkQueue Queue{WorkQueue::Dequeuing::Serial,
"sourcekit.swift.InterfaceGenContext"};
};
typedef SwiftInterfaceGenContext::Implementation::TextRange TextRange;
@@ -498,6 +502,14 @@ void SwiftInterfaceGenContext::reportEditorInfo(EditorConsumer &Consumer) const
Consumer.finished();
}
void SwiftInterfaceGenContext::accessASTAsync(std::function<void()> Fn) {
if (Impl.AstUnit) {
Impl.AstUnit->performAsync(std::move(Fn));
} else {
Impl.Queue.dispatch(std::move(Fn));
}
}
SwiftInterfaceGenContext::ResolvedEntity
SwiftInterfaceGenContext::resolveEntityForOffset(unsigned Offset) const {
// Search among the references.
@@ -633,8 +645,10 @@ void SwiftLangSupport::editorOpenInterface(EditorConsumer &Consumer,
return;
}
IFaceGenContexts.set(Name, IFaceGenRef);
IFaceGenRef->reportEditorInfo(Consumer);
// reportEditorInfo requires exclusive access to the AST, so don't add this
// to the service cache until it has returned.
IFaceGenContexts.set(Name, IFaceGenRef);
}
class PrimaryFileInterfaceConsumer : public SwiftASTConsumer {
@@ -740,8 +754,10 @@ void SwiftLangSupport::editorOpenHeaderInterface(EditorConsumer &Consumer,
return;
}
IFaceGenContexts.set(Name, IFaceGenRef);
IFaceGenRef->reportEditorInfo(Consumer);
// reportEditorInfo requires exclusive access to the AST, so don't add this
// to the service cache until it has returned.
IFaceGenContexts.set(Name, IFaceGenRef);
}
void SwiftLangSupport::findInterfaceDocument(StringRef ModuleName,