Skip to content

Commit fc1dac7

Browse files
committed
ObjCMessageTracing: append trace file content atomically to a canonical file location provided by the build environment
To simplify post-processing of these collected ObjC message traces, this PR teaches the compiler to atomically append the content of ObjC message trace to a file location provided by the build environment, instead of emitting multiple files.
1 parent 4a9d20d commit fc1dac7

File tree

2 files changed

+41
-34
lines changed

2 files changed

+41
-34
lines changed

lib/FrontendTool/LoadedModuleTrace.cpp

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -853,16 +853,16 @@ class ObjcMethodReferenceCollector: public SourceEntityWalker {
853853
}
854854
};
855855

856-
static std::optional<int> createObjCMessageTraceFile(const InputFile &input,
857-
ModuleDecl *MD,
858-
std::vector<SourceFile*> &filesToWalk) {
856+
static void createObjCMessageTraceFile(const InputFile &input, ModuleDecl *MD) {
859857
if (input.getLoadedModuleTracePath().empty()) {
860858
// we basically rely on the passing down of module trace file path
861859
// as an indicator that this job needs to emit an ObjC message trace file.
862860
// FIXME: add a separate swift-frontend flag for ObjC message trace path
863861
// specifically.
864-
return {};
862+
return;
865863
}
864+
auto &ctx = MD->getASTContext();
865+
std::vector<SourceFile*> filesToWalk;
866866
for (auto *FU : MD->getFiles()) {
867867
if (auto *SF = dyn_cast<SourceFile>(FU)) {
868868
switch (SF->Kind) {
@@ -880,29 +880,47 @@ static std::optional<int> createObjCMessageTraceFile(const InputFile &input,
880880
}
881881
// No source files to walk, abort.
882882
if (filesToWalk.empty()) {
883-
return {};
883+
return;
884884
}
885885
llvm::SmallString<128> tracePath;
886-
if (const char *P = ::getenv("SWIFT_COMPILER_OBJC_MESSAGE_TRACE_DIRECTORY")) {
887-
StringRef DirPath = P;
888-
llvm::sys::path::append(tracePath, DirPath);
886+
if (const char *P = ::getenv("SWIFT_COMPILER_OBJC_MESSAGE_TRACE_PATH")) {
887+
StringRef FilePath = P;
888+
llvm::sys::path::append(tracePath, FilePath);
889889
} else {
890890
llvm::sys::path::append(tracePath, input.getLoadedModuleTracePath());
891891
llvm::sys::path::remove_filename(tracePath);
892-
llvm::sys::path::append(tracePath, ".SWIFT_FINE_DEPENDENCY_TRACE");
892+
llvm::sys::path::append(tracePath, ".SWIFT_FINE_DEPENDENCY_TRACE.json");
893+
}
894+
// Write output via atomic append.
895+
llvm::vfs::OutputConfig config;
896+
config.setAppend().setAtomicWrite();
897+
auto outputFile = ctx.getOutputBackend().createFile(tracePath, config);
898+
if (!outputFile) {
899+
ctx.Diags.diagnose(SourceLoc(), diag::error_opening_output, tracePath,
900+
toString(outputFile.takeError()));
901+
return;
893902
}
894-
if (!llvm::sys::fs::exists(tracePath)) {
895-
if (llvm::sys::fs::create_directory(tracePath))
896-
return {};
903+
ObjcMethodReferenceCollector collector(MD);
904+
for (auto *SF : filesToWalk) {
905+
collector.setFileBeforeVisiting(SF);
906+
collector.walk(*SF);
907+
}
908+
909+
// print this json line.
910+
std::string stringBuffer;
911+
{
912+
llvm::raw_string_ostream memoryBuffer(stringBuffer);
913+
collector.serializeAsJson(memoryBuffer);
897914
}
898-
SmallString<32> fileName(MD->getNameStr());
899-
fileName.append("-%%%%-%%%%-%%%%.json");
900-
llvm::sys::path::append(tracePath, fileName);
901-
int tmpFD;
902-
if (llvm::sys::fs::createUniqueFile(tracePath.str(), tmpFD, tracePath)) {
903-
return {};
915+
stringBuffer += "\n";
916+
917+
// Write output via atomic append.
918+
*outputFile << stringBuffer;
919+
if (auto err = outputFile->keep()) {
920+
ctx.Diags.diagnose(SourceLoc(), diag::error_opening_output,
921+
tracePath, toString(std::move(err)));
922+
return;
904923
}
905-
return tmpFD;
906924
}
907925

908926
bool swift::emitObjCMessageSendTraceIfNeeded(ModuleDecl *mainModule,
@@ -912,18 +930,7 @@ bool swift::emitObjCMessageSendTraceIfNeeded(ModuleDecl *mainModule,
912930
"We should've already exited earlier if there was an error.");
913931

914932
opts.InputsAndOutputs.forEachInput([&](const InputFile &input) {
915-
std::vector<SourceFile*> filesToWalk;
916-
auto tmpFD = createObjCMessageTraceFile(input, mainModule, filesToWalk);
917-
if (!tmpFD)
918-
return false;
919-
// Write the contents of the buffer.
920-
llvm::raw_fd_ostream out(*tmpFD, /*shouldClose=*/true);
921-
ObjcMethodReferenceCollector collector(mainModule);
922-
for (auto *SF : filesToWalk) {
923-
collector.setFileBeforeVisiting(SF);
924-
collector.walk(*SF);
925-
}
926-
collector.serializeAsJson(out);
933+
createObjCMessageTraceFile(input, mainModule);
927934
return true;
928935
});
929936
return false;

test/IDE/objc_send_collector_1.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
// RUN: %empty-directory(%t/CUSTOM_DIR)
33

44
// RUN: %target-swift-frontend -I %t/lib/swift -typecheck %s %S/Inputs/objc_send_collector_2.swift -module-name main -swift-version 5 -F %S/Inputs/mock-sdk -emit-loaded-module-trace-path %t/.MODULE_TRACE
5-
// RUN: cat %t/.SWIFT_FINE_DEPENDENCY_TRACE/* | %FileCheck %s
5+
// RUN: cat %t/.SWIFT_FINE_DEPENDENCY_TRACE.json | %FileCheck %s
66

7-
// RUN: SWIFT_COMPILER_OBJC_MESSAGE_TRACE_DIRECTORY=%t/CUSTOM_DIR %target-swift-frontend -I %t/lib/swift -typecheck %s %S/Inputs/objc_send_collector_2.swift -module-name main -swift-version 5 -F %S/Inputs/mock-sdk -emit-loaded-module-trace-path %t/.MODULE_TRACE
8-
// RUN: cat %t/CUSTOM_DIR/* | %FileCheck %s
7+
// RUN: SWIFT_COMPILER_OBJC_MESSAGE_TRACE_PATH=%t/given_trace.json %target-swift-frontend -I %t/lib/swift -typecheck %s %S/Inputs/objc_send_collector_2.swift -module-name main -swift-version 5 -F %S/Inputs/mock-sdk -emit-loaded-module-trace-path %t/.MODULE_TRACE
8+
// RUN: cat %t/given_trace.json | %FileCheck %s
99

1010
// REQUIRES: objc_interop
1111

0 commit comments

Comments
 (0)