Skip to content

Commit c4434fe

Browse files
authored
Merge pull request swiftlang#23064 from mikeash/dynamically-select-is-swift-bit
[Runtime] Dynamically select the is-Swift bit at runtime on Apple platforms.
2 parents 32d5b32 + 082b377 commit c4434fe

File tree

18 files changed

+254
-10
lines changed

18 files changed

+254
-10
lines changed

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,8 @@ option(SWIFT_RUNTIME_CRASH_REPORTER_CLIENT
235235
FALSE)
236236

237237
option(SWIFT_DARWIN_ENABLE_STABLE_ABI_BIT
238-
"Enable the Swift stable ABI's class marker bit"
239-
FALSE)
238+
"Enable the Swift stable ABI's class marker bit for new deployment targets"
239+
TRUE)
240240

241241
set(SWIFT_DARWIN_XCRUN_TOOLCHAIN "XcodeDefault" CACHE STRING
242242
"The name of the toolchain to pass to 'xcrun'")

include/swift/ABI/Metadata.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,6 +1192,31 @@ struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
11921192
return bounds;
11931193
}
11941194

1195+
/// Given a statically-emitted metadata template, this sets the correct
1196+
/// "is Swift" bit for the current runtime. Depending on the deployment
1197+
/// target a binary was compiled for, statically emitted metadata templates
1198+
/// may have a different bit set from the one that this runtime canonically
1199+
/// considers the "is Swift" bit.
1200+
void setAsTypeMetadata() {
1201+
// If the wrong "is Swift" bit is set, set the correct one.
1202+
//
1203+
// Note that the only time we should see the "new" bit set while
1204+
// expecting the "old" one is when running a binary built for a
1205+
// new OS on an old OS, which is not supported, however we do
1206+
// have tests that exercise this scenario.
1207+
auto otherSwiftBit = (3ULL - SWIFT_CLASS_IS_SWIFT_MASK);
1208+
assert(otherSwiftBit == 1ULL || otherSwiftBit == 2ULL);
1209+
1210+
if ((this->Data & 3) == otherSwiftBit) {
1211+
this->Data ^= 3;
1212+
}
1213+
1214+
// Otherwise there should be nothing to do, since only the old "is
1215+
// Swift" bit is used for backward-deployed runtimes.
1216+
1217+
assert(isTypeMetadata());
1218+
}
1219+
11951220
static bool classof(const TargetMetadata<Runtime> *metadata) {
11961221
return metadata->getKind() == MetadataKind::Class;
11971222
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//===--- BackDeployment.h - Support for running on older OS versions. -----===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_STDLIB_BACKDEPLOYMENT_H
14+
#define SWIFT_STDLIB_BACKDEPLOYMENT_H
15+
16+
#if defined(__APPLE__) && defined(__MACH__)
17+
18+
#include "swift/Runtime/Config.h"
19+
#include "../../../stdlib/public/SwiftShims/Visibility.h"
20+
21+
#ifdef __cplusplus
22+
namespace swift { extern "C" {
23+
#endif
24+
25+
#if SWIFT_CLASS_IS_SWIFT_MASK_GLOBAL_VARIABLE
26+
# ifndef __cplusplus
27+
// This file gets included from some C/ObjC files and
28+
// SWIFT_RUNTIME_STDLIB_SPI doesn't imply extern in C.
29+
extern
30+
# endif
31+
SWIFT_RUNTIME_STDLIB_SPI unsigned long long _swift_classIsSwiftMask;
32+
#endif
33+
34+
/// Returns true if the current OS version, at runtime, is a back-deployment
35+
/// version.
36+
SWIFT_RUNTIME_STDLIB_INTERNAL
37+
int _swift_isBackDeploying();
38+
39+
#ifdef __cplusplus
40+
}} // extern "C", namespace swift
41+
#endif
42+
43+
#endif // defined(__APPLE__) && defined(__MACH__)
44+
45+
#endif // SWIFT_STDLIB_BACKDEPLOYMENT_H

include/swift/Runtime/CMakeConfig.h.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,7 @@
55
#define SWIFT_RUNTIME_CMAKECONFIG_H
66

77
#cmakedefine01 SWIFT_DARWIN_ENABLE_STABLE_ABI_BIT
8+
#cmakedefine01 SWIFT_BNI_OS_BUILD
9+
#cmakedefine01 SWIFT_BNI_XCODE_BUILD
810

911
#endif

include/swift/Runtime/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,13 @@
1+
# Detect B&I builds.
2+
set(SWIFT_BNI_OS_BUILD FALSE)
3+
set(SWIFT_BNI_XCODE_BUILD FALSE)
4+
if(DEFINED ENV{RC_XBS})
5+
if(NOT DEFINED ENV{RC_XCODE} OR NOT "$ENV{RC_XCODE}")
6+
set(SWIFT_BNI_OS_BUILD TRUE)
7+
else()
8+
set(SWIFT_BNI_XCODE_BUILD TRUE)
9+
endif()
10+
endif()
11+
112
configure_file(CMakeConfig.h.in ${CMAKE_CURRENT_BINARY_DIR}/CMakeConfig.h
213
ESCAPE_QUOTES @ONLY)

include/swift/Runtime/Config.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,27 @@
141141
/// Which bits in the class metadata are used to distinguish Swift classes
142142
/// from ObjC classes?
143143
#ifndef SWIFT_CLASS_IS_SWIFT_MASK
144-
# if defined(__APPLE__) && SWIFT_OBJC_INTEROP && SWIFT_DARWIN_ENABLE_STABLE_ABI_BIT
144+
145+
// Non-Apple platforms always use 1.
146+
# if !defined(__APPLE__)
147+
# define SWIFT_CLASS_IS_SWIFT_MASK 1ULL
148+
149+
// Builds for Swift-in-the-OS always use 2.
150+
# elif SWIFT_BNI_OS_BUILD
145151
# define SWIFT_CLASS_IS_SWIFT_MASK 2ULL
146-
# else
152+
153+
// Builds for Xcode always use 1.
154+
# elif SWIFT_BNI_XCODE_BUILD
147155
# define SWIFT_CLASS_IS_SWIFT_MASK 1ULL
156+
157+
// Other builds (such as local builds on developers' computers)
158+
// dynamically choose the bit at runtime based on the current OS
159+
// version.
160+
# else
161+
# define SWIFT_CLASS_IS_SWIFT_MASK _swift_classIsSwiftMask
162+
# define SWIFT_CLASS_IS_SWIFT_MASK_GLOBAL_VARIABLE 1
163+
# include "BackDeployment.h"
164+
148165
# endif
149166
#endif
150167

include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
extern "C" {
3838
#endif
3939

40+
extern unsigned long long swift_reflection_classIsSwiftMask;
41+
4042
/// Get the metadata version supported by the Remote Mirror library.
4143
SWIFT_REMOTE_MIRROR_LINKAGE
4244
uint16_t swift_reflection_getSupportedMetadataVersion(void);

lib/Frontend/CompilerInvocation.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,11 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
429429
Opts.EnableSILOpaqueValues |= Args.hasArg(OPT_enable_sil_opaque_values);
430430

431431
#if SWIFT_DARWIN_ENABLE_STABLE_ABI_BIT
432-
Opts.UseDarwinPreStableABIBit = false;
432+
Opts.UseDarwinPreStableABIBit =
433+
(Target.isMacOSX() && Target.isMacOSXVersionLT(10, 14, 4)) ||
434+
(Target.isiOS() && Target.isOSVersionLT(12, 2)) ||
435+
(Target.isTvOS() && Target.isOSVersionLT(12, 2)) ||
436+
(Target.isWatchOS() && Target.isOSVersionLT(5, 2));
433437
#else
434438
Opts.UseDarwinPreStableABIBit = true;
435439
#endif

stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#define SWIFT_CLASS_IS_SWIFT_MASK swift_reflection_classIsSwiftMask
14+
extern "C" unsigned long long swift_reflection_classIsSwiftMask = 2;
15+
1316
#include "swift/Reflection/ReflectionContext.h"
1417
#include "swift/Reflection/TypeLowering.h"
1518
#include "swift/Remote/CMemoryReader.h"
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//===--- BackDeployment.cpp - Support for running on older OS versions. ---===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "swift/Runtime/BackDeployment.h"
14+
#include "swift/Runtime/Config.h"
15+
#include "../SwiftShims/FoundationShims.h"
16+
#include <stdlib.h>
17+
18+
#if defined(__APPLE__) && defined(__MACH__)
19+
20+
#if SWIFT_CLASS_IS_SWIFT_MASK_GLOBAL_VARIABLE
21+
static unsigned long long computeIsSwiftMask() {
22+
if (swift::_swift_isBackDeploying())
23+
return 1ULL;
24+
return 2ULL;
25+
}
26+
27+
SWIFT_ALLOWED_RUNTIME_GLOBAL_CTOR_BEGIN
28+
extern "C" unsigned long long
29+
_swift_classIsSwiftMask = computeIsSwiftMask();
30+
SWIFT_ALLOWED_RUNTIME_GLOBAL_CTOR_END
31+
#endif // SWIFT_CLASS_IS_SWIFT_MASK_GLOBAL_VARIABLE
32+
33+
static swift::_SwiftNSOperatingSystemVersion swiftInOSVersion = {
34+
#if __MAC_OS_X_VERSION_MIN_REQUIRED
35+
10, 14, 4
36+
// WatchOS also pretends to be iOS, so check it first.
37+
#elif __WATCH_OS_VERSION_MIN_REQUIRED
38+
5, 2, 0
39+
#elif __IPHONE_OS_VERSION_MIN_REQUIRED || __TV_OS_VERSION_MIN_REQUIRED
40+
12, 2, 0
41+
#else
42+
9999, 0, 0
43+
#endif
44+
};
45+
46+
static bool versionLessThan(swift::_SwiftNSOperatingSystemVersion lhs,
47+
swift::_SwiftNSOperatingSystemVersion rhs) {
48+
if (lhs.majorVersion < rhs.majorVersion) return true;
49+
if (lhs.majorVersion > rhs.majorVersion) return false;
50+
51+
if (lhs.minorVersion < rhs.minorVersion) return true;
52+
if (lhs.minorVersion > rhs.minorVersion) return false;
53+
54+
if (lhs.patchVersion < rhs.patchVersion) return true;
55+
56+
return false;
57+
}
58+
59+
SWIFT_RUNTIME_STDLIB_INTERNAL
60+
int _swift_isBackDeploying() {
61+
auto version = swift::_swift_stdlib_operatingSystemVersion();
62+
return versionLessThan(version, swiftInOSVersion);
63+
}
64+
#endif

0 commit comments

Comments
 (0)