Skip to content

Commit b0fe8d4

Browse files
committed
[wip] Remove the Swift bit hack
Turns out that it won’t work for Objective-C subclasses; the superclass realization code path doesn’t try to handle Swift bits or metadata updaters in any way. We’ll need a change to the ObjC runtime to fix that issue, and as long as we’re doing that we might as well support metadata updaters without the Swift bit, so remove the Swift bit hack and add an availability check instead. This will break the resilient parts of the execution tests, hence the [wip].
1 parent 16af02d commit b0fe8d4

File tree

6 files changed

+118
-28
lines changed

6 files changed

+118
-28
lines changed

include/swift/AST/DiagnosticsIRGen.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,5 +69,11 @@ NOTE(layout_strings_blocked,none,
6969
"Layout string value witnesses have been disabled for module '%0' "
7070
"through block list entry", (StringRef))
7171

72+
ERROR(attr_objc_implementation_resilient_property_unsupported, none,
73+
"'@implementation' on %0 %1 does not support stored properties whose "
74+
"size can change due to library evolution; raise the minimum deployment "
75+
"target to %0 %2 or store this value in an object or 'any' type",
76+
(StringRef, const llvm::VersionTuple, const llvm::VersionTuple))
77+
7278
#define UNDEFINE_DIAGNOSTIC_MACROS
7379
#include "DefineDiagnosticMacros.h"

include/swift/AST/FeatureAvailability.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ FEATURE(IsolatedAny, (5, 11))
7474
FEATURE(TaskExecutor, FUTURE)
7575
FEATURE(Differentiation, FUTURE)
7676
FEATURE(InitRawStructMetadata, FUTURE)
77+
FEATURE(UpdatePureObjCClassMetadata, FUTURE)
7778

7879
#undef FEATURE
7980
#undef FUTURE

lib/IRGen/GenMeta.cpp

