Skip to content

Commit f4da34f

Browse files
author
Harlan Haskins
committed
[ParseableInterface] Only open module buffers once while loading
In addition to being wasteful, this is a correctness issue -- the compiler should only ever have one view of this file, and it should not read a potentially different file after validating dependencies. rdar://48654608
1 parent 384882d commit f4da34f

File tree

5 files changed

+171
-67
lines changed

5 files changed

+171
-67
lines changed

include/swift/Serialization/SerializedModuleLoader.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ class SerializedModuleLoaderBase : public ModuleLoader {
6363
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
6464
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer);
6565

66+
std::error_code
67+
openModuleDocFile(AccessPathElem ModuleID,
68+
StringRef ModuleDocPath,
69+
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer);
70+
6671
/// If the module loader subclass knows that all options have been tried for
6772
/// loading an architecture-specific file out of a swiftmodule bundle, try
6873
/// to list the architectures that \e are present.

include/swift/Subsystems.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,18 @@ namespace swift {
264264
void serialize(ModuleOrSourceFile DC, const SerializationOptions &options,
265265
const SILModule *M = nullptr);
266266

267+
/// Serializes a module or single source file to the given output file and
268+
/// returns back the file's contents as a memory buffer.
269+
///
270+
/// Use this if you intend to immediately load the serialized module, as that
271+
/// will both avoid extra filesystem traffic and will ensure you read back
272+
/// exactly what was written.
273+
void serializeToBuffers(ModuleOrSourceFile DC,
274+
const SerializationOptions &opts,
275+
std::unique_ptr<llvm::MemoryBuffer> *moduleBuffer,
276+
std::unique_ptr<llvm::MemoryBuffer> *moduleDocBuffer,
277+
const SILModule *M = nullptr);
278+
267279
/// Get the CPU, subtarget feature options, and triple to use when emitting code.
268280
std::tuple<llvm::TargetOptions, std::string, std::vector<std::string>,
269281
std::string>

lib/Frontend/ParseableInterfaceModuleLoader.cpp

Lines changed: 84 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -173,30 +173,40 @@ class DiscoveredModule {
173173
/// The kind of module that's been discovered.
174174
const Kind kind;
175175

176-
DiscoveredModule(StringRef path, Kind kind): kind(kind), path(path) {}
176+
DiscoveredModule(StringRef path, Kind kind,
177+
std::unique_ptr<llvm::MemoryBuffer> moduleBuffer)
178+
: kind(kind), moduleBuffer(std::move(moduleBuffer)), path(path) {}
179+
177180
public:
181+
/// The contents of the .swiftmodule, if we've read it while validating
182+
/// dependencies.
183+
std::unique_ptr<llvm::MemoryBuffer> moduleBuffer;
184+
178185
/// The path to the discovered serialized .swiftmodule on disk.
179186
const std::string path;
180187

181188
/// Creates a \c Normal discovered module.
182-
static DiscoveredModule normal(StringRef path) {
183-
return { path, Kind::Normal };
189+
static DiscoveredModule normal(StringRef path,
190+
std::unique_ptr<llvm::MemoryBuffer> moduleBuffer) {
191+
return { path, Kind::Normal, std::move(moduleBuffer) };
184192
}
185193

186194
/// Creates a \c Prebuilt discovered module.
187-
static DiscoveredModule prebuilt(StringRef path) {
188-
return { path, Kind::Prebuilt };
195+
static DiscoveredModule prebuilt(
196+
StringRef path, std::unique_ptr<llvm::MemoryBuffer> moduleBuffer) {
197+
return { path, Kind::Prebuilt, std::move(moduleBuffer) };
189198
}
190199

191200
/// Creates a \c Forwarded discovered module, whose dependencies have been
192201
/// externally validated by a \c ForwardingModule.
193-
static DiscoveredModule forwarded(StringRef path) {
194-
return { path, Kind::Forwarded };
202+
static DiscoveredModule forwarded(
203+
StringRef path, std::unique_ptr<llvm::MemoryBuffer> moduleBuffer) {
204+
return { path, Kind::Forwarded, std::move(moduleBuffer) };
195205
}
196206

197207
bool isNormal() const { return kind == Kind::Normal; }
198208
bool isPrebuilt() const { return kind == Kind::Prebuilt; }
199-
bool isForwarding() const { return kind == Kind::Forwarded; }
209+
bool isForwarded() const { return kind == Kind::Forwarded; }
200210
};
201211

202212
} // end anonymous namespace
@@ -453,7 +463,8 @@ class swift::ParseableInterfaceBuilder {
453463
return subInvocation;
454464
}
455465

456-
bool buildSwiftModule(StringRef OutPath, bool ShouldSerializeDeps) {
466+
bool buildSwiftModule(StringRef OutPath, bool ShouldSerializeDeps,
467+
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer) {
457468
bool SubError = false;
458469
bool RunSuccess = llvm::CrashRecoveryContext().RunSafelyOnThread([&] {
459470
// Note that we don't assume cachePath is the same as the Clang
@@ -559,7 +570,10 @@ class swift::ParseableInterfaceBuilder {
559570
if (ShouldSerializeDeps)
560571
SerializationOpts.Dependencies = Deps;
561572
SILMod->setSerializeSILAction([&]() {
562-
serialize(Mod, SerializationOpts, SILMod.get());
573+
// We don't want to serialize module docs in the cache -- they
574+
// will be serialized beside the interface file.
575+
serializeToBuffers(Mod, SerializationOpts, ModuleBuffer,
576+
/*ModuleDocBuffer*/nullptr, SILMod.get());
563577
});
564578

565579
LLVM_DEBUG(llvm::dbgs() << "Running SIL processing passes\n");
@@ -717,22 +731,23 @@ class ParseableInterfaceModuleLoaderImpl {
717731

718732
// Check that the output .swiftmodule file is at least as new as all the
719733
// dependencies it read when it was built last time.
720-
bool swiftModuleIsUpToDate(StringRef modulePath,
721-
SmallVectorImpl<FileDependency> &AllDeps) {
734+
bool swiftModuleIsUpToDate(
735+
StringRef modulePath, SmallVectorImpl<FileDependency> &AllDeps,
736+
std::unique_ptr<llvm::MemoryBuffer> &moduleBuffer) {
722737
auto OutBuf = fs.getBufferForFile(modulePath);
723738
if (!OutBuf)
724739
return false;
725-
return serializedASTBufferIsUpToDate(*OutBuf.get(), AllDeps);
740+
moduleBuffer = std::move(*OutBuf);
741+
return serializedASTBufferIsUpToDate(*moduleBuffer, AllDeps);
726742
}
727743

728744
// Check that a "forwarding" .swiftmodule file is at least as new as all the
729745
// dependencies it read when it was built last time. Requires that the
730746
// forwarding module has been loaded from disk.
731-
bool forwardingModuleIsUpToDate(const ForwardingModule &fwd,
732-
SmallVectorImpl<FileDependency> &deps) {
747+
bool forwardingModuleIsUpToDate(
748+
const ForwardingModule &fwd, SmallVectorImpl<FileDependency> &deps,
749+
std::unique_ptr<llvm::MemoryBuffer> &moduleBuffer) {
733750
// First, make sure the underlying module path exists and is valid.
734-
// FIXME: We should preserve this buffer, rather than opening it again
735-
// when loading the module.
736751
auto modBuf = fs.getBufferForFile(fwd.underlyingModulePath);
737752
if (!modBuf || !serializedASTLooksValid(*modBuf.get()))
738753
return false;
@@ -743,7 +758,11 @@ class ParseableInterfaceModuleLoaderImpl {
743758
FileDependency::modTimeBased(
744759
dep.path, dep.size, dep.lastModificationTime));
745760
}
746-
return dependenciesAreUpToDate(deps);
761+
if (!dependenciesAreUpToDate(deps))
762+
return false;
763+
764+
moduleBuffer = std::move(*modBuf);
765+
return true;
747766
}
748767

749768
Optional<StringRef>
@@ -809,22 +828,25 @@ class ParseableInterfaceModuleLoaderImpl {
809828
// First, check the cached module path. Whatever's in this cache represents
810829
// the most up-to-date knowledge we have about the module.
811830
if (auto cachedBufOrError = fs.getBufferForFile(cachedOutputPath)) {
812-
auto &buf = *cachedBufOrError.get();
831+
auto buf = std::move(*cachedBufOrError);
813832

814833
// Check to see if the module is a serialized AST. If it's not, then we're
815834
// probably dealing with a Forwarding Module, which is a YAML file.
816835
bool isForwardingModule =
817-
!serialization::isSerializedAST(buf.getBuffer());
836+
!serialization::isSerializedAST(buf->getBuffer());
818837

819838
// If it's a forwarding module, load the YAML file from disk and check
820839
// if it's up-to-date.
821840
if (isForwardingModule) {
822-
auto modOrErr = ForwardingModule::load(buf);
823-
if (modOrErr && forwardingModuleIsUpToDate(*modOrErr, deps))
824-
return DiscoveredModule::forwarded(modOrErr->underlyingModulePath);
841+
if (auto forwardingModule = ForwardingModule::load(*buf)) {
842+
std::unique_ptr<llvm::MemoryBuffer> moduleBuffer;
843+
if (forwardingModuleIsUpToDate(*forwardingModule, deps, moduleBuffer))
844+
return DiscoveredModule::forwarded(
845+
forwardingModule->underlyingModulePath, std::move(moduleBuffer));
846+
}
825847
// Otherwise, check if the AST buffer itself is up to date.
826-
} else if (serializedASTBufferIsUpToDate(buf, deps)) {
827-
return DiscoveredModule::normal(cachedOutputPath);
848+
} else if (serializedASTBufferIsUpToDate(*buf, deps)) {
849+
return DiscoveredModule::normal(cachedOutputPath, std::move(buf));
828850
}
829851
}
830852

@@ -835,9 +857,10 @@ class ParseableInterfaceModuleLoaderImpl {
835857
// from the SDK.
836858
if (!prebuiltCacheDir.empty()) {
837859
llvm::SmallString<256> scratch;
860+
std::unique_ptr<llvm::MemoryBuffer> moduleBuffer;
838861
auto path = computePrebuiltModulePath(scratch);
839-
if (path && swiftModuleIsUpToDate(*path, deps))
840-
return DiscoveredModule::prebuilt(*path);
862+
if (path && swiftModuleIsUpToDate(*path, deps, moduleBuffer))
863+
return DiscoveredModule::prebuilt(*path, std::move(moduleBuffer));
841864
}
842865

843866
// Finally, if there's a module adjacent to the .swiftinterface that we can
@@ -899,10 +922,12 @@ class ParseableInterfaceModuleLoaderImpl {
899922
});
900923
}
901924

902-
/// Looks up the best module to load for a given interface. See the main
903-
/// comment in \c ParseableInterfaceModuleLoader.h for an explanation of
904-
/// the module loading strategy.
905-
llvm::ErrorOr<std::string> findOrBuildLoadableModule() {
925+
/// Looks up the best module to load for a given interface, and returns a
926+
/// buffer of the module's contents. See the main comment in
927+
/// \c ParseableInterfaceModuleLoader.h for an explanation of the module
928+
/// loading strategy.
929+
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
930+
findOrBuildLoadableModule() {
906931

907932
// Set up a builder if we need to build the module. It'll also set up
908933
// the subinvocation we'll need to use to compute the cache paths.
@@ -927,24 +952,27 @@ class ParseableInterfaceModuleLoaderImpl {
927952
moduleOrErr.getError() != std::errc::no_such_file_or_directory)
928953
return moduleOrErr.getError();
929954

930-
// We discovered a module! Return the module's path so we know what to load.
955+
// We discovered a module! Return that module's buffer so we can load it.
931956
if (moduleOrErr) {
932-
auto &module = *moduleOrErr;
957+
auto module = std::move(moduleOrErr.get());
958+
933959
// If it's prebuilt, use this time to generate a forwarding module.
934960
if (module.isPrebuilt())
935961
if (writeForwardingModule(module, cachedOutputPath, allDeps))
936962
return std::make_error_code(std::errc::not_supported);
937963

938-
// FIXME: return and load module buffer directly
939-
return module.path;
964+
return std::move(module.moduleBuffer);
940965
}
941966

967+
std::unique_ptr<llvm::MemoryBuffer> moduleBuffer;
942968
// We didn't discover a module corresponding to this interface. Build one.
943-
if (builder.buildSwiftModule(cachedOutputPath, /*shouldSerializeDeps*/true))
969+
if (builder.buildSwiftModule(cachedOutputPath, /*shouldSerializeDeps*/true,
970+
&moduleBuffer))
944971
return std::make_error_code(std::errc::invalid_argument);
945972

946-
// FIXME: return and load module buffer directly
947-
return cachedOutputPath.str();
973+
assert(moduleBuffer &&
974+
"failed to write module buffer but returned success?");
975+
return std::move(moduleBuffer);
948976
}
949977
};
950978

@@ -984,26 +1012,24 @@ std::error_code ParseableInterfaceModuleLoader::findModuleFilesInDirectory(
9841012

9851013
// Ask the impl to find us a module that we can load or give us an error
9861014
// telling us that we couldn't load it.
987-
auto PathOrErr = Impl.findOrBuildLoadableModule();
988-
if (!PathOrErr)
989-
return PathOrErr.getError();
990-
std::string FinalPath = std::move(*PathOrErr);
991-
992-
// Finish off by delegating back up to the SerializedModuleLoaderBase
993-
// routine that can load the recently-manufactured serialized module.
994-
LLVM_DEBUG(llvm::dbgs() << "Loading " << FinalPath
995-
<< " via normal module loader\n");
1015+
auto ModuleBufferOrErr = Impl.findOrBuildLoadableModule();
1016+
if (!ModuleBufferOrErr)
1017+
return ModuleBufferOrErr.getError();
1018+
1019+
if (ModuleBuffer) {
1020+
*ModuleBuffer = std::move(*ModuleBufferOrErr);
1021+
}
1022+
1023+
// Delegate back to the serialized module loader to load the module doc.
9961024
llvm::SmallString<256> DocPath{DirPath};
9971025
path::append(DocPath, ModuleDocFilename);
998-
auto ErrorCode = SerializedModuleLoaderBase::openModuleFiles(
999-
ModuleID, FinalPath, DocPath, ModuleBuffer, ModuleDocBuffer);
1000-
LLVM_DEBUG(llvm::dbgs() << "Loaded " << FinalPath
1001-
<< " via normal module loader");
1002-
if (ErrorCode) {
1003-
LLVM_DEBUG(llvm::dbgs() << " with error: " << ErrorCode.message());
1004-
}
1005-
LLVM_DEBUG(llvm::dbgs() << "\n");
1006-
return ErrorCode;
1026+
auto DocLoadErr =
1027+
SerializedModuleLoaderBase::openModuleDocFile(ModuleID, DocPath,
1028+
ModuleDocBuffer);
1029+
if (DocLoadErr)
1030+
return DocLoadErr;
1031+
1032+
return std::error_code();
10071033
}
10081034

10091035

@@ -1018,5 +1044,6 @@ bool ParseableInterfaceModuleLoader::buildSwiftModuleFromSwiftInterface(
10181044
// make them relocatable (SDK-relative) if we want to ship the built
10191045
// swiftmodules to another machine. Just track them as absolute paths
10201046
// for now, so we can test the dependency tracking locally.
1021-
return builder.buildSwiftModule(OutPath, /*shouldSerializeDeps*/true);
1047+
return builder.buildSwiftModule(OutPath, /*shouldSerializeDeps*/true,
1048+
/*ModuleBuffer*/nullptr);
10221049
}

lib/Serialization/Serialization.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include "llvm/Support/OnDiskHashTable.h"
5252
#include "llvm/Support/Path.h"
5353
#include "llvm/Support/raw_ostream.h"
54+
#include "llvm/Support/SmallVectorMemoryBuffer.h"
5455

5556
#include <vector>
5657

@@ -4809,6 +4810,48 @@ void Serializer::writeToStream(raw_ostream &os, ModuleOrSourceFile DC,
48094810
S.writeToStream(os);
48104811
}
48114812

4813+
void swift::serializeToBuffers(
4814+
ModuleOrSourceFile DC, const SerializationOptions &options,
4815+
std::unique_ptr<llvm::MemoryBuffer> *moduleBuffer,
4816+
std::unique_ptr<llvm::MemoryBuffer> *moduleDocBuffer,
4817+
const SILModule *M) {
4818+
4819+
assert(options.OutputPath && options.OutputPath[0] != '\0');
4820+
{
4821+
SharedTimer timer("Serialization, swiftmodule, to buffer");
4822+
llvm::SmallString<1024> buf;
4823+
llvm::raw_svector_ostream stream(buf);
4824+
Serializer::writeToStream(stream, DC, M, options);
4825+
bool hadError = withOutputFile(getContext(DC).Diags,
4826+
options.OutputPath,
4827+
[&](raw_ostream &out) {
4828+
out << stream.str();
4829+
return false;
4830+
});
4831+
if (hadError)
4832+
return;
4833+
if (moduleBuffer)
4834+
*moduleBuffer = llvm::make_unique<llvm::SmallVectorMemoryBuffer>(
4835+
std::move(buf), options.OutputPath);
4836+
}
4837+
4838+
if (options.DocOutputPath && options.DocOutputPath[0] != '\0') {
4839+
SharedTimer timer("Serialization, swiftdoc, to buffer");
4840+
llvm::SmallString<1024> buf;
4841+
llvm::raw_svector_ostream stream(buf);
4842+
writeDocToStream(stream, DC, options.GroupInfoPath);
4843+
(void)withOutputFile(getContext(DC).Diags,
4844+
options.DocOutputPath,
4845+
[&](raw_ostream &out) {
4846+
out << stream.str();
4847+
return false;
4848+
});
4849+
if (moduleDocBuffer)
4850+
*moduleDocBuffer = llvm::make_unique<llvm::SmallVectorMemoryBuffer>(
4851+
std::move(buf), options.DocOutputPath);
4852+
}
4853+
}
4854+
48124855
void swift::serialize(ModuleOrSourceFile DC,
48134856
const SerializationOptions &options,
48144857
const SILModule *M) {

0 commit comments

Comments
 (0)