[IRGen][runtime] Prepare to change the is-Swift bit in class metadata. (#13595)

Swift class metadata has a bit to distinguish it from non-Swift Objective-C
classes. The stable ABI will use a different bit so that stable Swift and
pre-stable Swift can be distinguished from each other.

No bits are actually changed yet. Enabling the new bit needs to wait for
other coordination such as libobjc.

rdar://35767811
This commit is contained in:
Greg Parker
2017-12-22 00:52:00 -08:00
committed by GitHub
parent f39d1cd6b6
commit c677a5dc11
19 changed files with 78 additions and 34 deletions

View File

@@ -207,6 +207,10 @@ option(SWIFT_RUNTIME_CRASH_REPORTER_CLIENT
"Whether to enable CrashReporter integration"
FALSE)
option(SWIFT_DARWIN_ENABLE_STABLE_ABI_BIT
"Enable the Swift stable ABI's class marker bit"
FALSE)
set(SWIFT_DARWIN_XCRUN_TOOLCHAIN "XcodeDefault" CACHE STRING
"The name of the toolchain to pass to 'xcrun'")

View File

@@ -86,12 +86,16 @@ inline DynamicCastFlags &operator|=(DynamicCastFlags &a, DynamicCastFlags b) {
}
/// Swift class flags.
/// These flags are valid only when isTypeMetadata().
/// When !isTypeMetadata() these flags will collide with other Swift ABIs.
enum class ClassFlags : uint32_t {
/// Is this a Swift 1 class?
IsSwift1 = 0x1,
/// Is this a Swift class from the Darwin pre-stable ABI?
/// This bit is clear in stable ABI Swift classes.
/// The Objective-C runtime also reads this bit.
IsSwiftPreStableABI = 0x1,
/// Does this class use Swift 1.0 refcounting?
UsesSwift1Refcounting = 0x2,
/// Does this class use Swift refcounting?
UsesSwiftRefcounting = 0x2,
/// Has this class a custom name, specified with the @objc attribute?
HasCustomObjCName = 0x4

View File

@@ -18,6 +18,7 @@
#ifndef SWIFT_BASIC_LANGOPTIONS_H
#define SWIFT_BASIC_LANGOPTIONS_H
#include "swift/Config.h"
#include "swift/Basic/LLVM.h"
#include "swift/Basic/Version.h"
#include "clang/Basic/VersionTuple.h"
@@ -128,6 +129,10 @@ namespace swift {
/// configuration options.
bool EnableObjCInterop = true;
/// On Darwin platforms, use the pre-stable ABI's mark bit for Swift
/// classes instead of the stable ABI's bit.
bool UseDarwinPreStableABIBit = !bool(SWIFT_DARWIN_ENABLE_STABLE_ABI_BIT);
/// Enables checking that uses of @objc require importing
/// the Foundation module.
/// This is enabled by default because SILGen can crash in such a case, but

View File

@@ -8,4 +8,6 @@
#cmakedefine HAVE_UNICODE_LIBEDIT 1
#cmakedefine01 SWIFT_DARWIN_ENABLE_STABLE_ABI_BIT
#endif // SWIFT_CONFIG_H

View File

@@ -65,6 +65,16 @@
#error Masking ISAs are incompatible with opaque ISAs
#endif
/// Which bits in the class metadata are used to distinguish Swift classes
/// from ObjC classes?
#ifndef SWIFT_CLASS_IS_SWIFT_MASK
# if __APPLE__ && SWIFT_OBJC_INTEROP && SWIFT_DARWIN_ENABLE_STABLE_ABI_BIT
# define SWIFT_CLASS_IS_SWIFT_MASK 2ULL
# else
# define SWIFT_CLASS_IS_SWIFT_MASK 1ULL
# endif
#endif
// We try to avoid global constructors in the runtime as much as possible.
// These macros delimit allowed global ctors.
#if __clang__

View File

@@ -1355,7 +1355,7 @@ struct TargetClassMetadata : public TargetHeapMetadata<Runtime> {
/// Is this object a valid swift type metadata?
bool isTypeMetadata() const {
return (Data & 1);
return (Data & SWIFT_CLASS_IS_SWIFT_MASK);
}
/// A different perspective on the same bit
bool isPureObjC() const {

View File

@@ -1184,6 +1184,12 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
Target.isOSDarwin());
Opts.EnableSILOpaqueValues |= Args.hasArg(OPT_enable_sil_opaque_values);
#if SWIFT_DARWIN_ENABLE_STABLE_ABI_BIT
Opts.UseDarwinPreStableABIBit = false;
#else
Opts.UseDarwinPreStableABIBit = true;
#endif
// Must be processed after any other language options that could affect
// platform conditions.
bool UnsupportedOS, UnsupportedArch;

View File

@@ -3333,16 +3333,16 @@ namespace {
}
void addClassFlags() {
// Always set a flag saying that this is a Swift 1.0 class.
ClassFlags flags = ClassFlags::IsSwift1;
auto flags = ClassFlags();
// Set a flag if the class uses Swift 1.0 refcounting.
// Set a flag if the class uses Swift refcounting.
auto type = Target->getDeclaredType()->getCanonicalType();
if (getReferenceCountingForType(IGM, type)
== ReferenceCounting::Native) {
flags |= ClassFlags::UsesSwift1Refcounting;
flags |= ClassFlags::UsesSwiftRefcounting;
}
// Set a flag if the class has a custom ObjC name.
DeclAttributes attrs = Target->getAttrs();
if (auto objc = attrs.getAttribute<ObjCAttr>()) {
if (objc->getName())
@@ -3411,17 +3411,21 @@ namespace {
if (!IGM.ObjCInterop) {
// with no Objective-C runtime, just give an empty pointer with the
// swift bit set.
// FIXME: Remove null data altogether rdar://problem/18801263
B.addInt(IGM.IntPtrTy, 1);
return;
}
// Derive the RO-data.
llvm::Constant *data = emitClassPrivateData(IGM, Target);
// We always set the low bit to indicate this is a Swift class.
data = llvm::ConstantExpr::getPtrToInt(data, IGM.IntPtrTy);
data = llvm::ConstantExpr::getAdd(data,
llvm::ConstantInt::get(IGM.IntPtrTy, 1));
// Set a low bit to indicate this class has Swift metadata.
auto bit = llvm::ConstantInt::get(IGM.IntPtrTy,
IGM.UseDarwinPreStableABIBit ? 1 : 2);
// Emit data + bit.
data = llvm::ConstantExpr::getPtrToInt(data, IGM.IntPtrTy);
data = llvm::ConstantExpr::getAdd(data, bit);
B.add(data);
}

View File

@@ -134,6 +134,7 @@ IRGenModule::IRGenModule(IRGenerator &irgen,
OutputFilename(OutputFilename),
TargetInfo(SwiftTargetInfo::get(*this)), DebugInfo(nullptr),
ModuleHash(nullptr), ObjCInterop(Context.LangOpts.EnableObjCInterop),
UseDarwinPreStableABIBit(Context.LangOpts.UseDarwinPreStableABIBit),
Types(*new TypeConverter(*this)) {
irgen.addGenModule(SF, this);

View File

@@ -413,6 +413,9 @@ public:
/// Does the current target require Objective-C interoperation?
bool ObjCInterop = true;
/// Is the current target using the Darwin pre-stable ABI's class marker bit?
bool UseDarwinPreStableABIBit = true;
/// Should we add value names to local IR values?
bool EnableValueNames = false;

View File

@@ -1,6 +1,11 @@
set(swift_runtime_compile_flags ${SWIFT_RUNTIME_CORE_CXX_FLAGS})
set(swift_runtime_linker_flags ${SWIFT_RUNTIME_CORE_LINK_FLAGS})
if(SWIFT_DARWIN_ENABLE_STABLE_ABI_BIT)
list(APPEND swift_runtime_compile_flags
"-DSWIFT_DARWIN_ENABLE_STABLE_ABI_BIT=1")
endif()
if(SWIFT_RUNTIME_CLOBBER_FREED_OBJECTS)
list(APPEND swift_runtime_compile_flags
"-DSWIFT_RUNTIME_CLOBBER_FREED_OBJECTS=1")

View File

@@ -443,7 +443,7 @@ static NSString *_getClassDescription(Class cls) {
bool swift::usesNativeSwiftReferenceCounting(const ClassMetadata *theClass) {
#if SWIFT_OBJC_INTEROP
if (!theClass->isTypeMetadata()) return false;
return (theClass->getFlags() & ClassFlags::UsesSwift1Refcounting);
return (theClass->getFlags() & ClassFlags::UsesSwiftRefcounting);
#else
return true;
#endif

View File

@@ -23,8 +23,8 @@
// CHECK-native-SAME: %swift.opaque* null,
// CHECK-objc-SAME: %swift.opaque* @_objc_empty_cache,
// CHECK-SAME: %swift.opaque* null,
// CHECK-SAME: i64 1,
// CHECK-SAME: i32 3,
// CHECK-SAME: i64 {{1|2}},
// CHECK-SAME: i32 2,
// CHECK-SAME: i32 0,
// CHECK-SAME: i32 24,
// CHECK-SAME: i16 7,
@@ -52,8 +52,8 @@
// CHECK-native-SAME: %swift.opaque* null,
// CHECK-objc-SAME: %swift.opaque* @_objc_empty_cache,
// CHECK-SAME: %swift.opaque* null,
// CHECK-SAME: i64 1,
// CHECK-SAME: i32 3,
// CHECK-SAME: i64 {{1|2}},
// CHECK-SAME: i32 2,
// CHECK-SAME: i32 0,
// CHECK-SAME: i32 24,
// CHECK-SAME: i16 7,
@@ -74,8 +74,8 @@
// CHECK-native-SAME: %swift.opaque* null,
// CHECK-objc-SAME: %swift.opaque* @_objc_empty_cache,
// CHECK-SAME: %swift.opaque* null,
// CHECK-SAME: i64 1,
// CHECK-SAME: i32 3,
// CHECK-SAME: i64 {{1|2}},
// CHECK-SAME: i32 2,
// CHECK-SAME: i32 0,
// CHECK-SAME: i32 24,
// CHECK-SAME: i16 7,
@@ -96,8 +96,8 @@
// CHECK-native-SAME: %swift.opaque* null,
// CHECK-objc-SAME: %swift.opaque* @_objc_empty_cache,
// CHECK-SAME: %swift.opaque* null,
// CHECK-SAME: i64 1,
// CHECK-SAME: i32 3,
// CHECK-SAME: i64 {{1|2}},
// CHECK-SAME: i32 2,
// CHECK-SAME: i32 0,
// CHECK-SAME: i32 24,
// CHECK-SAME: i16 7,

View File

@@ -14,8 +14,8 @@
// \ CHECK: [[TYPE]]* bitcast (i64* getelementptr inbounds (<{ {{.*}} }>, <{ {{.*}} }>* @_T014ivar_destroyer11TrivialBaseCMf, i32 0, i32 2) to [[TYPE]]*),
// \ CHECK: [[OPAQUE]]* @_objc_empty_cache,
// \ CHECK: [[OPAQUE]]* null,
// \ CHECK: i64 add (i64 ptrtoint ({{.*}}* @_DATA__TtC14ivar_destroyer17NonTrivialDerived to i64), i64 1),
// \ CHECK: i32 3,
// \ CHECK: i64 add (i64 ptrtoint ({{.*}}* @_DATA__TtC14ivar_destroyer17NonTrivialDerived to i64), i64 {{1|2}}),
// \ CHECK: i32 2,
// \ CHECK: i32 0,
// \ CHECK: i32 24,
// \ CHECK: i16 7,

View File

@@ -27,7 +27,7 @@ sil_vtable X {}
// The getter/setter should not show up in the Swift metadata.
/* FIXME: sil_vtable parser picks the wrong 'init' overload. Both vtable entries
ought to be nonnull here. rdar://problem/19572342 */
// CHECK: @_T019objc_attr_NSManaged10SwiftGizmoCMf = internal global <{ {{.*}} }> <{ void (%T19objc_attr_NSManaged10SwiftGizmoC*)* @_T019objc_attr_NSManaged10SwiftGizmoCfD, i8** @_T0BOWV, i64 ptrtoint (%objc_class* @"OBJC_METACLASS_$__TtC19objc_attr_NSManaged10SwiftGizmo" to i64), %objc_class* @"OBJC_CLASS_$_Gizmo", %swift.opaque* @_objc_empty_cache, %swift.opaque* null, i64 add (i64 ptrtoint ({ i32, i32, i32, i32, i8*, i8*, { i32, i32, [2 x { i8*, i8*, i8* }] }*, i8*, i8*, i8*, { i32, i32, [1 x { i8*, i8* }] }* }* @_DATA__TtC19objc_attr_NSManaged10SwiftGizmo to i64), i64 1), i32 1, i32 0, i32 8, i16 7, i16 0, i32 112, i32 16, {{.*}}* @_T019objc_attr_NSManaged10SwiftGizmoCMn, i8* null, %T19objc_attr_NSManaged10SwiftGizmoC* (i64, %T19objc_attr_NSManaged10SwiftGizmoC*)* @_T019objc_attr_NSManaged10SwiftGizmoC7bellsOnACSi_tcfc, i8* bitcast (void ()* @swift_deletedMethodError to i8*) }>
// CHECK: @_T019objc_attr_NSManaged10SwiftGizmoCMf = internal global <{ {{.*}} }> <{ void (%T19objc_attr_NSManaged10SwiftGizmoC*)* @_T019objc_attr_NSManaged10SwiftGizmoCfD, i8** @_T0BOWV, i64 ptrtoint (%objc_class* @"OBJC_METACLASS_$__TtC19objc_attr_NSManaged10SwiftGizmo" to i64), %objc_class* @"OBJC_CLASS_$_Gizmo", %swift.opaque* @_objc_empty_cache, %swift.opaque* null, i64 add (i64 ptrtoint ({ i32, i32, i32, i32, i8*, i8*, { i32, i32, [2 x { i8*, i8*, i8* }] }*, i8*, i8*, i8*, { i32, i32, [1 x { i8*, i8* }] }* }* @_DATA__TtC19objc_attr_NSManaged10SwiftGizmo to i64), i64 {{1|2}}), i32 0, i32 0, i32 8, i16 7, i16 0, i32 112, i32 16, {{.*}}* @_T019objc_attr_NSManaged10SwiftGizmoCMn, i8* null, %T19objc_attr_NSManaged10SwiftGizmoC* (i64, %T19objc_attr_NSManaged10SwiftGizmoC*)* @_T019objc_attr_NSManaged10SwiftGizmoC7bellsOnACSi_tcfc, i8* bitcast (void ()* @swift_deletedMethodError to i8*) }>
@objc class SwiftGizmo : Gizmo {
@objc @NSManaged var x: X

View File

@@ -26,8 +26,8 @@ sil @_T06vtable1CCfD : $@convention(method) (@owned C) -> ()
// CHECK-objc: %objc_class* @"OBJC_CLASS_$_SwiftObject",
// CHECK-objc: %swift.opaque* @_objc_empty_cache,
// CHECK-objc: %swift.opaque* null,
// CHECK-objc: i64 add (i64 ptrtoint ({ i32, i32, i32, i32, i8*, i8*, i8*, i8*, i8*, i8*, i8* }* @_DATA__TtC6vtable1C to i64), i64 1),
// CHECK-objc: i32 3, i32 0, i32 16, i16 7, i16 0,
// CHECK-objc: i64 add (i64 ptrtoint ({ i32, i32, i32, i32, i8*, i8*, i8*, i8*, i8*, i8*, i8* }* @_DATA__TtC6vtable1C to i64), i64 {{1|2}}),
// CHECK-objc: i32 2, i32 0, i32 16, i16 7, i16 0,
// CHECK-objc: i32 112, i32 16,
// CHECK-objc: @_T06vtable1CCMn
// CHECK-objc: [[C]]* (%swift.type*)* @_T06vtable1CCACycACmcfC,
@@ -42,7 +42,7 @@ sil @_T06vtable1CCfD : $@convention(method) (@owned C) -> ()
// CHECK-native: %swift.opaque* null,
// CHECK-native: %swift.opaque* null,
// CHECK-native: i64 1,
// CHECK-native: i32 3, i32 0, i32 16, i16 7, i16 0,
// CHECK-native: i32 2, i32 0, i32 16, i16 7, i16 0,
// CHECK-native: i32 112, i32 16,
// CHECK-native: @_T06vtable1CCMn
// CHECK-native: [[C]]* (%swift.type*)* @_T06vtable1CCACycACmcfC,

View File

@@ -80,8 +80,8 @@ static SWIFT_CC(swift) void destroyTestObject(SWIFT_CONTEXT HeapObject *_object)
static const FullMetadata<ClassMetadata> TestClassObjectMetadata = {
{ { &destroyTestObject }, { &VALUE_WITNESS_SYM(Bo) } },
{ { { MetadataKind::Class } }, 0, /*rodata*/ 1,
ClassFlags::UsesSwift1Refcounting, 0, 0, 0, 0, 0, 0 }
{ { { MetadataKind::Class } }, 0, SWIFT_CLASS_IS_SWIFT_MASK,
ClassFlags::UsesSwiftRefcounting, 0, 0, 0, 0, 0, 0 }
};
/// Create an object that, when deallocated, stores the given value to

View File

@@ -98,8 +98,8 @@ static SWIFT_CC(swift) void deinitTestObject(SWIFT_CONTEXT HeapObject *_object)
static const FullMetadata<ClassMetadata> TestClassObjectMetadata = {
{ { &deinitTestObject }, { &VALUE_WITNESS_SYM(Bo) } },
{ { { MetadataKind::Class } }, 0, /*rodata*/ 1,
ClassFlags::UsesSwift1Refcounting, 0, 0, 0, 0, 0, 0 }
{ { { MetadataKind::Class } }, 0, SWIFT_CLASS_IS_SWIFT_MASK,
ClassFlags::UsesSwiftRefcounting, 0, 0, 0, 0, 0, 0 }
};
/// Create an object that, when deinited, stores the given value to

View File

@@ -31,8 +31,8 @@ static SWIFT_CC(swift) void destroyTestObject(SWIFT_CONTEXT HeapObject *_object)
static const FullMetadata<ClassMetadata> TestClassObjectMetadata = {
{ { &destroyTestObject }, { &VALUE_WITNESS_SYM(Bo) } },
{ { { MetadataKind::Class } }, 0, /*rodata*/ 1,
ClassFlags::UsesSwift1Refcounting, 0, 0, 0, 0, 0, 0 }
{ { { MetadataKind::Class } }, 0, SWIFT_CLASS_IS_SWIFT_MASK,
ClassFlags::UsesSwiftRefcounting, 0, 0, 0, 0, 0, 0 }
};
/// Create an object that, when deallocated, stores the given value to