Serialize and honor whether a particular library should be force-loaded.

When a module built with -autolink-force-load is imported, add a reference
to a special symbol in the corresponding library so that ld is forced to
link it.

This means the library will be linked into the final binary even if no other
symbols are used (which happens for some of our overlays that just add
category methods to Objective-C classes).

Second part of <rdar://problem/16829587>

Swift SVN r17751
This commit is contained in:
Jordan Rose
2014-05-09 01:20:32 +00:00
parent 41700b03da
commit dde2a8b06b
9 changed files with 63 additions and 38 deletions

View File

@@ -31,13 +31,18 @@ enum class LibraryKind {
class LinkLibrary {
private:
std::string Name;
LibraryKind Kind;
unsigned Kind : 1;
unsigned ForceLoad : 1;
public:
LinkLibrary(StringRef N, LibraryKind K) : Name(N), Kind(K) {}
LinkLibrary(StringRef N, LibraryKind K, bool forceLoad = false)
: Name(N), Kind(static_cast<unsigned>(K)), ForceLoad(forceLoad) {
assert(getKind() == K && "not enough bits for the kind");
}
LibraryKind getKind() const { return Kind; }
LibraryKind getKind() const { return static_cast<LibraryKind>(Kind); }
StringRef getName() const { return Name; }
bool shouldForceLoad() const { return ForceLoad; }
};
} // end namespace swift

View File

@@ -40,7 +40,7 @@ const uint16_t VERSION_MAJOR = 0;
/// Serialized module format minor version number.
///
/// When the format changes IN ANY WAY, this number should be incremented.
const uint16_t VERSION_MINOR = 91;
const uint16_t VERSION_MINOR = 92;
using DeclID = Fixnum<31>;
using DeclIDField = BCFixed<31>;
@@ -348,6 +348,7 @@ namespace input_block {
using LinkLibraryLayout = BCRecordLayout<
LINK_LIBRARY,
LibraryKindField, // kind
BCFixed<1>, // forced?
BCBlob // library name
>;

View File

@@ -160,8 +160,9 @@ namespace swift {
const SILModule *M = nullptr,
bool serializeAllSIL = false,
ArrayRef<std::string> inputFilenames = {},
StringRef importedHeader = {},
StringRef moduleLinkName = {},
StringRef importedHeader = {});
bool autolinkForceLoad = false);
/// Turn the given Swift module into either LLVM IR or native code
/// and return the generated LLVM IR module.

View File