Lines changed: 79 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4309,6 +4309,9 @@ namespace {
43094309
llvm::Constant *getROData() { return emitClassPrivateData(IGM, Target); }
43104310

43114311
uint64_t getClassDataPointerHasSwiftMetadataBits() {
4312+
// objcImpl classes should not have the Swift bit set.
4313+
if (isPureObjC())
4314+
return 0;
43124315
return IGM.UseDarwinPreStableABIBit ? 1 : 2;
43134316
}
43144317

@@ -4324,20 +4327,13 @@ namespace {
43244327
// Derive the RO-data.
43254328
llvm::Constant *data = asImpl().getROData();
43264329

4327-
// Fixed-layout objcImpl classes should not have the Swift bit set.
4328-
// Variable-layout objcImpl classes have the Swift bit set *temporarily*
4329-
// so that the ObjC runtime realizes them as though they are Swift
4330-
// classes, but the metadata update callback will clear the Swift bit
4331-
// before the rest of the ObjC runtime starts looking at the class.
4332-
if (!isPureObjC() || !hasFixedLayout()) {
4333-
// Set a low bit to indicate this class has Swift metadata.
4334-
auto bit = llvm::ConstantInt::get(
4335-
IGM.IntPtrTy, asImpl().getClassDataPointerHasSwiftMetadataBits());
4336-
4337-
// Emit data + bit.
4338-
data = llvm::ConstantExpr::getPtrToInt(data, IGM.IntPtrTy);
4339-
data = llvm::ConstantExpr::getAdd(data, bit);
4340-
}
4330+
// Set a low bit to indicate this class has Swift metadata.
4331+
auto bit = llvm::ConstantInt::get(
4332+
IGM.IntPtrTy, asImpl().getClassDataPointerHasSwiftMetadataBits());
4333+
4334+
// Emit data + bit.
4335+
data = llvm::ConstantExpr::getPtrToInt(data, IGM.IntPtrTy);
4336+
data = llvm::ConstantExpr::getAdd(data, bit);
43414337

43424338
B.add(data);
43434339
}
@@ -5016,6 +5012,7 @@ namespace {
50165012
}
50175013

50185014
uint64_t getClassDataPointerHasSwiftMetadataBits() {
5015+
assert(!isPureObjC());
50195016
return super::getClassDataPointerHasSwiftMetadataBits() | 2;
50205017
}
50215018

@@ -5060,13 +5057,81 @@ static void emitObjCClassSymbol(IRGenModule &IGM, ClassDecl *classDecl,
50605057
.to(alias, link.isForDefinition());
50615058
}
50625059

5060+
/// Check whether the metadata update strategy requires runtime support that is
5061+
/// not guaranteed available by the minimum deployment target, and diagnose if
5062+
/// so.
5063+
static void
5064+
diagnoseUnsupportedObjCImplLayout(IRGenModule &IGM, ClassDecl *classDecl,
5065+
const ClassLayout &fragileLayout) {
5066+
if (!fragileLayout.hasObjCImplementation())
5067+
return;
5068+
5069+
auto strategy = IGM.getClassMetadataStrategy(classDecl);
5070+
5071+
switch (strategy) {
5072+
case ClassMetadataStrategy::Fixed:
5073+
// Fixed is just fine; no special support needed.
5074+
break;
5075+
5076+
case ClassMetadataStrategy::FixedOrUpdate:
5077+
case ClassMetadataStrategy::Update: {
5078+
auto &ctx = IGM.Context;
5079+
5080+
// Update and FixedOrUpdate require support in both the Swift and ObjC
5081+
// runtimes.
5082+
auto requiredAvailability=ctx.getUpdatePureObjCClassMetadataAvailability();
5083+
// FIXME: Take the class's availability into account
5084+
auto currentAvailability = AvailabilityContext::forDeploymentTarget(ctx);
5085+
if (currentAvailability.isContainedIn(requiredAvailability))
5086+
break;
5087+
5088+
// We don't have the support we need. Find and diagnose the variable-size
5089+
// stored properties.
5090+
auto &diags = ctx.Diags;
5091+
5092+
bool diagnosed = false;
5093+
forEachField(IGM, classDecl, [&](Field field) {
5094+
auto elemLayout = fragileLayout.getFieldAccessAndElement(field).second;
5095+
if (field.getKind() != Field::Kind::Var ||
5096+
elemLayout.getType().isFixedSize())
5097+
return;
5098+
5099+
diags.diagnose(
5100+
field.getVarDecl(),
5101+
diag::attr_objc_implementation_resilient_property_unsupported,
5102+
prettyPlatformString(targetPlatform(ctx.LangOpts)),
5103+
currentAvailability.getOSVersion().getLowerEndpoint(),
5104+
requiredAvailability.getOSVersion().getLowerEndpoint());
5105+
diagnosed = true;
5106+
});
5107+
5108+
// We should have found at least one property to complain about.
5109+
if (diagnosed)
5110+
break;
5111+
5112+
LLVM_FALLTHROUGH;
5113+
}
5114+
5115+
case ClassMetadataStrategy::Singleton:
5116+
case ClassMetadataStrategy::Resilient:
5117+
// This isn't supposed to happen, but just in case, let's give some sort of
5118+
// vaguely legible output instead of using llvm_unreachable().
5119+
IGM.error(classDecl->getLoc(),
5120+
llvm::Twine("class '") + classDecl->getBaseIdentifier().str() +
5121+
"' needs a metadata strategy not supported by @implementation");
5122+
break;
5123+
}
5124+
}
5125+
50635126
/// Emit the type metadata or metadata template for a class.
50645127
void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
50655128
const ClassLayout &fragileLayout,
50665129
const ClassLayout &resilientLayout) {
50675130
assert(!classDecl->isForeign());
50685131
PrettyStackTraceDecl stackTraceRAII("emitting metadata for", classDecl);
50695132

5133+
diagnoseUnsupportedObjCImplLayout(IGM, classDecl, fragileLayout);
5134+
50705135
emitFieldOffsetGlobals(IGM, classDecl, fragileLayout, resilientLayout);
50715136

50725137
// Set up a dummy global to stand in for the metadata object while we produce

stdlib/public/runtime/Metadata.cpp

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3980,16 +3980,6 @@ swift::swift_updatePureObjCClassMetadata(Class cls,
39803980
ClassLayoutFlags flags,
39813981
size_t numFields,
39823982
const TypeLayout * const *fieldTypes) {
3983-
auto self = (ObjCClass *)cls;
3984-
3985-
// Realize the superclass first.
3986-
(void)swift_getInitializedObjCClass((Class)self->Isa);
3987-
3988-
// The Swift bit has been set so that we use Swift class initialization paths,
3989-
// but from here on in, we want to treat this as a pure ObjC class. Clear it.
3990-
auto rodata = getROData(self);
3991-
self->RODataAndFlags = (uintptr_t)rodata;
3992-
39933983
bool requiresRealizeClassFromSwift =
39943984
SWIFT_RUNTIME_WEAK_CHECK(_objc_realizeClassFromSwift);
39953985
assert(requiresRealizeClassFromSwift);
@@ -4002,7 +3992,10 @@ swift::swift_updatePureObjCClassMetadata(Class cls,
40023992

40033993
// Update the field offset globals using runtime type information; the layout
40043994
// of resilient types might be different than the statically-emitted layout.
3995+
ObjCClass *self = (ObjCClass *)cls;
3996+
ClassROData *rodata = getROData(self);
40053997
ClassIvarList *ivars = rodata->IvarList;
3998+
40063999
if (!ivars) {
40074000
assert(numFields == 0);
40084001
return cls;

test/IRGen/objc_implementation.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Test doesn't pass on all platforms (rdar://101420862)
22
// REQUIRES: OS=macosx
33

4-
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -I %S/Inputs/abi -F %clang-importer-sdk-path/frameworks %s -import-objc-header %S/Inputs/objc_implementation.h -emit-ir > %t.ir
4+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -I %S/Inputs/abi -F %clang-importer-sdk-path/frameworks %s -import-objc-header %S/Inputs/objc_implementation.h -emit-ir -target %target-future-triple > %t.ir
55
// RUN: %FileCheck --input-file %t.ir %s
66
// RUN: %FileCheck --input-file %t.ir --check-prefix NEGATIVE %s
77
// REQUIRES: objc_interop
@@ -17,7 +17,7 @@
1717

1818
// Metaclass
1919
// CHECK: @"OBJC_METACLASS_$_ImplClass" = global %objc_class { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, {{.*}}ptr [[_METACLASS_DATA_ImplClass:@[^, ]+]]{{.*}}, align 8
20-
// CHECK: @_PROTOCOLS_ImplClass = internal constant { i64, [2 x ptr] } { i64 2, [2 x ptr] [ptr @_PROTOCOL_NSCopying, ptr @_PROTOCOL_NSMutableCopying] }, section "__DATA, __objc_const", align 8
20+
// CHECK: @_PROTOCOLS_ImplClass = internal constant { i64, [2 x ptr] } { i64 2, [2 x ptr] [ptr @"_OBJC_PROTOCOL_$_NSCopying", ptr @"_OBJC_PROTOCOL_$_NSMutableCopying"] }, section "__DATA, __objc_const", align 8
2121
// CHECK: [[_METACLASS_DATA_ImplClass]] = internal constant { i32, i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr } { i32 129, i32 40, i32 40, i32 0, ptr null, ptr @.str.9.ImplClass, ptr null, ptr @_PROTOCOLS_ImplClass, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
2222
// TODO: Why the extra i32 field above?
2323

@@ -121,7 +121,7 @@
121121
// CHECK: @"$s19objc_implementationMXM" = linkonce_odr hidden constant <{ i32, i32, i32 }> <{ i32 0, i32 0, i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.19.objc_implementation to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32, i32 }>, ptr @"$s19objc_implementationMXM", i32 0, i32 2) to i64)) to i32) }>, section "__TEXT,__constg_swiftt", align 4
122122
// CHECK: @"symbolic So9ImplClassC" = linkonce_odr hidden constant <{ [13 x i8], i8 }> <{ [13 x i8] c"So9ImplClassC", i8 0 }>, section "__TEXT,__swift5_typeref, regular"{{.*}}, align 2
123123
// CHECK: @"$s19objc_implementation13SwiftSubclassCMn" = constant <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }> <{ i32 80, i32 trunc (i64 sub (i64 ptrtoint (ptr @"$s19objc_implementationMXM" to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, ptr @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 1) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @.str.13.SwiftSubclass to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, ptr @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @"$s19objc_implementation13SwiftSubclassCMa" to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, ptr @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 3) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @"$s19objc_implementation13SwiftSubclassCMF" to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, ptr @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 4) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @"symbolic So9ImplClassC" to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, ptr @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 5) to i64)) to i32), i32 3, i32 10, i32 0, i32 0, i32 10 }>, section "__TEXT,__constg_swiftt", align 4
124-
// CHECK: @"$s19objc_implementation13SwiftSubclassCMf" = internal global <{ ptr, ptr, ptr, i64, ptr, ptr, ptr, i64, i32, i32, i32, i16, i16, i32, i32, ptr, ptr }> <{ ptr null, ptr @"$s19objc_implementation13SwiftSubclassCfD", ptr @"$sBOWV", i64 ptrtoint (ptr @"OBJC_METACLASS_$__TtC19objc_implementation13SwiftSubclass" to i64), ptr @"OBJC_CLASS_$_ImplClass", ptr @_objc_empty_cache, ptr null, i64 add (i64 ptrtoint (ptr @_DATA__TtC19objc_implementation13SwiftSubclass to i64), i64 1), i32 0, i32 0, i32 24, i16 7, i16 0, i32 104, i32 24, ptr @"$s19objc_implementation13SwiftSubclassCMn", ptr null }>, section "__DATA,__objc_data, regular", align 8
124+
// CHECK: @"$s19objc_implementation13SwiftSubclassCMf" = internal global <{ ptr, ptr, ptr, i64, ptr, ptr, ptr, i64, i32, i32, i32, i16, i16, i32, i32, ptr, ptr }> <{ ptr null, ptr @"$s19objc_implementation13SwiftSubclassCfD", ptr @"$sBOWV", i64 ptrtoint (ptr @"OBJC_METACLASS_$__TtC19objc_implementation13SwiftSubclass" to i64), ptr @"OBJC_CLASS_$_ImplClass", ptr @_objc_empty_cache, ptr null, i64 add (i64 ptrtoint (ptr @_DATA__TtC19objc_implementation13SwiftSubclass to i64), i64 2), i32 0, i32 0, i32 24, i16 7, i16 0, i32 104, i32 24, ptr @"$s19objc_implementation13SwiftSubclassCMn", ptr null }>, section "__DATA,__objc_data, regular", align 8
125125
// CHECK: @"symbolic _____ 19objc_implementation13SwiftSubclassC" = linkonce_odr hidden constant <{ i8, i32, i8 }> <{ i8 1, i32 trunc (i64 sub (i64 ptrtoint (ptr @"$s19objc_implementation13SwiftSubclassCMn" to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i8, i32, i8 }>, ptr @"symbolic _____ 19objc_implementation13SwiftSubclassC", i32 0, i32 1) to i64)) to i32), i8 0 }>, section "__TEXT,__swift5_typeref, regular"{{.*}}, align 2
126126
// CHECK: @"$s19objc_implementation13SwiftSubclassCMF" = internal constant { i32, i32, i16, i16, i32 } { i32 trunc (i64 sub (i64 ptrtoint (ptr @"symbolic _____ 19objc_implementation13SwiftSubclassC" to i64), i64 ptrtoint (ptr @"$s19objc_implementation13SwiftSubclassCMF" to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (ptr @"symbolic So9ImplClassC" to i64), i64 ptrtoint (ptr getelementptr inbounds ({ i32, i32, i16, i16, i32 }, ptr @"$s19objc_implementation13SwiftSubclassCMF", i32 0, i32 1) to i64)) to i32), i16 7, i16 12, i32 0 }, section "__TEXT,__swift5_fieldmd, regular"{{.*}}, align 4
127127
open class SwiftSubclass: ImplClass {
@@ -142,7 +142,7 @@ open class SwiftSubclass: ImplClass {
142142
// Class
143143
// CHECK: @_IVARS_ImplClassWithResilientStoredProperty = internal constant { i32, i32, [4 x { ptr, ptr, ptr, i32, i32 }] } { i32 32, i32 4, [4 x { ptr, ptr, ptr, i32, i32 }] [{ ptr, ptr, ptr, i32, i32 } { ptr @"$sSo36ImplClassWithResilientStoredPropertyC19objc_implementationE9beforeInts5Int32VvpWvd", ptr @.str.9.beforeInt, ptr @.str.0., i32 2, i32 4 }, { ptr, ptr, ptr, i32, i32 } { ptr @"$sSo36ImplClassWithResilientStoredPropertyC19objc_implementationE6mirrors6MirrorVSgvpWvd", ptr @.str.6.mirror, ptr @.str.0., i32 0, i32 0 }, { ptr, ptr, ptr, i32, i32 } { ptr @"$sSo36ImplClassWithResilientStoredPropertyC19objc_implementationE13afterIntFinals5Int32VvpWvd", ptr @.str.13.afterIntFinal, ptr @.str.0., i32 2, i32 4 }, { ptr, ptr, ptr, i32, i32 } { ptr @"$sSo36ImplClassWithResilientStoredPropertyC19objc_implementationE8afterInts5Int32VvpWvd", ptr @.str.8.afterInt, ptr @.str.0., i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
144144
// CHECK: @_DATA_ImplClassWithResilientStoredProperty = internal constant { i32, i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr } { i32 452, i32 8, i32 20, i32 0, ptr null, ptr @.str.36.ImplClassWithResilientStoredProperty, ptr @_INSTANCE_METHODS_ImplClassWithResilientStoredProperty, ptr null, ptr @_IVARS_ImplClassWithResilientStoredProperty, ptr null, ptr @_PROPERTIES_ImplClassWithResilientStoredProperty, ptr @"$sSo36ImplClassWithResilientStoredPropertyCMU" }, section "__DATA, __objc_data", align 8
145-
// CHECK: @"OBJC_CLASS_$_ImplClassWithResilientStoredProperty" = global <{ i64, ptr, ptr, ptr, i64 }> <{ i64 ptrtoint (ptr @"OBJC_METACLASS_$_ImplClassWithResilientStoredProperty" to i64), ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, i64 add (i64 ptrtoint (ptr @_DATA_ImplClassWithResilientStoredProperty to i64), i64 1) }>, section "__DATA,__objc_data, regular", align 8
145+
// CHECK: @"OBJC_CLASS_$_ImplClassWithResilientStoredProperty" = global <{ i64, ptr, ptr, ptr, i64 }> <{ i64 ptrtoint (ptr @"OBJC_METACLASS_$_ImplClassWithResilientStoredProperty" to i64), ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, i64 add (i64 ptrtoint (ptr @_DATA_ImplClassWithResilientStoredProperty to i64), i64 2) }>, section "__DATA,__objc_data, regular", align 8
146146

147147
@_objcImplementation extension ImplClassWithResilientStoredProperty {
148148
@objc var beforeInt: Int32 = 0
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -target %target-stable-abi-triple -I %S/Inputs/abi -F %clang-importer-sdk-path/frameworks %s -import-objc-header %S/Inputs/objc_implementation.h -emit-ir -o %t.ir -enable-library-evolution -verify
2+
// REQUIRES: objc_interop
3+
4+
@_objcImplementation extension ImplClassWithResilientStoredProperty {
5+
@objc var beforeInt: Int32 = 0 // no-error
6+
final var a: Mirror? // expected-error {{does not support stored properties whose size can change due to library evolution; raise the minimum deployment target to}}
7+
final var b: AnyKeyPath? // no-error
8+
final var c: Int = 0 // no-error
9+
final var d: S1? // no-error
10+
final var e: S2? // expected-error {{does not support stored properties whose size can change due to library evolution; raise the minimum deployment target to}}
11+
final var f: C1? // no-error
12+
@objc var afterInt: Int32 = 0 // no-error
13+
}
14+
15+
public struct S1 {
16+
var int = 1
17+
}
18+
19+
public struct S2 {
20+
var mirror: Mirror?
21+
}
22+
23+
public class C1 {
24+
var mirror: Mirror?
25+
}

0 commit comments

Comments
 (0)