-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Introduce a backward-deployment library for SR-10600. #25030
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -221,9 +221,46 @@ static bool wantsObjCRuntime(const llvm::Triple &triple) { | |
llvm_unreachable("unknown Darwin OS"); | ||
} | ||
|
||
/// Return the earliest backward deployment compatibility version we need to | ||
/// link in for the given target triple, if any. | ||
static Optional<std::pair<unsigned, unsigned>> | ||
getSwiftRuntimeCompatibilityVersionForTarget(const llvm::Triple &Triple) { | ||
unsigned Major, Minor, Micro; | ||
|
||
if (Triple.isMacOSX()) { | ||
Triple.getMacOSXVersion(Major, Minor, Micro); | ||
if (Major == 10) { | ||
if (Minor <= 14) { | ||
return std::make_pair(5u, 0u); | ||
} else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you eliminate these else returns? They don't add anything. You can remove the else. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For bonus points: invert if statements to reduce indentation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That would become unmanageable if we add branches for more OS versions in the future. |
||
return None; | ||
} | ||
} else { | ||
return None; | ||
} | ||
} else if (Triple.isiOS()) { // includes tvOS | ||
Triple.getiOSVersion(Major, Minor, Micro); | ||
if (Major <= 12) { | ||
return std::make_pair(5u, 0u); | ||
} else { | ||
return None; | ||
} | ||
} else if (Triple.isWatchOS()) { | ||
Triple.getWatchOSVersion(Major, Minor, Micro); | ||
if (Major <= 5) { | ||
return std::make_pair(5u, 0u); | ||
} else { | ||
return None; | ||
} | ||
} else { | ||
return None; | ||
} | ||
} | ||
|
||
ToolChain::InvocationInfo | ||
toolchains::Darwin::constructInvocation(const LinkJobAction &job, | ||
const JobContext &context) const { | ||
const JobContext &context) const | ||
{ | ||
assert(context.Output.getPrimaryOutputType() == file_types::TY_Image && | ||
"Invalid linker output type."); | ||
|
||
|
@@ -392,6 +429,38 @@ toolchains::Darwin::constructInvocation(const LinkJobAction &job, | |
SmallString<128> RuntimeLibPath; | ||
getRuntimeLibraryPath(RuntimeLibPath, context.Args, /*Shared=*/true); | ||
|
||
// Link compatibility libraries, if we're deploying back to OSes that | ||
// have an older Swift runtime. | ||
Optional<std::pair<unsigned, unsigned>> runtimeCompatibilityVersion; | ||
|
||
if (context.Args.hasArg(options::OPT_runtime_compatibility_version)) { | ||
auto value = context.Args.getLastArgValue(options::OPT_runtime_compatibility_version); | ||
if (value.equals("5.0")) { | ||
runtimeCompatibilityVersion = std::make_pair(5u, 0u); | ||
} else if (value.equals("none")) { | ||
runtimeCompatibilityVersion = None; | ||
} else { | ||
// TODO: diagnose unknown runtime compatibility version? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. :-( Yeah, this would have to be somewhere earlier; we currently don't diagnose from command generation. |
||
} | ||
} else if (job.getKind() == LinkKind::Executable) { | ||
runtimeCompatibilityVersion | ||
= getSwiftRuntimeCompatibilityVersionForTarget(Triple); | ||
} | ||
jckarter marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if (runtimeCompatibilityVersion) { | ||
if (*runtimeCompatibilityVersion <= std::make_pair(5u, 0u)) { | ||
// Swift 5.0 compatibility library | ||
SmallString<128> BackDeployLib; | ||
BackDeployLib.append(RuntimeLibPath); | ||
llvm::sys::path::append(BackDeployLib, "libswiftCompatibility50.a"); | ||
|
||
if (llvm::sys::fs::exists(BackDeployLib)) { | ||
Arguments.push_back("-force_load"); | ||
Arguments.push_back(context.Args.MakeArgString(BackDeployLib)); | ||
} | ||
} | ||
} | ||
|
||
// Link the standard library. | ||
Arguments.push_back("-L"); | ||
if (context.Args.hasFlag(options::OPT_static_stdlib, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
set(swift_runtime_compile_flags ${SWIFT_RUNTIME_CORE_CXX_FLAGS}) | ||
set(swift_runtime_linker_flags ${SWIFT_RUNTIME_CORE_LINK_FLAGS}) | ||
|
||
add_swift_target_library(swiftCompatibility50 TARGET_LIBRARY STATIC | ||
ProtocolConformance.cpp | ||
Overrides.cpp | ||
C_COMPILE_FLAGS ${swift_runtime_library_compile_flags} | ||
LINK_FLAGS ${swift_runtime_linker_flags} | ||
TARGET_SDKS ${SWIFT_APPLE_PLATFORMS} | ||
INSTALL_IN_COMPONENT stdlib) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
//===--- Overrides.cpp - Compat override table for Swift 5.0 runtime ------===// | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors | ||
// Licensed under Apache License v2.0 with Runtime Library Exception | ||
// | ||
// See https://swift.org/LICENSE.txt for license information | ||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file provides compatibility override hooks for Swift 5.0 runtimes. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "Overrides.h" | ||
#include "../runtime/CompatibilityOverride.h" | ||
|
||
using namespace swift; | ||
|
||
struct OverrideSection { | ||
uintptr_t version; | ||
#define OVERRIDE(name, ret, attrs, ccAttrs, namespace, typedArgs, namedArgs) \ | ||
Override_ ## name name; | ||
#include "../runtime/CompatibilityOverride.def" | ||
}; | ||
|
||
OverrideSection Overrides | ||
__attribute__((used, section("__DATA,__swift_hooks"))) = { | ||
.version = 0, | ||
.conformsToProtocol = swift50override_conformsToProtocol, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
//===--- Overrides.cpp - Compat overrides for Swift 5.0 runtime ----s------===// | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors | ||
// Licensed under Apache License v2.0 with Runtime Library Exception | ||
// | ||
// See https://swift.org/LICENSE.txt for license information | ||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file provides compatibility override hooks for Swift 5.0 runtimes. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "swift/Basic/LLVM.h" | ||
#include "swift/Runtime/Metadata.h" | ||
|
||
namespace swift { | ||
|
||
using ConformsToProtocol_t = | ||
const WitnessTable *(const Metadata *, const ProtocolDescriptor *); | ||
|
||
const WitnessTable * | ||
swift50override_conformsToProtocol(const Metadata * const type, | ||
const ProtocolDescriptor *protocol, | ||
ConformsToProtocol_t *original); | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
//===--- ProtocolConformance.cpp - Swift protocol conformance checking ----===// | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors | ||
// Licensed under Apache License v2.0 with Runtime Library Exception | ||
// | ||
// See https://swift.org/LICENSE.txt for license information | ||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// Checking and caching of Swift protocol conformances. | ||
// | ||
// This implementation is intended to be backward-deployed into Swift 5.0 | ||
// runtimes. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "Overrides.h" | ||
#include "../runtime/Private.h" | ||
#include "swift/Basic/Lazy.h" | ||
#include <objc/runtime.h> | ||
|
||
using namespace swift; | ||
|
||
// Clone of private function getRootSuperclass. This returns the SwiftObject | ||
// class in the ABI-stable dylib, regardless of what the local runtime build | ||
// does, since we're always patching an ABI-stable dylib. | ||
__attribute__((visibility("hidden"), weak)) | ||
const ClassMetadata *swift::getRootSuperclass() { | ||
auto theClass = SWIFT_LAZY_CONSTANT(objc_getClass("_TtCs12_SwiftObject")); | ||
return (const ClassMetadata *)theClass; | ||
} | ||
|
||
// Clone of private helper swift::_swiftoverride_class_getSuperclass | ||
// for use in the override implementation. | ||
static const Metadata *_swift50override_class_getSuperclass( | ||
const Metadata *theClass) { | ||
if (const ClassMetadata *classType = theClass->getClassObject()) { | ||
if (classHasSuperclass(classType)) | ||
return getMetadataForClass(classType->Superclass); | ||
} | ||
|
||
if (const ForeignClassMetadata *foreignClassType | ||
= dyn_cast<ForeignClassMetadata>(theClass)) { | ||
if (const Metadata *superclass = foreignClassType->Superclass) | ||
return superclass; | ||
} | ||
|
||
return nullptr; | ||
} | ||
|
||
const WitnessTable * | ||
swift::swift50override_conformsToProtocol(const Metadata *type, | ||
const ProtocolDescriptor *protocol, | ||
ConformsToProtocol_t *original_conformsToProtocol) | ||
{ | ||
// The implementation of swift_conformsToProtocol in Swift 5.0 would return | ||
// a false negative answer when asking whether a subclass conforms using | ||
// a conformance from a superclass. Work around this by walking up the | ||
// superclass chain in cases where the original implementation returns | ||
// null. | ||
do { | ||
auto result = original_conformsToProtocol(type, protocol); | ||
if (result) | ||
return result; | ||
} while ((type = _swift50override_class_getSuperclass(type))); | ||
|
||
return nullptr; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// RUN: %target-run-simple-swift | %FileCheck %s | ||
jckarter marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
public class BaseView { } | ||
public class GenericView<T>: BaseView { } | ||
public class FinalView: GenericView<ContentForTheView> { } | ||
|
||
|
||
public class ContentForTheView { } | ||
extension ContentForTheView: InfoNeededByControllers { } | ||
|
||
public protocol ConditionallyConformed { } | ||
public protocol InfoNeededByControllers { } | ||
|
||
extension GenericView: ConditionallyConformed where T: InfoNeededByControllers { } | ||
|
||
open class BaseGenericController<T> where T: BaseView & ConditionallyConformed { } | ||
|
||
|
||
open class FinalController: BaseGenericController<FinalView> { public override init() { } } | ||
|
||
// CHECK: FinalController | ||
print(FinalController()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: can you use llvm::VersionTuple for this? Bigger, sure, but also obviously a version. (And has an "empty" representation, though the Optional is fine too.)