@@ -100,6 +100,8 @@ static void addCommonFrontendArgs(const ToolChain &TC,
inputArgs.AddLastArg(arguments, options::OPT_module_cache_path);
inputArgs.AddLastArg(arguments, options::OPT_enable_app_extension);
inputArgs.AddLastArg(arguments, options::OPT_import_objc_header);
inputArgs.AddLastArg(arguments, options::OPT_module_link_name);
inputArgs.AddLastArg(arguments, options::OPT_autolink_force_load);
// Pass through the values passed to -Xfrontend.
inputArgs.AddAllArgValues(arguments, options::OPT_Xfrontend);
@@ -260,12 +262,7 @@ Job *Swift::constructJob(const JobAction &JA, std::unique_ptr<JobList> Inputs,
addCommonFrontendArgs(getToolChain(), OI, Output.get(), Args, Arguments);
Args.AddLastArg(Arguments, options::OPT_module_link_name);
Args.AddLastArg(Arguments, options::OPT_import_underlying_module);
// FIXME: Warn if -module-link-name is not present.
Args.AddLastArg(Arguments, options::OPT_autolink_force_load);
Args.AddLastArg(Arguments, options::OPT_split_objc_selectors);
Args.AddLastArg(Arguments, options::OPT_implicit_objc_with);
Args.AddLastArg(Arguments, options::OPT_strict_keyword_arguments);

View File

@@ -388,6 +388,19 @@ llvm::Constant *IRGenModule::getSize(Size size) {
return llvm::ConstantInt::get(SizeTy, size.getValue());
}
static StringRef encodeForceLoadSymbolName(llvm::SmallVectorImpl<char> &buf,
StringRef name) {
llvm::raw_svector_ostream os{buf};
os << "_swift_FORCE_LOAD_$";
if (clang::isValidIdentifier(name)) {
os << "_" << name;
} else {
for (auto c : name)
os.write_hex(static_cast<uint8_t>(c));
}
return os.str();
}
void IRGenModule::addLinkLibrary(const LinkLibrary &linkLib) {
llvm::LLVMContext &ctx = Module.getContext();
@@ -410,6 +423,22 @@ void IRGenModule::addLinkLibrary(const LinkLibrary &linkLib) {
AutolinkEntries.push_back(llvm::MDNode::get(ctx, args));
break;
}
if (linkLib.shouldForceLoad()) {
llvm::SmallString<64> buf;
encodeForceLoadSymbolName(buf, linkLib.getName());
auto symbolAddr = Module.getOrInsertGlobal(buf.str(), Int1Ty);
buf += "_$_";
buf += Opts.ModuleName;
if (!Module.getGlobalVariable(buf.str())) {
(void)new llvm::GlobalVariable(Module, symbolAddr->getType(),
/*constant=*/true,
llvm::GlobalAlias::LinkOnceAnyLinkage,
symbolAddr, buf.str());
}
}
}
// FIXME: This should just be the implementation of
@@ -425,19 +454,6 @@ static int pointerPODSortComparator(T * const *lhs, T * const *rhs) {
return 0;
}
static StringRef encodeForceLoadSymbolName(llvm::SmallVectorImpl<char> &buf,
StringRef name) {
llvm::raw_svector_ostream os{buf};
os << "_swift_FORCE_LOAD_$";
if (clang::isValidIdentifier(name)) {
os << "_" << name;
} else {
for (auto c : name)
os.write_hex(static_cast<uint8_t>(c));
}
return os.str();
}
void IRGenModule::emitAutolinkInfo() {
// FIXME: This constant should be vended by LLVM somewhere.
static const char * const LinkerOptionsFlagName = "Linker Options";

View File

@@ -586,9 +586,11 @@ ModuleFile::ModuleFile(
}
case input_block::LINK_LIBRARY: {
uint8_t rawKind;
input_block::ImportedModuleLayout::readRecord(scratch, rawKind);
bool shouldForceLink;
input_block::LinkLibraryLayout::readRecord(scratch, rawKind,
shouldForceLink);
if (auto libKind = getActualLibraryKind(rawKind))
LinkLibraries.push_back({blobData, *libKind});
LinkLibraries.push_back({blobData, *libKind, shouldForceLink});
// else ignore the dependency...it'll show up as a linker error.
break;
}

View File

@@ -424,8 +424,9 @@ static void flattenImportPath(const Module::ImportedModule &import,
}
void Serializer::writeInputFiles(FilenamesTy inputFiles,
StringRef importedHeader,
StringRef moduleLinkName,
StringRef importedHeader) {
bool autolinkForceLoad) {
BCBlockRAII restoreBlock(Out, INPUT_BLOCK_ID, 3);
input_block::SourceFileLayout SourceFile(Out);
input_block::ImportedModuleLayout ImportedModule(Out);
@@ -480,7 +481,7 @@ void Serializer::writeInputFiles(FilenamesTy inputFiles,
if (!moduleLinkName.empty()) {
LinkLibrary.emit(ScratchRecord, serialization::LibraryKind::Library,
moduleLinkName);
autolinkForceLoad, moduleLinkName);
}
}
@@ -2841,9 +2842,9 @@ Serializer::Serializer(const unsigned char (&signature)[N],
void Serializer::writeToStream(raw_ostream &os, ModuleOrSourceFile DC,
const SILModule *SILMod, bool serializeAllSIL,
FilenamesTy inputFiles,
FilenamesTy inputFiles, StringRef importedHeader,
StringRef moduleLinkName,
StringRef importedHeader) {
bool autolinkForceLoad) {
Serializer S{MODULE_SIGNATURE, DC};
// FIXME: This is only really needed for debugging. We don't actually use it.
@@ -2852,7 +2853,8 @@ void Serializer::writeToStream(raw_ostream &os, ModuleOrSourceFile DC,
{
BCBlockRAII moduleBlock(S.Out, MODULE_BLOCK_ID, 2);
S.writeHeader();
S.writeInputFiles(inputFiles, moduleLinkName, importedHeader);
S.writeInputFiles(inputFiles, importedHeader, moduleLinkName,
autolinkForceLoad);
S.writeSIL(SILMod, serializeAllSIL);
S.writeAST(DC);
}
@@ -2883,8 +2885,8 @@ void Serializer::writeDocToStream(raw_ostream &os, ModuleOrSourceFile DC) {
void swift::serialize(ModuleOrSourceFile DC, const char *outputPath,
const char *docOutputPath,
const SILModule *M, bool serializeAllSIL,
FilenamesTy inputFiles, StringRef moduleLinkName,
StringRef importedHeader) {
FilenamesTy inputFiles, StringRef importedHeader,
StringRef moduleLinkName, bool autolinkForceLoad) {
assert(outputPath && outputPath[0] != '\0');
std::string errorInfo;
@@ -2898,7 +2900,7 @@ void swift::serialize(ModuleOrSourceFile DC, const char *outputPath,
}
Serializer::writeToStream(out, DC, M, serializeAllSIL, inputFiles,
moduleLinkName, importedHeader);
importedHeader, moduleLinkName, autolinkForceLoad);
if (docOutputPath && docOutputPath[0] != '\0') {
std::string errorInfo;

View File

@@ -176,8 +176,8 @@ private:
/// Writes the dependencies used to build this module: its imported
/// modules and its source files.
void writeInputFiles(FilenamesTy inputFiles, StringRef moduleLinkName,
StringRef importedHeader);
void writeInputFiles(FilenamesTy inputFiles, StringRef importedHeader,
StringRef moduleLinkName, bool autolinkForceLoad);
/// Writes the given pattern, recursively.
void writePattern(const Pattern *pattern);
@@ -286,8 +286,8 @@ public:
/// Serialize a module to the given stream.
static void writeToStream(raw_ostream &os, ModuleOrSourceFile DC,
const SILModule *M, bool serializeAllSIL,
FilenamesTy inputFiles, StringRef moduleLinkName,
StringRef importedHeader);
FilenamesTy inputFiles, StringRef importedHeader,
StringRef moduleLinkName, bool autolinkForceLoad);
/// Serialize module documentation to the given stream.
static void writeDocToStream(raw_ostream &os, ModuleOrSourceFile DC);

View File

@@ -190,7 +190,8 @@ static bool performCompile(CompilerInstance &Instance,
serialize(DC, opts.ModuleOutputPath.c_str(),
opts.ModuleDocOutputPath.c_str(), SM.get(),
opts.SILSerializeAll, opts.InputFilenames,
opts.ModuleLinkName, opts.ImplicitObjCHeaderPath);
opts.ImplicitObjCHeaderPath, opts.ModuleLinkName,
!IRGenOpts.ForceLoadSymbolName.empty());
if (Action == FrontendOptions::EmitModuleOnly)
return false;