Skip to content

TBDGen: when previous install name map is specified, emit $ld$previous linker directives. #29293

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -1607,6 +1607,7 @@ class OriginallyDefinedInAttr: public DeclAttribute {
const llvm::VersionTuple MovedVersion;

struct ActiveVersion {
StringRef ModuleName;
PlatformKind Platform;
bool IsSimulator;
llvm::VersionTuple Version;
Expand Down
5 changes: 5 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,11 @@ class alignas(1 << DeclAlignInBits) Decl {
return Attrs;
}

/// Returns the introduced OS version in the given platform kind specified
/// by @available attribute.
/// This function won't consider the parent context to get the information.
Optional<llvm::VersionTuple> getIntroducedOSVersion(PlatformKind Kind) const;

/// Returns the starting location of the entire declaration.
SourceLoc getStartLoc() const { return getSourceRange().Start; }

Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/DiagnosticsFrontend.def
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,9 @@ REMARK(platform_previous_install_name, none,
ERROR(unknown_platform_name, none,
"unkown platform name %0", (StringRef))

ERROR(cannot_find_install_name, none,
"cannot find previous install name for module %0 in %1", (StringRef, StringRef))

ERROR(symbol_in_tbd_not_in_ir,none,
"symbol '%0' (%1) is in TBD file, but not in generated IR",
(StringRef, StringRef))
Expand Down
1 change: 1 addition & 0 deletions lib/AST/Attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1291,6 +1291,7 @@ OriginallyDefinedInAttr::isActivePlatform(const ASTContext &ctx) const {
OriginallyDefinedInAttr::ActiveVersion Result;
Result.Platform = Platform;
Result.Version = MovedVersion;
Result.ModuleName = OriginalModuleName;
if (isPlatformActive(Platform, ctx.LangOpts)) {
Result.IsSimulator = ctx.LangOpts.Target.isSimulatorEnvironment();
return Result;
Expand Down
12 changes: 12 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,18 @@ StringRef Decl::getDescriptiveKindName(DescriptiveDeclKind K) {
llvm_unreachable("bad DescriptiveDeclKind");
}

Optional<llvm::VersionTuple>
Decl::getIntroducedOSVersion(PlatformKind Kind) const {
for (auto *attr: getAttrs()) {
if (auto *ava = dyn_cast<AvailableAttr>(attr)) {
if (ava->Platform == Kind && ava->Introduced) {
return ava->Introduced;
}
}
}
return None;
}

llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &OS,
StaticSpellingKind SSK) {
switch (SSK) {
Expand Down
101 changes: 85 additions & 16 deletions lib/TBDGen/TBDGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,18 +86,6 @@ getAllMovedPlatformVersions(Decl *D) {
return Results;
}

static Optional<llvm::VersionTuple>
getIntroducedOSVersion(Decl *D, PlatformKind Kind) {
for (auto *attr: D->getAttrs()) {
if (auto *ava = dyn_cast<AvailableAttr>(attr)) {
if (ava->Platform == Kind && ava->Introduced) {
return ava->Introduced;
}
}
}
return None;
}

static StringRef getLinkerPlatformName(uint8_t Id) {
switch (Id) {
#define LD_PLATFORM(Name, Id) case Id: return #Name;
Expand Down Expand Up @@ -245,8 +233,85 @@ TBDGenVisitor::parsePreviousModuleInstallNameMap() {
return pResult;
}

void TBDGenVisitor::addLinkerDirectiveSymbols(StringRef name,
llvm::MachO::SymbolKind kind) {
static LinkerPlatformId
getLinkerPlatformId(OriginallyDefinedInAttr::ActiveVersion Ver) {
switch(Ver.Platform) {
case swift::PlatformKind::none:
llvm_unreachable("cannot find platform kind");
case swift::PlatformKind::iOS:
case swift::PlatformKind::iOSApplicationExtension:
return Ver.IsSimulator ? LinkerPlatformId::iOS_sim:
LinkerPlatformId::iOS;
case swift::PlatformKind::tvOS:
case swift::PlatformKind::tvOSApplicationExtension:
return Ver.IsSimulator ? LinkerPlatformId::tvOS_sim:
LinkerPlatformId::tvOS;
case swift::PlatformKind::watchOS:
case swift::PlatformKind::watchOSApplicationExtension:
return Ver.IsSimulator ? LinkerPlatformId::watchOS_sim:
LinkerPlatformId::watchOS;
case swift::PlatformKind::OSX:
case swift::PlatformKind::OSXApplicationExtension:
return LinkerPlatformId::macOS;
}
}

static StringRef
getLinkerPlatformName(OriginallyDefinedInAttr::ActiveVersion Ver) {
return getLinkerPlatformName((uint8_t)getLinkerPlatformId(Ver));
}

void TBDGenVisitor::addLinkerDirectiveSymbolsLdPrevious(StringRef name,
llvm::MachO::SymbolKind kind) {
if (kind != llvm::MachO::SymbolKind::GlobalSymbol)
return;
if (!TopLevelDecl)
return;
auto MovedVers = getAllMovedPlatformVersions(TopLevelDecl);
if (MovedVers.empty())
return;
assert(!MovedVers.empty());
assert(previousInstallNameMap);
auto &Ctx = TopLevelDecl->getASTContext();
for (auto &Ver: MovedVers) {
auto IntroVer = TopLevelDecl->getIntroducedOSVersion(Ver.Platform);
assert(IntroVer && "cannot find OS intro version");
if (!IntroVer.hasValue())
continue;
auto PlatformNumber = getLinkerPlatformId(Ver);
auto It = previousInstallNameMap->find(Ver.ModuleName);
if (It == previousInstallNameMap->end()) {
Ctx.Diags.diagnose(SourceLoc(), diag::cannot_find_install_name,
Ver.ModuleName, getLinkerPlatformName(Ver));
continue;
}
auto InstallName = It->second.getInstallName(PlatformNumber);
if (InstallName.empty()) {
Ctx.Diags.diagnose(SourceLoc(), diag::cannot_find_install_name,
Ver.ModuleName, getLinkerPlatformName(Ver));
continue;
}
llvm::SmallString<64> Buffer;
llvm::raw_svector_ostream OS(Buffer);
// Empty compatible version indicates using the current compatible version.
StringRef ComptibleVersion = "";
OS << "$ld$previous$";
OS << InstallName << "$";
OS << ComptibleVersion << "$";
OS << std::to_string((uint8_t)PlatformNumber) << "$";
static auto getMinor = [](Optional<unsigned> Minor) {
return Minor.hasValue() ? *Minor : 0;
};
OS << IntroVer->getMajor() << "." << getMinor(IntroVer->getMinor()) << "$";
OS << Ver.Version.getMajor() << "." << getMinor(Ver.Version.getMinor()) << "$";
OS << name << "$";
addSymbolInternal(OS.str(), llvm::MachO::SymbolKind::GlobalSymbol,
/*LinkerDirective*/true);
}
}

void TBDGenVisitor::addLinkerDirectiveSymbolsLdHide(StringRef name,
llvm::MachO::SymbolKind kind) {
if (kind != llvm::MachO::SymbolKind::GlobalSymbol)
return;
if (!TopLevelDecl)
Expand All @@ -265,7 +330,7 @@ void TBDGenVisitor::addLinkerDirectiveSymbols(StringRef name,
unsigned Minor[2];
Major[1] = MovedVer.getMajor();
Minor[1] = MovedVer.getMinor().hasValue() ? *MovedVer.getMinor(): 0;
auto IntroVer = getIntroducedOSVersion(TopLevelDecl, Platform);
auto IntroVer = TopLevelDecl->getIntroducedOSVersion(Platform);
assert(IntroVer && "cannot find the start point of availability");
if (!IntroVer.hasValue())
return;
Expand Down Expand Up @@ -296,7 +361,11 @@ void TBDGenVisitor::addSymbol(StringRef name, SymbolKind kind) {
SmallString<32> mangled;
llvm::Mangler::getNameWithPrefix(mangled, name, DataLayout);
addSymbolInternal(mangled, kind);
addLinkerDirectiveSymbols(mangled, kind);
if (previousInstallNameMap) {
addLinkerDirectiveSymbolsLdPrevious(mangled, kind);
} else {
addLinkerDirectiveSymbolsLdHide(mangled, kind);
}
}

void TBDGenVisitor::addSymbol(SILDeclRef declRef) {
Expand Down
3 changes: 2 additions & 1 deletion lib/TBDGen/TBDGenVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ class TBDGenVisitor : public ASTVisitor<TBDGenVisitor> {
parsePreviousModuleInstallNameMap();
void addSymbolInternal(StringRef name, llvm::MachO::SymbolKind kind,
bool isLinkerDirective = false);
void addLinkerDirectiveSymbols(StringRef name, llvm::MachO::SymbolKind kind);
void addLinkerDirectiveSymbolsLdHide(StringRef name, llvm::MachO::SymbolKind kind);
void addLinkerDirectiveSymbolsLdPrevious(StringRef name, llvm::MachO::SymbolKind kind);
void addSymbol(StringRef name, llvm::MachO::SymbolKind kind =
llvm::MachO::SymbolKind::GlobalSymbol);

Expand Down
12 changes: 12 additions & 0 deletions test/TBD/Inputs/install-name-map-toasterkit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"module": "ToasterKit",
"install_name": "/System/Previous/macOS/ToasterKit.dylib",
"platforms": ["macOS"]
},
{
"module": "ToasterKit",
"install_name": "/System/Previous/iOS/ToasterKit.dylib",
"platforms": ["iOS"]
}
]
9 changes: 9 additions & 0 deletions test/TBD/Inputs/linker-directive.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@available(OSX 10.8, iOS 10.2, *)
@_originallyDefinedIn(module: "ToasterKit", macOS 10.15, iOS 13)
public func toast() {}

@available(OSX 10.8, iOS 10.2, *)
@_originallyDefinedIn(module: "ToasterKit", macOS 10.15, iOS 13)
public struct Vehicle {
public func move() {}
}
14 changes: 14 additions & 0 deletions test/TBD/linker-directives-ld-previous-ios.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// REQUIRES: OS=ios

// RUN: %empty-directory(%t)

// RUN: %target-swift-frontend -typecheck %S/Inputs/linker-directive.swift -tbd-is-installapi -emit-tbd -emit-tbd-path %t/linker_directives.tbd -previous-module-installname-map-file %S/Inputs/install-name-map-toasterkit.json
// RUN: %FileCheck %s < %t/linker_directives.tbd
// RUN: %target-swift-frontend -typecheck %S/Inputs/linker-directive.swift -emit-tbd -emit-tbd-path %t/linker_directives.tbd -previous-module-installname-map-file %S/Inputs/install-name-map-toasterkit.json
// RUN: %FileCheck %s < %t/linker_directives.tbd

// CHECK: $ld$previous$/System/Previous/iOS/ToasterKit.dylib$$2$10.2$13.0$_$s10ToasterKit5toastyyF$
// CHECK: $ld$previous$/System/Previous/iOS/ToasterKit.dylib$$2$10.2$13.0$_$s10ToasterKit7VehicleV4moveyyF$
// CHECK: $ld$previous$/System/Previous/iOS/ToasterKit.dylib$$2$10.2$13.0$_$s10ToasterKit7VehicleVMa$
// CHECK: $ld$previous$/System/Previous/iOS/ToasterKit.dylib$$2$10.2$13.0$_$s10ToasterKit7VehicleVMn$
// CHECK: $ld$previous$/System/Previous/iOS/ToasterKit.dylib$$2$10.2$13.0$_$s10ToasterKit7VehicleVN$
14 changes: 14 additions & 0 deletions test/TBD/linker-directives-ld-previous-macos.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// REQUIRES: OS=macosx

// RUN: %empty-directory(%t)

// RUN: %target-swift-frontend -typecheck %S/Inputs/linker-directive.swift -tbd-is-installapi -emit-tbd -emit-tbd-path %t/linker_directives.tbd -previous-module-installname-map-file %S/Inputs/install-name-map-toasterkit.json
// RUN: %FileCheck %s < %t/linker_directives.tbd
// RUN: %target-swift-frontend -typecheck %S/Inputs/linker-directive.swift -emit-tbd -emit-tbd-path %t/linker_directives.tbd -previous-module-installname-map-file %S/Inputs/install-name-map-toasterkit.json
// RUN: %FileCheck %s < %t/linker_directives.tbd

// CHECK: $ld$previous$/System/Previous/macOS/ToasterKit.dylib$$1$10.8$10.15$_$s10ToasterKit5toastyyF$
// CHECK: $ld$previous$/System/Previous/macOS/ToasterKit.dylib$$1$10.8$10.15$_$s10ToasterKit7VehicleV4moveyyF$
// CHECK: $ld$previous$/System/Previous/macOS/ToasterKit.dylib$$1$10.8$10.15$_$s10ToasterKit7VehicleVMa$
// CHECK: $ld$previous$/System/Previous/macOS/ToasterKit.dylib$$1$10.8$10.15$_$s10ToasterKit7VehicleVMn$
// CHECK: $ld$previous$/System/Previous/macOS/ToasterKit.dylib$$1$10.8$10.15$_$s10ToasterKit7VehicleVN$