Support resilient stored properties in objcImpl

When an @objc @implementation class requires the use of `ClassMetadataStrategy::Update` because some of its stored properties do not have fixed sizes, we adjust the direct field offsets during class realization by emitting a custom metadata update function which calls a new entry point in the Swift runtime. That entry point adjusts field offsets like `swift_updateClassMetadata2()`, but it only assumes that the class has Objective-C metadata, not Swift metadata.

This commit introduces an alternative mechanism which does the same thing without using any Swift-only metadata. It’s a rough implementation with important limitations:

• We’re currently using the field offset vector, which means that field offsets are being emitted into @objc @implementation classes; these will be removed.
• The new Swift runtime entry point duplicates a lot of `swift_updateClassMetadata2()`’s implementation; it will be refactored into something much smaller and more compact.
• Availability bounds for this feature have not yet been implemented.

Future commits in this PR will correct these issues.
This commit is contained in:
Becca Royal-Gordon
2024-04-30 12:03:44 -07:00
parent 9e83099279
commit 427386feea
14 changed files with 830 additions and 167 deletions

View File

@@ -782,6 +782,14 @@ swift_updateClassMetadata2(ClassMetadata *self,
size_t numFields,
const TypeLayout * const *fieldTypes,
size_t *fieldOffsets);
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
Class
swift_updatePureObjCClassMetadata(Class self,
ClassLayoutFlags flags,
size_t numFields,
const TypeLayout * const *fieldTypes,
size_t *fieldOffsets);
#endif
/// Given class metadata, a class descriptor and a method descriptor, look up

View File

@@ -1437,6 +1437,21 @@ FUNCTION(UpdateClassMetadata2,
EFFECT(MetaData),
UNKNOWN_MEMEFFECTS)
// objc_class *swift_updatePureObjCClassMetadata(objc_class *self,
// ClassLayoutFlags flags,
// size_t numFields,
// TypeLayout * const *fieldTypes,
// size_t *fieldOffsets);
FUNCTION(UpdatePureObjCClassMetadata,
swift_updatePureObjCClassMetadata, SwiftCC, AlwaysAvailable,
RETURNS(ObjCClassPtrTy),
ARGS(ObjCClassPtrTy, SizeTy, SizeTy,
Int8PtrPtrTy->getPointerTo(),
SizeTy->getPointerTo()),
ATTRS(NoUnwind),
EFFECT(MetaData),
UNKNOWN_MEMEFFECTS)
// void *swift_lookUpClassMethod(Metadata *metadata,
// ClassDescriptor *description,
// MethodDescriptor *method);

View File

@@ -2561,12 +2561,27 @@ static llvm::Function *emitObjCMetadataUpdateFunction(IRGenModule &IGM,
Explosion params = IGF.collectParameters();
(void) params.claimAll();
// Just directly call our metadata accessor. This should actually
// return the same metadata; the Objective-C runtime enforces this.
auto type = D->getDeclaredType()->getCanonicalType();
auto *metadata = IGF.emitTypeMetadataRef(type,
MetadataState::Complete)
.getMetadata();
llvm::Value *metadata;
if (D->getObjCImplementationDecl()) {
// This is an @objc @implementation class, so it has no metadata completion
// function. We must do the completion function's work here, taking care to
// fetch the address of the ObjC class without going through either runtime.
metadata = IGM.getAddrOfObjCClass(D, NotForDefinition);
auto loweredTy = IGM.getLoweredType(D->getDeclaredTypeInContext());
IGF.emitInitializeFieldOffsetVector(loweredTy, metadata,
/*isVWTMutable=*/false,
/*collector=*/nullptr);
} else {
// Just call our metadata accessor, which will cause the Swift runtime to
// call the metadata completion function if there is one. This should
// actually return the same metadata; the Objective-C runtime enforces this.
auto type = D->getDeclaredType()->getCanonicalType();
metadata = IGF.emitTypeMetadataRef(type,
MetadataState::Complete)
.getMetadata();
}
IGF.Builder.CreateRet(
IGF.Builder.CreateBitCast(metadata,
IGM.ObjCClassPtrTy));

View File

@@ -2948,37 +2948,34 @@ IRGenModule::getAddrOfOriginalModuleContextDescriptor(StringRef Name) {
.first->getValue());
}
static void emitInitializeFieldOffsetVector(IRGenFunction &IGF,
SILType T,
llvm::Value *metadata,
bool isVWTMutable,
MetadataDependencyCollector *collector) {
auto &IGM = IGF.IGM;
void IRGenFunction::
emitInitializeFieldOffsetVector(SILType T, llvm::Value *metadata,
bool isVWTMutable,
MetadataDependencyCollector *collector) {
auto *target = T.getNominalOrBoundGenericNominal();
llvm::Value *fieldVector
= emitAddressOfFieldOffsetVector(IGF, metadata, target)
= emitAddressOfFieldOffsetVector(*this, metadata, target)
.getAddress();
// Collect the stored properties of the type.
unsigned numFields = getNumFields(target);
// Fill out an array with the field type metadata records.
Address fields = IGF.createAlloca(
llvm::ArrayType::get(IGM.Int8PtrPtrTy, numFields),
IGM.getPointerAlignment(), "classFields");
IGF.Builder.CreateLifetimeStart(fields, IGM.getPointerSize() * numFields);
fields = IGF.Builder.CreateStructGEP(fields, 0, Size(0));
Address fields = createAlloca(
llvm::ArrayType::get(IGM.Int8PtrPtrTy, numFields),
IGM.getPointerAlignment(), "classFields");
Builder.CreateLifetimeStart(fields, IGM.getPointerSize() * numFields);
fields = Builder.CreateStructGEP(fields, 0, Size(0));
unsigned index = 0;
forEachField(IGM, target, [&](Field field) {
assert(field.isConcrete() &&
"initializing offset vector for type with missing member?");
SILType propTy = field.getType(IGM, T);
llvm::Value *fieldLayout = emitTypeLayoutRef(IGF, propTy, collector);
llvm::Value *fieldLayout = emitTypeLayoutRef(*this, propTy, collector);
Address fieldLayoutAddr =
IGF.Builder.CreateConstArrayGEP(fields, index, IGM.getPointerSize());
IGF.Builder.CreateStore(fieldLayout, fieldLayoutAddr);
Builder.CreateConstArrayGEP(fields, index, IGM.getPointerSize());
Builder.CreateStore(fieldLayout, fieldLayoutAddr);
++index;
});
assert(index == numFields);
@@ -3004,29 +3001,38 @@ static void emitInitializeFieldOffsetVector(IRGenFunction &IGF,
llvm_unreachable("Emitting metadata init for fixed class metadata?");
}
llvm::Value *dependency;
llvm::Value *dependency = nullptr;
switch (IGM.getClassMetadataStrategy(classDecl)) {
case ClassMetadataStrategy::Resilient:
case ClassMetadataStrategy::Singleton:
// Call swift_initClassMetadata().
dependency = IGF.Builder.CreateCall(
IGM.getInitClassMetadata2FunctionPointer(),
{metadata, IGM.getSize(Size(uintptr_t(flags))), numFieldsV,
fields.getAddress(), fieldVector});
assert(fieldVector && "Singleton/Resilient strategies not supported for "
"objcImplementation");
dependency = Builder.CreateCall(
IGM.getInitClassMetadata2FunctionPointer(),
{metadata, IGM.getSize(Size(uintptr_t(flags))), numFieldsV,
fields.getAddress(), fieldVector});
break;
case ClassMetadataStrategy::Update:
case ClassMetadataStrategy::FixedOrUpdate:
assert(IGM.Context.LangOpts.EnableObjCInterop);
// Call swift_updateClassMetadata(). Note that the static metadata
// already references the superclass in this case, but we still want
// to ensure the superclass metadata is initialized first.
dependency = IGF.Builder.CreateCall(
IGM.getUpdateClassMetadata2FunctionPointer(),
{metadata, IGM.getSize(Size(uintptr_t(flags))), numFieldsV,
fields.getAddress(), fieldVector});
if (!classDecl->getObjCImplementationDecl()) {
// Call swift_updateClassMetadata(). Note that the static metadata
// already references the superclass in this case, but we still want
// to ensure the superclass metadata is initialized first.
dependency = Builder.CreateCall(
IGM.getUpdateClassMetadata2FunctionPointer(),
{metadata, IGM.getSize(Size(uintptr_t(flags))), numFieldsV,
fields.getAddress(), fieldVector});
} else {
Builder.CreateCall(
IGM.getUpdatePureObjCClassMetadataFunctionPointer(),
{metadata, IGM.getSize(Size(uintptr_t(flags))), numFieldsV,
fields.getAddress(), fieldVector});
}
break;
case ClassMetadataStrategy::Fixed:
@@ -3035,8 +3041,8 @@ static void emitInitializeFieldOffsetVector(IRGenFunction &IGF,
// Collect any possible dependency from initializing the class; generally
// this involves the superclass.
assert(collector);
collector->collect(IGF, dependency);
if (collector && dependency)
collector->collect(*this, dependency);
} else {
assert(isa<StructDecl>(target));
@@ -3047,12 +3053,12 @@ static void emitInitializeFieldOffsetVector(IRGenFunction &IGF,
flags |= StructLayoutFlags::IsVWTMutable;
// Call swift_initStructMetadata().
IGF.Builder.CreateCall(IGM.getInitStructMetadataFunctionPointer(),
{metadata, IGM.getSize(Size(uintptr_t(flags))),
numFieldsV, fields.getAddress(), fieldVector});
Builder.CreateCall(IGM.getInitStructMetadataFunctionPointer(),
{metadata, IGM.getSize(Size(uintptr_t(flags))),
numFieldsV, fields.getAddress(), fieldVector});
}
IGF.Builder.CreateLifetimeEnd(fields, IGM.getPointerSize() * numFields);
Builder.CreateLifetimeEnd(fields, IGM.getPointerSize() * numFields);
}
static void emitInitializeFieldOffsetVectorWithLayoutString(
@@ -3314,8 +3320,8 @@ static void emitInitializeValueMetadata(IRGenFunction &IGF,
emitInitializeFieldOffsetVectorWithLayoutString(IGF, loweredTy, metadata,
isVWTMutable, collector);
} else {
emitInitializeFieldOffsetVector(IGF, loweredTy, metadata, isVWTMutable,
collector);
IGF.emitInitializeFieldOffsetVector(loweredTy, metadata, isVWTMutable,
collector);
}
} else {
assert(isa<EnumDecl>(nominalDecl));
@@ -3347,9 +3353,9 @@ static void emitInitializeClassMetadata(IRGenFunction &IGF,
// Set the superclass, fill out the field offset vector, and copy vtable
// entries, generic requirements and field offsets from superclasses.
emitInitializeFieldOffsetVector(IGF, loweredTy,
metadata, /*VWT is mutable*/ false,
collector);
IGF.emitInitializeFieldOffsetVector(loweredTy,
metadata, /*VWT is mutable*/ false,
collector);
// Realizing the class with the ObjC runtime will copy back to the
// field offset globals for us; but if ObjC interop is disabled, we
@@ -3721,6 +3727,25 @@ createSingletonInitializationMetadataAccessFunction(IRGenModule &IGM,
[&](IRGenFunction &IGF,
DynamicMetadataRequest request,
llvm::Constant *cacheVariable) {
if (auto CD = dyn_cast<ClassDecl>(typeDecl)) {
if (CD->getObjCImplementationDecl()) {
// Use the Objective-C runtime symbol instead of the Swift one.
llvm::Value *descriptor =
IGF.IGM.getAddrOfObjCClass(CD, NotForDefinition);
// Make the ObjC runtime initialize the class.
llvm::Value *initializedDescriptor =
IGF.Builder.CreateCall(IGF.IGM.getFixedClassInitializationFn(),
{descriptor});
// Turn the ObjC class into a valid Swift metadata pointer.
auto response =
IGF.Builder.CreateCall(IGF.IGM.getGetObjCClassMetadataFunctionPointer(),
{initializedDescriptor});
return MetadataResponse::forComplete(response);
}
}
llvm::Value *descriptor =
IGF.IGM.getAddrOfTypeContextDescriptor(typeDecl, RequireMetadata);
auto responsePair =
@@ -4275,6 +4300,9 @@ namespace {
llvm::Constant *getROData() { return emitClassPrivateData(IGM, Target); }
uint64_t getClassDataPointerHasSwiftMetadataBits() {
// objcImpl classes should not have the Swift bit set.
if (isPureObjC())
return 0;
return IGM.UseDarwinPreStableABIBit ? 1 : 2;
}
@@ -4290,15 +4318,13 @@ namespace {
// Derive the RO-data.
llvm::Constant *data = asImpl().getROData();
if (!asImpl().getFieldLayout().hasObjCImplementation()) {
// Set a low bit to indicate this class has Swift metadata.
auto bit = llvm::ConstantInt::get(
IGM.IntPtrTy, asImpl().getClassDataPointerHasSwiftMetadataBits());
// Set a low bit to indicate this class has Swift metadata.
auto bit = llvm::ConstantInt::get(
IGM.IntPtrTy, asImpl().getClassDataPointerHasSwiftMetadataBits());
// Emit data + bit.
data = llvm::ConstantExpr::getPtrToInt(data, IGM.IntPtrTy);
data = llvm::ConstantExpr::getAdd(data, bit);
}
// Emit data + bit.
data = llvm::ConstantExpr::getPtrToInt(data, IGM.IntPtrTy);
data = llvm::ConstantExpr::getAdd(data, bit);
B.add(data);
}
@@ -4369,6 +4395,9 @@ namespace {
if (IGM.getClassMetadataStrategy(Target) == ClassMetadataStrategy::Fixed)
return;
if (isPureObjC())
return;
emitMetadataCompletionFunction(
IGM, Target,
[&](IRGenFunction &IGF, llvm::Value *metadata,
@@ -4409,9 +4438,6 @@ namespace {
: super(IGM, theClass, builder, fieldLayout, vtable) {}
void addFieldOffset(VarDecl *var) {
if (asImpl().getFieldLayout().hasObjCImplementation())
return;
addFixedFieldOffset(IGM, B, var, [](DeclContext *dc) {
return dc->getDeclaredTypeInContext();
});
@@ -4443,18 +4469,12 @@ namespace {
: super(IGM, theClass, builder, fieldLayout) {}
void addFieldOffset(VarDecl *var) {
if (asImpl().getFieldLayout().hasObjCImplementation())
return;
// Field offsets are either copied from the superclass or calculated
// at runtime.
B.addInt(IGM.SizeTy, 0);
}
void addFieldOffsetPlaceholders(MissingMemberDecl *placeholder) {
if (asImpl().getFieldLayout().hasObjCImplementation())
return;
for (unsigned i = 0,
e = placeholder->getNumberOfFieldOffsetVectorEntries();
i < e; ++i) {
@@ -4955,9 +4975,6 @@ namespace {
}
void addFieldOffset(VarDecl *var) {
if (asImpl().getFieldLayout().hasObjCImplementation())
return;
addFixedFieldOffset(IGM, B, var, [&](DeclContext *dc) {
return dc->mapTypeIntoContext(type);
});
@@ -4980,6 +4997,7 @@ namespace {
}
uint64_t getClassDataPointerHasSwiftMetadataBits() {
assert(!isPureObjC());
return super::getClassDataPointerHasSwiftMetadataBits() | 2;
}

View File

@@ -59,6 +59,7 @@ namespace irgen {
class IRGenModule;
class LinkEntity;
class LocalTypeDataCache;
class MetadataDependencyCollector;
class MetadataResponse;
class Scope;
class TypeInfo;
@@ -407,6 +408,12 @@ public:
llvm::Value *&metadataSlot,
ValueWitness index);
void emitInitializeFieldOffsetVector(SILType T,
llvm::Value *metadata,
bool isVWTMutable,
MetadataDependencyCollector *collector);
llvm::Value *optionallyLoadFromConditionalProtocolWitnessTable(
llvm::Value *wtable);

View File

@@ -3195,6 +3195,13 @@ namespace {
const uint8_t *WeakIvarLayout;
const void *PropertyList;
};
struct ObjCClass {
ObjCClass *Isa;
ObjCClass *Superclass;
void *CacheData[2];
uintptr_t RODataAndFlags;
};
} // end anonymous namespace
#if SWIFT_OBJC_INTEROP
@@ -3212,6 +3219,9 @@ static inline ClassROData *getROData(ClassMetadata *theClass) {
return (ClassROData*)(theClass->Data & ~uintptr_t(SWIFT_CLASS_IS_SWIFT_MASK));
}
static inline ClassROData *getROData(ObjCClass *theClass) {
return (ClassROData*)(theClass->RODataAndFlags & ~uintptr_t(SWIFT_CLASS_IS_SWIFT_MASK));
}
// This gets called if we fail during copyGenericClassObjcName(). Its job is
// to generate a unique name, even though the name won't be very helpful if
// we end up looking at it in a debugger.
@@ -3964,6 +3974,150 @@ swift::swift_updateClassMetadata2(ClassMetadata *self,
/*allowDependency*/ true);
}
static void initClassFieldOffsetVector(ObjCClass *self,
size_t numFields,
const TypeLayout * const *fieldTypes,
size_t *fieldOffsets) {
size_t size, alignMask;
ClassROData *rodata = getROData(self);
// Start layout from our static notion of where the superclass starts.
// Objective-C expects us to have generated a correct ivar layout, which it
// will simply slide if it needs to.
assert(self->Superclass && "Swift cannot implement a root class");
size = rodata->InstanceStart;
alignMask = 0xF; // malloc alignment guarantee
// Okay, now do layout.
for (unsigned i = 0; i != numFields; ++i) {
auto *eltLayout = fieldTypes[i];
// Skip empty fields.
if (fieldOffsets[i] == 0 && eltLayout->size == 0)
continue;
auto offset = roundUpToAlignMask(size,
eltLayout->flags.getAlignmentMask());
fieldOffsets[i] = offset;
size = offset + eltLayout->size;
alignMask = std::max(alignMask, eltLayout->flags.getAlignmentMask());
}
// Save the size into the Objective-C metadata.
if (rodata->InstanceSize != size)
rodata->InstanceSize = size;
}
/// Non-generic classes only. Initialize the Objective-C ivar descriptors and
/// field offset globals. Does *not* register the class with the Objective-C
/// runtime; that must be done by the caller.
///
/// This function copies the ivar descriptors and updates each ivar global with
/// the corresponding offset in \p fieldOffsets, before asking the Objective-C
/// runtime to realize the class. The Objective-C runtime will then slide the
/// offsets stored in those globals.
///
/// Note that \p fieldOffsets remains unchanged in this case.
static void initObjCClass(ObjCClass *self,
size_t numFields,
const TypeLayout * const *fieldTypes,
size_t *fieldOffsets) {
ClassROData *rodata = getROData(self);
ClassIvarList *ivars = rodata->IvarList;
if (!ivars) {
assert(numFields == 0);
return;
}
assert(ivars->Count == numFields);
assert(ivars->EntrySize == sizeof(ClassIvarEntry));
bool copiedIvarList = false;
for (unsigned i = 0; i != numFields; ++i) {
auto *eltLayout = fieldTypes[i];
ClassIvarEntry *ivar = &ivars->getIvars()[i];
// Fill in the field offset global, if this ivar has one.
if (ivar->Offset) {
if (*ivar->Offset != fieldOffsets[i])
*ivar->Offset = fieldOffsets[i];
}
// If the ivar's size doesn't match the field layout we
// computed, overwrite it and give it better type information.
if (ivar->Size != eltLayout->size) {
// If we're going to modify the ivar list, we need to copy it first.
if (!copiedIvarList) {
auto ivarListSize = sizeof(ClassIvarList) +
numFields * sizeof(ClassIvarEntry);
ivars = (ClassIvarList*) getResilientMetadataAllocator()
.Allocate(ivarListSize, alignof(ClassIvarList));
memcpy(ivars, rodata->IvarList, ivarListSize);
rodata->IvarList = ivars;
copiedIvarList = true;
// Update ivar to point to the newly copied list.
ivar = &ivars->getIvars()[i];
}
ivar->Size = eltLayout->size;
ivar->Type = nullptr;
ivar->Log2Alignment =
getLog2AlignmentFromMask(eltLayout->flags.getAlignmentMask());
}
}
}
Class
swift::swift_updatePureObjCClassMetadata(Class cls,
ClassLayoutFlags flags,
size_t numFields,
const TypeLayout * const *fieldTypes,
size_t *fieldOffsets) {
auto self = (ObjCClass *)cls;
bool requiresUpdate = SWIFT_RUNTIME_WEAK_CHECK(_objc_realizeClassFromSwift);
// Realize the superclass first.
(void)swift_getInitializedObjCClass((Class)self->Isa);
auto ROData = getROData(self);
// If we're running on a older Objective-C runtime, just realize
// the class.
if (!requiresUpdate) {
// If we don't have a backward deployment layout, we cannot proceed here.
if (ROData->InstanceSize == 0) {
fatalError(0, "class %s does not have a fragile layout; "
"the deployment target was newer than this OS\n",
ROData->Name);
}
// Realize the class. This causes the runtime to slide the field offsets
// stored in the field offset globals.
//
// Note that the field offset vector is *not* updated; however in
// Objective-C interop mode, we don't actually use the field offset vector
// of non-generic classes.
//
// In particular, class mirrors always use the Objective-C ivar descriptors,
// which point at field offset globals and not the field offset vector.
swift_getInitializedObjCClass((Class)self);
} else {
// Update the field offset vector using runtime type information; the layout
// of resilient types might be different than the statically-emitted layout.
initClassFieldOffsetVector(self, numFields, fieldTypes, fieldOffsets);
// Copy field offset vector entries to the field offset globals.
initObjCClass(self, numFields, fieldTypes, fieldOffsets);
// See remark above about how this slides field offset globals.
SWIFT_RUNTIME_WEAK_USE(_objc_realizeClassFromSwift(cls, cls));
}
return cls;
}
#endif
#ifndef NDEBUG

View File

@@ -48,3 +48,10 @@ extern void implFuncCName(int param) __asm__("_implFuncAsmName");
@property (strong, nonnull) NSString *s4;
@end
@interface ImplClassWithResilientStoredProperty : NSObject
@property (assign) int beforeInt;
@property (assign) int afterInt;
@end

View File

@@ -6,10 +6,10 @@
// RUN: %FileCheck --input-file %t.ir --check-prefix NEGATIVE %s
// REQUIRES: objc_interop
// CHECK: [[selector_data_implProperty:@[^, ]+]] = private global [13 x i8] c"implProperty\00", section "__TEXT,__objc_methname,cstring_literals", align 1
// CHECK: [[selector_data_setImplProperty_:@[^, ]+]] = private global [17 x i8] c"setImplProperty:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
// CHECK: [[selector_data_mainMethod_:@[^, ]+]] = private global [12 x i8] c"mainMethod:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
// CHECK-DAG: @"$sSo36ImplClassWithResilientStoredPropertyC19objc_implementationE9beforeInts5Int32VvpWvd" = hidden global i64 8, align 8
// CHECK-DAG: @"$sSo36ImplClassWithResilientStoredPropertyC19objc_implementationE6mirrors6MirrorVSgvpWvd" = hidden global i64 0, align 8
// CHECK-DAG: @"$sSo36ImplClassWithResilientStoredPropertyC19objc_implementationE13afterIntFinals5Int32VvpWvd" = hidden global i64 0, align 8
// CHECK-DAG: @"$sSo36ImplClassWithResilientStoredPropertyC19objc_implementationE8afterInts5Int32VvpWvd" = hidden global i64 0, align 8
//
// @_objcImplementation class
@@ -23,12 +23,12 @@
// Class
// CHECK: [[selector_data__cxx_destruct:@[^, ]+]] = private global [14 x i8] c".cxx_destruct\00", section "__TEXT,__objc_methname,cstring_literals", align 1
// CHECK: [[_INSTANCE_METHODS_ImplClass:@[^, ]+]] = internal constant { i32, i32, [9 x { ptr, ptr, ptr }] } { i32 24, i32 9, [9 x { ptr, ptr, ptr }] [{ ptr, ptr, ptr } { ptr @"\01L_selector_data(init)", ptr @".str.7.@16@0:8", ptr @"$sSo9ImplClassC19objc_implementationEABycfcTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr [[selector_data_implProperty]], ptr @".str.7.i16@0:8", ptr @"$sSo9ImplClassC19objc_implementationE12implPropertys5Int32VvgTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr [[selector_data_setImplProperty_]], ptr @".str.10.v20@0:8i16", ptr @"$sSo9ImplClassC19objc_implementationE12implPropertys5Int32VvsTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr [[selector_data_mainMethod_]], ptr @".str.10.v20@0:8i16", ptr @"$sSo9ImplClassC19objc_implementationE10mainMethodyys5Int32VFTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr @"\01L_selector_data(extensionMethod:)", ptr @".str.10.v20@0:8i16", ptr @"$sSo9ImplClassC19objc_implementationE15extensionMethodyys5Int32VFTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr @"\01L_selector_data(copyWithZone:)", ptr @".str.11.@24@0:8^v16", ptr @"$sSo9ImplClassC19objc_implementationE4copy4withypSg10ObjectiveC6NSZoneVSg_tFTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr @"\01L_selector_data(mutableCopyWithZone:)", ptr @".str.11.@24@0:8^v16", ptr @"$sSo9ImplClassC19objc_implementationE11mutableCopy4withypSg10ObjectiveC6NSZoneVSg_tFTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr @"\01L_selector_data(dealloc)", ptr @".str.7.v16@0:8", ptr @"$sSo9ImplClassC19objc_implementationEfDTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr [[selector_data__cxx_destruct]], ptr @".str.7.v16@0:8", ptr @"$sSo9ImplClassCfETo{{(\.ptrauth)?}}" }] }, section "__DATA, __objc_data", align 8
// CHECK: [[_INSTANCE_METHODS_ImplClass:@[^, ]+]] = internal constant { i32, i32, [9 x { ptr, ptr, ptr }] } { i32 24, i32 9, [9 x { ptr, ptr, ptr }] [{ ptr, ptr, ptr } { ptr @"\01L_selector_data(init)", ptr @".str.7.@16@0:8", ptr @"$sSo9ImplClassC19objc_implementationEABycfcTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr @"\01L_selector_data(implProperty)", ptr @".str.7.i16@0:8", ptr @"$sSo9ImplClassC19objc_implementationE12implPropertys5Int32VvgTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr @"\01L_selector_data(setImplProperty:)", ptr @".str.10.v20@0:8i16", ptr @"$sSo9ImplClassC19objc_implementationE12implPropertys5Int32VvsTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr @"\01L_selector_data(mainMethod:)", ptr @".str.10.v20@0:8i16", ptr @"$sSo9ImplClassC19objc_implementationE10mainMethodyys5Int32VFTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr @"\01L_selector_data(extensionMethod:)", ptr @".str.10.v20@0:8i16", ptr @"$sSo9ImplClassC19objc_implementationE15extensionMethodyys5Int32VFTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr @"\01L_selector_data(copyWithZone:)", ptr @".str.11.@24@0:8^v16", ptr @"$sSo9ImplClassC19objc_implementationE4copy4withypSg10ObjectiveC6NSZoneVSg_tFTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr @"\01L_selector_data(mutableCopyWithZone:)", ptr @".str.11.@24@0:8^v16", ptr @"$sSo9ImplClassC19objc_implementationE11mutableCopy4withypSg10ObjectiveC6NSZoneVSg_tFTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr @"\01L_selector_data(dealloc)", ptr @".str.7.v16@0:8", ptr @"$sSo9ImplClassC19objc_implementationEfDTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr [[selector_data__cxx_destruct]], ptr @".str.7.v16@0:8", ptr @"$sSo9ImplClassCfETo{{(\.ptrauth)?}}" }] }, section "__DATA, __objc_data", align 8
// CHECK: [[_IVARS_ImplClass:@[^, ]+]] = internal constant { i32, i32, [2 x { ptr, ptr, ptr, i32, i32 }] } { i32 32, i32 2, [2 x { ptr, ptr, ptr, i32, i32 }] [{ ptr, ptr, ptr, i32, i32 } { ptr @"$sSo9ImplClassC19objc_implementationE12implPropertys5Int32VvpWvd", ptr @.str.12.implProperty, ptr @.str.0., i32 2, i32 4 }, { ptr, ptr, ptr, i32, i32 } { ptr @"$sSo9ImplClassC19objc_implementationE13implProperty2So8NSObjectCSgvpWvd", ptr @.str.13.implProperty2, ptr @.str.0., i32 3, i32 8 }] }, section "__DATA, __objc_const", align 8
// CHECK: [[_PROPERTIES_ImplClass:@[^, ]+]] = internal constant { i32, i32, [1 x { ptr, ptr }] } { i32 16, i32 1, [1 x { ptr, ptr }] [{ ptr, ptr } { ptr @.str.12.implProperty, ptr @".str.18.Ti,N,VimplProperty" }] }, section "__DATA, __objc_const", align 8
// FIXME: Should just be @_PROTOCOLS_ImplClass, but an IRGen bug causes the protocol list to be emitted twice.
// CHECK: [[_DATA_ImplClass:@[^, ]+]] = internal constant { i32, i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr } { i32 388, i32 8, i32 24, i32 0, ptr null, ptr @.str.9.ImplClass, ptr [[_INSTANCE_METHODS_ImplClass]], ptr @_PROTOCOLS_ImplClass.{{[0-9]+}}, ptr [[_IVARS_ImplClass]], ptr null, ptr [[_PROPERTIES_ImplClass]] }, section "__DATA, __objc_data", align 8
// CHECK: @"OBJC_CLASS_$_ImplClass" = global <{ i64, ptr, ptr, ptr, ptr }> <{ i64 ptrtoint (ptr @"OBJC_METACLASS_$_ImplClass" to i64), ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr [[_DATA_ImplClass]] }>, section "__DATA,__objc_data, regular", align 8
// CHECK: @"OBJC_CLASS_$_ImplClass" = global <{ i64, ptr, ptr, ptr, i64, i64, i64 }> <{ i64 ptrtoint (ptr @"OBJC_METACLASS_$_ImplClass" to i64), ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, i64 ptrtoint (ptr [[_DATA_ImplClass]] to i64), i64 8, i64 16 }>, section "__DATA,__objc_data, regular", align 8
// Swift metadata
// NEGATIVE-NOT: OBJC_CLASS_$_ImplClass.{{[0-9]}}
@@ -92,7 +92,7 @@
// CHECK: @_IVARS_NoInitImplClass = 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 @"$sSo15NoInitImplClassC19objc_implementationE2s1SSvpWvd", ptr @.str.2.s1, ptr @.str.0., i32 3, i32 16 }, { ptr, ptr, ptr, i32, i32 } { ptr @"$sSo15NoInitImplClassC19objc_implementationE2s2SSvpWvd", ptr @.str.2.s2, ptr @.str.0., i32 3, i32 16 }, { ptr, ptr, ptr, i32, i32 } { ptr @"$sSo15NoInitImplClassC19objc_implementationE2s3SSvpWvd", ptr @.str.2.s3, ptr @.str.0., i32 3, i32 16 }, { ptr, ptr, ptr, i32, i32 } { ptr @"$sSo15NoInitImplClassC19objc_implementationE2s4SSvpWvd", ptr @.str.2.s4, ptr @.str.0., i32 3, i32 16 }] }, section "__DATA, __objc_const", align 8
// CHECK: @_PROPERTIES_NoInitImplClass = internal constant { i32, i32, [4 x { ptr, ptr }] } { i32 16, i32 4, [4 x { ptr, ptr }] [{ ptr, ptr } { ptr @.str.2.s1, ptr @".str.16.T@\22NSString\22,N,R" }, { ptr, ptr } { ptr @.str.2.s2, ptr @".str.16.T@\22NSString\22,N,C" }, { ptr, ptr } { ptr @.str.2.s3, ptr @".str.16.T@\22NSString\22,N,R" }, { ptr, ptr } { ptr @.str.2.s4, ptr @".str.16.T@\22NSString\22,N,C" }] }, section "__DATA, __objc_const", align 8
// CHECK: @_DATA_NoInitImplClass = internal constant { i32, i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr } { i32 388, i32 8, i32 72, i32 0, ptr null, ptr @.str.15.NoInitImplClass, ptr @_INSTANCE_METHODS_NoInitImplClass, ptr null, ptr @_IVARS_NoInitImplClass, ptr null, ptr @_PROPERTIES_NoInitImplClass }, section "__DATA, __objc_data", align 8
// CHECK: @"OBJC_CLASS_$_NoInitImplClass" = global <{ i64, ptr, ptr, ptr, ptr }> <{ i64 ptrtoint (ptr @"OBJC_METACLASS_$_NoInitImplClass" to i64), ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @_DATA_NoInitImplClass }>, section "__DATA,__objc_data, regular", align 8
// CHECK: @"OBJC_CLASS_$_NoInitImplClass" = global <{ i64, ptr, ptr, ptr, i64, i64, i64, i64, i64 }> <{ i64 ptrtoint (ptr @"OBJC_METACLASS_$_NoInitImplClass" to i64), ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, i64 ptrtoint (ptr @_DATA_NoInitImplClass to i64), i64 8, i64 24, i64 40, i64 56 }>, section "__DATA,__objc_data, regular", align 8
@_objcImplementation extension NoInitImplClass {
@objc let s1 = "s1v"
@objc var s2 = "s2v"
@@ -114,7 +114,7 @@
// CHECK: [[_METACLASS_DATA_SwiftSubclass]] = 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.40._TtC19objc_implementation13SwiftSubclass, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
// Class
// CHECK: [[_INSTANCE_METHODS_SwiftSubclass:@[^, ]+]] = internal constant { i32, i32, [2 x { ptr, ptr, ptr }] } { i32 24, i32 2, [2 x { ptr, ptr, ptr }] [{ ptr, ptr, ptr } { ptr [[selector_data_mainMethod_]], ptr @".str.10.v20@0:8i16", ptr @"$s19objc_implementation13SwiftSubclassC10mainMethodyys5Int32VFTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr @"\01L_selector_data(init)", ptr @".str.7.@16@0:8", ptr @"$s19objc_implementation13SwiftSubclassCACycfcTo{{(\.ptrauth)?}}" }] }, section "__DATA, __objc_data", align 8
// CHECK: [[_INSTANCE_METHODS_SwiftSubclass:@[^, ]+]] = internal constant { i32, i32, [2 x { ptr, ptr, ptr }] } { i32 24, i32 2, [2 x { ptr, ptr, ptr }] [{ ptr, ptr, ptr } { ptr @"\01L_selector_data(mainMethod:)", ptr @".str.10.v20@0:8i16", ptr @"$s19objc_implementation13SwiftSubclassC10mainMethodyys5Int32VFTo{{(\.ptrauth)?}}" }, { ptr, ptr, ptr } { ptr @"\01L_selector_data(init)", ptr @".str.7.@16@0:8", ptr @"$s19objc_implementation13SwiftSubclassCACycfcTo{{(\.ptrauth)?}}" }] }, section "__DATA, __objc_data", align 8
// CHECK: [[_DATA_SwiftSubclass:@[^, ]+]] = internal constant { i32, i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr } { i32 128, i32 24, i32 24, i32 0, ptr null, ptr @.str.40._TtC19objc_implementation13SwiftSubclass, ptr [[_INSTANCE_METHODS_SwiftSubclass]], ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_data", align 8
// Swift metadata
@@ -130,6 +130,27 @@ open class SwiftSubclass: ImplClass {
}
}
//
// @_objcImplementation class with a resilient stored property
//
// Metaclass
// CHECK: @"OBJC_METACLASS_$_ImplClassWithResilientStoredProperty" = global %objc_class { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, {{.*}}ptr @_METACLASS_DATA_ImplClassWithResilientStoredProperty{{.*}}, align 8
// CHECK: @_METACLASS_DATA_ImplClassWithResilientStoredProperty = 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.36.ImplClassWithResilientStoredProperty, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
// TODO: Why the extra i32 field above?
// Class
// 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
// 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
// CHECK: @"OBJC_CLASS_$_ImplClassWithResilientStoredProperty" = global <{ i64, ptr, ptr, ptr, i64, i64, i64, i64, i64 }> <{ i64 ptrtoint (ptr @"OBJC_METACLASS_$_ImplClassWithResilientStoredProperty" to i64), ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, i64 ptrtoint (ptr @_DATA_ImplClassWithResilientStoredProperty to i64), i64 0, i64 0, i64 0, i64 0 }>, section "__DATA,__objc_data, regular", align 8
@_objcImplementation extension ImplClassWithResilientStoredProperty {
@objc var beforeInt: Int32 = 0
final var mirror: Mirror?
final var afterIntFinal: Int32 = 0
@objc var afterInt: Int32 = 0
}
//
// Epilogue
//
@@ -288,6 +309,48 @@ public func fn(impl: ImplClass, swiftSub: SwiftSubclass) {
// CHECK: ret void
// CHECK: }
// ImplClassWithResilientStoredProperty ObjC metadata update function
// CHECK-LABEL: define internal ptr @"$sSo36ImplClassWithResilientStoredPropertyCMU"
//
// This function should not invoke the metadata accessor.
// CHECK-NOT: sSo36ImplClassWithResilientStoredPropertyCMa
//
// This function should directly gather the field sizes and invoke the metadata update.
// CHECK: %classFields = alloca [4 x ptr]
// CHECK: [[FIELDS_ARRAY:%[0-9]+]] = getelementptr inbounds [4 x ptr], ptr %classFields, i32 0, i32 0
// CHECK: store ptr getelementptr inbounds (ptr, ptr @"$sBi32_WV", i32 8), ptr {{%[0-9]+}}
// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @"$ss6MirrorVSgMa"(i64 63)
// CHECK: store ptr {{%[0-9]+}}, ptr {{%[0-9]+}}
// CHECK: store ptr getelementptr inbounds (ptr, ptr @"$sBi32_WV", i32 8), ptr {{%[0-9]+}}
// CHECK: store ptr getelementptr inbounds (ptr, ptr @"$sBi32_WV", i32 8), ptr {{%[0-9]+}}
// CHECK: {{%[0-9]+}} = call swiftcc ptr @swift_updatePureObjCClassMetadata(ptr @"OBJC_CLASS_$_ImplClassWithResilientStoredProperty", i64 256, i64 4, ptr [[FIELDS_ARRAY]], ptr getelementptr inbounds (i64, ptr @"OBJC_CLASS_$_ImplClassWithResilientStoredProperty", i64 5))
//
// This function should not invoke the metadata accessor.
// CHECK-NOT: sSo36ImplClassWithResilientStoredPropertyCMa
//
// CHECK: ret ptr @"OBJC_CLASS_$_ImplClassWithResilientStoredProperty"
// CHECK: }
// ImplClassWithResilientStoredProperty type metadata accessor
// CHECK-LABEL: define swiftcc %swift.metadata_response @"$sSo36ImplClassWithResilientStoredPropertyCMa"
//
// This function should not use the runtime call for Swift class metadata
// CHECK-NOT: swift_getSingletonMetadata
//
// This function should realize the ObjC class and then convert it to metadata.
// CHECK: {{%[0-9]+}} = call ptr @objc_opt_self(ptr @"OBJC_CLASS_$_ImplClassWithResilientStoredProperty")
// CHECK-NEXT: {{%[0-9]+}} = call ptr @swift_getObjCClassMetadata(ptr {{%[0-9]+}})
//
// This function should not use the runtime call for Swift class metadata
// CHECK-NOT: swift_getSingletonMetadata
//
// CHECK: ret
// CHECK: }
// ImplClassWithResilientStoredProperty Swift metadata completion function
// This function shouldn't exist or be referenced
// NEGATIVE-NOT: sSo36ImplClassWithResilientStoredPropertyCMr
//
// Not implemented in Swift
//

View File

@@ -2,6 +2,8 @@
NS_ASSUME_NONNULL_BEGIN
@class ImplClassWithResilientStoredProperty;
@interface ImplClass : NSObject
- (instancetype)init;
@@ -10,10 +12,21 @@ NS_ASSUME_NONNULL_BEGIN
@property (assign) NSInteger defaultIntProperty;
+ (void)runTests;
+ (ImplClassWithResilientStoredProperty *)makeResilientImpl;
- (void)testSelf;
- (void)printSelfWithLabel:(int)label;
- (nonnull NSString *)someMethod;
@end
@interface ImplClassWithResilientStoredProperty : NSObject
- (void)printSelfWithLabel:(int)label;
- (void)mutate;
@end
extern void implFunc(int param);
NS_ASSUME_NONNULL_END

View File

@@ -20,6 +20,7 @@ class LastWords {
@_objcImplementation extension ImplClass {
@objc override init() {
print("ImplClass.init()")
self.implProperty = 0
self.object = LastWords(text: String(describing: type(of: self)))
super.init()
@@ -31,34 +32,48 @@ class LastWords {
@objc var defaultIntProperty: Int = 17
@objc class func runTests() {
do {
let impl = ImplClass()
print("someMethod =", impl.someMethod())
print("implProperty =", impl.implProperty)
impl.implProperty = 42
print("implProperty =", impl.implProperty)
print("defaultIntProperty =", impl.defaultIntProperty)
print("description =", impl.description)
}
do {
let swiftSub = SwiftSubclass()
print("someMethod =", swiftSub.someMethod())
print("implProperty =", swiftSub.implProperty)
swiftSub.implProperty = 42
print("implProperty =", swiftSub.implProperty)
print("defaultIntProperty =", swiftSub.defaultIntProperty)
print("otherProperty =", swiftSub.otherProperty)
swiftSub.otherProperty = 13
print("otherProperty =", swiftSub.otherProperty)
print("implProperty =", swiftSub.implProperty)
}
implFunc(2023 - 34)
do {
print("*** ImplClass init ***")
let impl = ImplClass()
impl.testSelf()
print("*** ImplClass end ***")
}
do {
print("*** SwiftSubclass init ***")
let swiftSub = SwiftSubclass()
swiftSub.testSelf()
print("*** SwiftSubclass end ***")
}
}
@objc func someMethod() -> String { "ImplClass.someMethod()" }
@objc func testSelf() {
let resilientImpl = Self.makeResilientImpl()
resilientImpl.printSelf(withLabel: 1)
resilientImpl.mutate()
resilientImpl.printSelf(withLabel: 2)
self.printSelf(withLabel: 1)
self.implProperty = 42
self.printSelf(withLabel: 2)
}
@objc func printSelf(withLabel label: CInt) {
let type = type(of: self)
print("*** \(type) #\(label) ***")
print("\(type).someMethod() =", self.someMethod())
print("\(type).implProperty =", self.implProperty)
print("\(type).defaultIntProperty =", self.defaultIntProperty)
print("\(type).description =", self.description)
}
@objc func someMethod() -> String { "ImplClass" }
@objc class func makeResilientImpl() -> ImplClassWithResilientStoredProperty {
ImplClassWithResilientStoredProperty()
}
open override var description: String {
"ImplClass(implProperty: \(implProperty), object: \(object))"
@@ -69,10 +84,72 @@ class SwiftSubclass: ImplClass {
@objc var otherProperty: Int = 1
override init() {
print("SwiftSubclass.init()")
super.init()
}
override func someMethod() -> String { "SwiftSubclass.someMethod()" }
override func someMethod() -> String { "SwiftSubclass" }
override func testSelf() {
super.testSelf()
self.otherProperty = 13
self.printSelf(withLabel: 3)
}
override func printSelf(withLabel label: CInt) {
super.printSelf(withLabel: label)
let type = type(of: self)
print("\(type).otherProperty =", self.otherProperty)
}
override class func makeResilientImpl() -> ImplClassWithResilientStoredProperty {
SwiftResilientStoredSubclass()
}
}
@_objcImplementation extension ImplClassWithResilientStoredProperty {
final var mirror: Mirror?
final var afterMirrorProperty: Int
public override init() {
self.mirror = nil
self.afterMirrorProperty = 0
}
@objc func printSelf(withLabel label: CInt) {
let type = type(of: self)
print("*** \(type) #\(label) ***")
print("\(type).mirror =", self.mirror as Any)
print("\(type).afterMirrorProperty =", self.afterMirrorProperty)
}
@objc func mutate() {
self.afterMirrorProperty = 42
}
}
extension SwiftSubclass {
class SwiftResilientStoredSubclass: ImplClassWithResilientStoredProperty {
final var mirror2: Mirror?
final var afterMirrorProperty2: Int
public override init() {
self.mirror2 = nil
self.afterMirrorProperty2 = 1
}
override func printSelf(withLabel label: CInt) {
super.printSelf(withLabel: label)
let type = type(of: self)
print("\(type).mirror2 =", self.mirror2 as Any)
print("\(type).afterMirrorProperty2 =", self.afterMirrorProperty2)
}
override func mutate() {
super.mutate()
self.afterMirrorProperty2 = 43
}
}
}
@_objcImplementation @_cdecl("implFunc") public func implFunc(_ param: Int32) {
@@ -82,19 +159,58 @@ class SwiftSubclass: ImplClass {
// `#if swift` to ignore the inactive branch's contents
#if swift(>=5.0) && TOP_LEVEL_CODE
ImplClass.runTests()
// CHECK: someMethod = ImplClass.someMethod()
// CHECK: implProperty = 0
// CHECK: implProperty = 42
// CHECK: defaultIntProperty = 17
// CHECK: description = ImplClass(implProperty: 42, object: main.LastWords)
// CHECK: ImplClass It's better to burn out than to fade away.
// CHECK: someMethod = SwiftSubclass.someMethod()
// CHECK: implProperty = 0
// CHECK: implProperty = 42
// CHECK: defaultIntProperty = 17
// CHECK: otherProperty = 1
// CHECK: otherProperty = 13
// CHECK: implProperty = 42
// CHECK: SwiftSubclass It's better to burn out than to fade away.
// CHECK: implFunc(1989)
// CHECK-LABEL: *** ImplClass init ***
// CHECK: ImplClass.init()
// CHECK-LABEL: *** ImplClassWithResilientStoredProperty #1 ***
// CHECK: ImplClassWithResilientStoredProperty.mirror = nil
// CHECK: ImplClassWithResilientStoredProperty.afterMirrorProperty = 0
// CHECK-LABEL: *** ImplClassWithResilientStoredProperty #2 ***
// CHECK: ImplClassWithResilientStoredProperty.mirror = nil
// CHECK: ImplClassWithResilientStoredProperty.afterMirrorProperty = 42
// CHECK-LABEL: *** ImplClass #1 ***
// CHECK: ImplClass.someMethod() = ImplClass
// CHECK: ImplClass.implProperty = 0
// CHECK: ImplClass.defaultIntProperty = 17
// CHECK: ImplClass.description = ImplClass(implProperty: 0, object: main.LastWords)
// CHECK-LABEL: *** ImplClass #2 ***
// CHECK: ImplClass.someMethod() = ImplClass
// CHECK: ImplClass.implProperty = 42
// CHECK: ImplClass.defaultIntProperty = 17
// CHECK: ImplClass.description = ImplClass(implProperty: 42, object: main.LastWords)
// CHECK-LABEL: *** ImplClass end ***
// CHECK: ImplClass It's better to burn out than to fade away.
// CHECK-LABEL: *** SwiftSubclass init ***
// CHECK: SwiftSubclass.init()
// CHECK: ImplClass.init()
// CHECK-LABEL: *** SwiftResilientStoredSubclass #1 ***
// CHECK: SwiftResilientStoredSubclass.mirror = nil
// CHECK: SwiftResilientStoredSubclass.afterMirrorProperty = 0
// CHECK: SwiftResilientStoredSubclass.mirror2 = nil
// CHECK: SwiftResilientStoredSubclass.afterMirrorProperty2 = 1
// CHECK-LABEL: *** SwiftResilientStoredSubclass #2 ***
// CHECK: SwiftResilientStoredSubclass.mirror = nil
// CHECK: SwiftResilientStoredSubclass.afterMirrorProperty = 42
// CHECK: SwiftResilientStoredSubclass.mirror2 = nil
// CHECK: SwiftResilientStoredSubclass.afterMirrorProperty2 = 43
// CHECK-LABEL: *** SwiftSubclass #1 ***
// CHECK: SwiftSubclass.someMethod() = SwiftSubclass
// CHECK: SwiftSubclass.implProperty = 0
// CHECK: SwiftSubclass.defaultIntProperty = 17
// CHECK: SwiftSubclass.description = ImplClass(implProperty: 0, object: main.LastWords)
// CHECK: SwiftSubclass.otherProperty = 1
// CHECK-LABEL: *** SwiftSubclass #2 ***
// CHECK: SwiftSubclass.someMethod() = SwiftSubclass
// CHECK: SwiftSubclass.implProperty = 42
// CHECK: SwiftSubclass.defaultIntProperty = 17
// CHECK: SwiftSubclass.description = ImplClass(implProperty: 42, object: main.LastWords)
// CHECK: SwiftSubclass.otherProperty = 1
// CHECK-LABEL: *** SwiftSubclass #3 ***
// CHECK: SwiftSubclass.someMethod() = SwiftSubclass
// CHECK: SwiftSubclass.implProperty = 42
// CHECK: SwiftSubclass.defaultIntProperty = 17
// CHECK: SwiftSubclass.description = ImplClass(implProperty: 42, object: main.LastWords)
// CHECK: SwiftSubclass.otherProperty = 13
// CHECK-LABEL: *** SwiftSubclass end ***
// CHECK: SwiftSubclass It's better to burn out than to fade away.
#endif

View File

@@ -38,6 +38,9 @@
@end
static void print(NSString *str) {
// Flush any buffered Swift output.
fflush(stdout);
NSData *strData = [str dataUsingEncoding:NSUTF8StringEncoding];
NSData *nlData = [@"\n" dataUsingEncoding:NSUTF8StringEncoding];
@@ -57,64 +60,194 @@ static void print(NSString *str) {
}
}
static void printInt(NSString *str, NSUInteger num) {
static void printInt(Class class, NSString *property, NSUInteger num) {
NSString *fullStr =
[NSString stringWithFormat:@"%@ %lld", str, (long long)num];
[NSString stringWithFormat:@"%@.%@ = %lld", class, property, (long long)num];
print(fullStr);
}
static void printString(Class class, NSString *property, NSString *str) {
NSString *fullStr =
[NSString stringWithFormat:@"%@.%@ = %@", class, property, str];
print(fullStr);
}
int main() {
[ImplClass runTests];
// CHECK: someMethod = ImplClass.someMethod()
// CHECK: implProperty = 0
// CHECK: implProperty = 42
// CHECK: someMethod = SwiftSubclass.someMethod()
// CHECK: implProperty = 0
// CHECK: implProperty = 42
// CHECK: otherProperty = 1
// CHECK: otherProperty = 13
// CHECK: implProperty = 42
// CHECK: implFunc(1989)
// CHECK-LABEL: *** ImplClass init ***
// CHECK: ImplClass.init()
// CHECK-LABEL: *** ImplClassWithResilientStoredProperty #1 ***
// CHECK: ImplClassWithResilientStoredProperty.mirror = nil
// CHECK: ImplClassWithResilientStoredProperty.afterMirrorProperty = 0
// CHECK-LABEL: *** ImplClassWithResilientStoredProperty #2 ***
// CHECK: ImplClassWithResilientStoredProperty.mirror = nil
// CHECK: ImplClassWithResilientStoredProperty.afterMirrorProperty = 42
// CHECK-LABEL: *** ImplClass #1 ***
// CHECK: ImplClass.someMethod() = ImplClass
// CHECK: ImplClass.implProperty = 0
// CHECK: ImplClass.defaultIntProperty = 17
// CHECK: ImplClass.description = ImplClass(implProperty: 0, object: objc_implementation.LastWords)
// CHECK-LABEL: *** ImplClass #2 ***
// CHECK: ImplClass.someMethod() = ImplClass
// CHECK: ImplClass.implProperty = 42
// CHECK: ImplClass.defaultIntProperty = 17
// CHECK: ImplClass.description = ImplClass(implProperty: 42, object: objc_implementation.LastWords)
// CHECK-LABEL: *** ImplClass end ***
// CHECK: ImplClass It's better to burn out than to fade away.
// CHECK-LABEL: *** SwiftSubclass init ***
// CHECK: SwiftSubclass.init()
// CHECK: ImplClass.init()
// CHECK-LABEL: *** SwiftResilientStoredSubclass #1 ***
// CHECK: SwiftResilientStoredSubclass.mirror = nil
// CHECK: SwiftResilientStoredSubclass.afterMirrorProperty = 0
// CHECK: SwiftResilientStoredSubclass.mirror2 = nil
// CHECK: SwiftResilientStoredSubclass.afterMirrorProperty2 = 1
// CHECK-LABEL: *** SwiftResilientStoredSubclass #2 ***
// CHECK: SwiftResilientStoredSubclass.mirror = nil
// CHECK: SwiftResilientStoredSubclass.afterMirrorProperty = 42
// CHECK: SwiftResilientStoredSubclass.mirror2 = nil
// CHECK: SwiftResilientStoredSubclass.afterMirrorProperty2 = 43
// CHECK-LABEL: *** SwiftSubclass #1 ***
// CHECK: SwiftSubclass.someMethod() = SwiftSubclass
// CHECK: SwiftSubclass.implProperty = 0
// CHECK: SwiftSubclass.defaultIntProperty = 17
// CHECK: SwiftSubclass.description = ImplClass(implProperty: 0, object: objc_implementation.LastWords)
// CHECK: SwiftSubclass.otherProperty = 1
// CHECK-LABEL: *** SwiftSubclass #2 ***
// CHECK: SwiftSubclass.someMethod() = SwiftSubclass
// CHECK: SwiftSubclass.implProperty = 42
// CHECK: SwiftSubclass.defaultIntProperty = 17
// CHECK: SwiftSubclass.description = ImplClass(implProperty: 42, object: objc_implementation.LastWords)
// CHECK: SwiftSubclass.otherProperty = 1
// CHECK-LABEL: *** SwiftSubclass #3 ***
// CHECK: SwiftSubclass.someMethod() = SwiftSubclass
// CHECK: SwiftSubclass.implProperty = 42
// CHECK: SwiftSubclass.defaultIntProperty = 17
// CHECK: SwiftSubclass.description = ImplClass(implProperty: 42, object: objc_implementation.LastWords)
// CHECK: SwiftSubclass.otherProperty = 13
// CHECK-LABEL: *** SwiftSubclass end ***
// CHECK: SwiftSubclass It's better to burn out than to fade away.
{
print(@"*** ObjCClientSubclass init ***");
ObjCClientSubclass *objcSub = [[ObjCClientSubclass alloc] init];
[objcSub testSelf];
print(@"*** ObjCClientSubclass end ***");
}
// CHECK-LABEL: *** ObjCClientSubclass init ***
// CHECK: -[ObjCClientSubclass init]
// CHECK: ImplClass.init()
// CHECK-LABEL: *** ObjCClientResilientSubclass #1 ***
// CHECK: ObjCClientResilientSubclass.mirror = nil
// CHECK: ObjCClientResilientSubclass.afterMirrorProperty = 0
// CHECK: ObjCClientResilientSubclass.subclassProperty = 100
// CHECK-LABEL: *** ObjCClientResilientSubclass #2 ***
// CHECK: ObjCClientResilientSubclass.mirror = nil
// CHECK: ObjCClientResilientSubclass.afterMirrorProperty = 42
// CHECK: ObjCClientResilientSubclass.subclassProperty = 101
// CHECK-LABEL: *** ObjCClientSubclass #1 ***
// CHECK: ObjCClientSubclass.someMethod() = ObjCClientSubclass
// CHECK: ObjCClientSubclass.implProperty = 0
// CHECK: ObjCClientSubclass.defaultIntProperty = 17
// CHECK: ObjCClientSubclass.description = ImplClass(implProperty: 0, object: objc_implementation.LastWords)
// CHECK: ObjCClientSubclass.otherProperty = 4
// CHECK-LABEL: *** ObjCClientSubclass #2 ***
// CHECK: ObjCClientSubclass.someMethod() = ObjCClientSubclass
// CHECK: ObjCClientSubclass.implProperty = 42
// CHECK: ObjCClientSubclass.defaultIntProperty = 17
// CHECK: ObjCClientSubclass.description = ImplClass(implProperty: 42, object: objc_implementation.LastWords)
// CHECK: ObjCClientSubclass.otherProperty = 4
// CHECK-LABEL: *** ObjCClientSubclass #3 ***
// CHECK: ObjCClientSubclass.someMethod() = ObjCClientSubclass
// CHECK: ObjCClientSubclass.implProperty = 42
// CHECK: ObjCClientSubclass.defaultIntProperty = 17
// CHECK: ObjCClientSubclass.description = ImplClass(implProperty: 42, object: objc_implementation.LastWords)
// CHECK: ObjCClientSubclass.otherProperty = 6
// CHECK-LABEL: *** ObjCClientSubclass end ***
// CHECK: ObjCClientSubclass It's better to burn out than to fade away.
fflush(stdout);
ImplClass *impl = [[ImplClass alloc] init];
print([impl someMethod]);
// CHECK: ImplClass.someMethod()
printInt(@"implProperty", impl.implProperty);
// CHECK: implProperty 0
printInt([impl class], @"implProperty", impl.implProperty);
impl.implProperty = -2;
printInt(@"implProperty", impl.implProperty);
// CHECK: implProperty -2
printInt([impl class], @"implProperty", impl.implProperty);
// CHECK: ImplClass.implProperty = 0
// CHECK: ImplClass.implProperty = -2
ObjCClientSubclass *objcSub = [[ObjCClientSubclass alloc] init];
print([objcSub someMethod]);
// CHECK: -[ObjCClientSubclass someMethod]
// CHECK: ObjCClientSubclass
printInt(@"implProperty", objcSub.implProperty);
// CHECK: implProperty 0
printInt(@"otherProperty", objcSub.otherProperty);
// CHECK: otherProperty 4
printInt([objcSub class], @"implProperty", objcSub.implProperty);
printInt([objcSub class], @"otherProperty", objcSub.otherProperty);
objcSub.implProperty = 7;
objcSub.otherProperty = 9;
printInt(@"implProperty", objcSub.implProperty);
// CHECK: implProperty 7
printInt(@"otherProperty", objcSub.otherProperty);
// CHECK: otherProperty 9
printInt([objcSub class], @"implProperty", objcSub.implProperty);
printInt([objcSub class], @"otherProperty", objcSub.otherProperty);
// CHECK: ObjCClientSubclass.implProperty = 0
// CHECK: ObjCClientSubclass.otherProperty = 4
// CHECK: ObjCClientSubclass.implProperty = 7
// CHECK: ObjCClientSubclass.otherProperty = 9
return 0;
}
@interface ObjCClientResilientSubclass : ImplClassWithResilientStoredProperty
@property (assign) NSInteger subclassProperty;
@end
@implementation ObjCClientSubclass
- (id)init {
print(@"-[ObjCClientSubclass init]");
if (self = [super init]) {
_otherProperty = 4;
}
return self;
}
- (void)testSelf {
[super testSelf];
self.otherProperty = 6;
[self printSelfWithLabel:3];
}
- (void)printSelfWithLabel:(int)label {
[super printSelfWithLabel:label];
printInt([self class], @"otherProperty", self.otherProperty);
}
- (NSString *)someMethod {
return @"-[ObjCClientSubclass someMethod]";
return @"ObjCClientSubclass";
}
+ (ImplClassWithResilientStoredProperty *)makeResilientImpl {
return [ObjCClientResilientSubclass new];
}
@end
@implementation ObjCClientResilientSubclass
- (id)init {
if (self = [super init]) {
_subclassProperty = 100;
}
return self;
}
- (void)printSelfWithLabel:(int)label {
[super printSelfWithLabel:label];
printInt([self class], @"subclassProperty", self.subclassProperty);
}
- (void)mutate {
[super mutate];
self.subclassProperty = 101;
}
@end

View File

@@ -37,34 +37,146 @@
import Foundation
import objc_implementation
ImplClass.runTests()
// CHECK: someMethod = ImplClass.someMethod()
// CHECK: implProperty = 0
// CHECK: implProperty = 42
// CHECK: someMethod = SwiftSubclass.someMethod()
// CHECK: implProperty = 0
// CHECK: implProperty = 42
// CHECK: otherProperty = 1
// CHECK: otherProperty = 13
// CHECK: implProperty = 42
let impl = ImplClass()
print(impl.someMethod(), impl.implProperty)
// CHECK: ImplClass.someMethod() 0
class SwiftClientSubclass: ImplClass {
override init() {}
override init() { print("SwiftClientSubclass.init() ") }
var otherProperty = 2
override func someMethod() -> String { "SwiftClientSubclass.someMethod()" }
override func someMethod() -> String { "SwiftClientSubclass" }
override func testSelf() {
super.testSelf()
self.implProperty = 3
self.otherProperty = 9
self.printSelf(withLabel: 3)
}
override func printSelf(withLabel label: CInt) {
super.printSelf(withLabel: label)
let type = type(of: self)
print("\(type).otherProperty =", otherProperty);
}
override class func makeResilientImpl() -> ImplClassWithResilientStoredProperty {
SwiftResilientStoredClientSubclass()
}
}
let swiftClientSub = SwiftClientSubclass()
print(swiftClientSub.someMethod())
// CHECK: SwiftClientSubclass.someMethod()
print(swiftClientSub.implProperty, swiftClientSub.otherProperty)
// CHECK: 0 2
swiftClientSub.implProperty = 3
swiftClientSub.otherProperty = 9
print(swiftClientSub.implProperty, swiftClientSub.otherProperty)
// CHECK: 3 9
extension SwiftClientSubclass {
class SwiftResilientStoredClientSubclass: ImplClassWithResilientStoredProperty {
final var mirror2: Mirror?
final var afterMirrorProperty2: Int
public override init() {
self.mirror2 = nil
self.afterMirrorProperty2 = 1
}
override func printSelf(withLabel label: CInt) {
super.printSelf(withLabel: label)
let type = type(of: self)
print("\(type).mirror2 =", self.mirror2 as Any)
print("\(type).afterMirrorProperty2 =", self.afterMirrorProperty2)
}
override func mutate() {
super.mutate()
self.afterMirrorProperty2 = 43
}
}
}
ImplClass.runTests();
do {
print("*** SwiftClientSubclass init ***")
let swiftClientSub = SwiftClientSubclass()
swiftClientSub.testSelf()
print("*** SwiftClientSubclass end ***")
}
// CHECK: implFunc(1989)
// CHECK-LABEL: *** ImplClass init ***
// CHECK: ImplClass.init()
// CHECK-LABEL: *** ImplClassWithResilientStoredProperty #1 ***
// CHECK: ImplClassWithResilientStoredProperty.mirror = nil
// CHECK: ImplClassWithResilientStoredProperty.afterMirrorProperty = 0
// CHECK-LABEL: *** ImplClassWithResilientStoredProperty #2 ***
// CHECK: ImplClassWithResilientStoredProperty.mirror = nil
// CHECK: ImplClassWithResilientStoredProperty.afterMirrorProperty = 42
// CHECK-LABEL: *** ImplClass #1 ***
// CHECK: ImplClass.someMethod() = ImplClass
// CHECK: ImplClass.implProperty = 0
// CHECK: ImplClass.defaultIntProperty = 17
// CHECK: ImplClass.description = ImplClass(implProperty: 0, object: objc_implementation.LastWords)
// CHECK-LABEL: *** ImplClass #2 ***
// CHECK: ImplClass.someMethod() = ImplClass
// CHECK: ImplClass.implProperty = 42
// CHECK: ImplClass.defaultIntProperty = 17
// CHECK: ImplClass.description = ImplClass(implProperty: 42, object: objc_implementation.LastWords)
// CHECK-LABEL: *** ImplClass end ***
// CHECK: ImplClass It's better to burn out than to fade away.
// CHECK-LABEL: *** SwiftSubclass init ***
// CHECK: SwiftSubclass.init()
// CHECK: ImplClass.init()
// CHECK-LABEL: *** SwiftResilientStoredSubclass #1 ***
// CHECK: SwiftResilientStoredSubclass.mirror = nil
// CHECK: SwiftResilientStoredSubclass.afterMirrorProperty = 0
// CHECK: SwiftResilientStoredSubclass.mirror2 = nil
// CHECK: SwiftResilientStoredSubclass.afterMirrorProperty2 = 1
// CHECK-LABEL: *** SwiftResilientStoredSubclass #2 ***
// CHECK: SwiftResilientStoredSubclass.mirror = nil
// CHECK: SwiftResilientStoredSubclass.afterMirrorProperty = 42
// CHECK: SwiftResilientStoredSubclass.mirror2 = nil
// CHECK: SwiftResilientStoredSubclass.afterMirrorProperty2 = 43
// CHECK-LABEL: *** SwiftSubclass #1 ***
// CHECK: SwiftSubclass.someMethod() = SwiftSubclass
// CHECK: SwiftSubclass.implProperty = 0
// CHECK: SwiftSubclass.defaultIntProperty = 17
// CHECK: SwiftSubclass.description = ImplClass(implProperty: 0, object: objc_implementation.LastWords)
// CHECK: SwiftSubclass.otherProperty = 1
// CHECK-LABEL: *** SwiftSubclass #2 ***
// CHECK: SwiftSubclass.someMethod() = SwiftSubclass
// CHECK: SwiftSubclass.implProperty = 42
// CHECK: SwiftSubclass.defaultIntProperty = 17
// CHECK: SwiftSubclass.description = ImplClass(implProperty: 42, object: objc_implementation.LastWords)
// CHECK: SwiftSubclass.otherProperty = 1
// CHECK-LABEL: *** SwiftSubclass #3 ***
// CHECK: SwiftSubclass.someMethod() = SwiftSubclass
// CHECK: SwiftSubclass.implProperty = 42
// CHECK: SwiftSubclass.defaultIntProperty = 17
// CHECK: SwiftSubclass.description = ImplClass(implProperty: 42, object: objc_implementation.LastWords)
// CHECK: SwiftSubclass.otherProperty = 13
// CHECK-LABEL: *** SwiftSubclass end ***
// CHECK: SwiftSubclass It's better to burn out than to fade away.
// CHECK-LABEL: *** SwiftClientSubclass init ***
// CHECK: SwiftClientSubclass.init()
// CHECK: ImplClass.init()
// CHECK-LABEL: *** SwiftResilientStoredClientSubclass #1 ***
// CHECK: SwiftResilientStoredClientSubclass.mirror = nil
// CHECK: SwiftResilientStoredClientSubclass.afterMirrorProperty = 0
// CHECK: SwiftResilientStoredClientSubclass.mirror2 = nil
// CHECK: SwiftResilientStoredClientSubclass.afterMirrorProperty2 = 1
// CHECK-LABEL: *** SwiftResilientStoredClientSubclass #2 ***
// CHECK: SwiftResilientStoredClientSubclass.mirror = nil
// CHECK: SwiftResilientStoredClientSubclass.afterMirrorProperty = 42
// CHECK: SwiftResilientStoredClientSubclass.mirror2 = nil
// CHECK: SwiftResilientStoredClientSubclass.afterMirrorProperty2 = 43
// CHECK-LABEL: *** SwiftClientSubclass #1 ***
// CHECK: SwiftClientSubclass.someMethod() = SwiftClientSubclass
// CHECK: SwiftClientSubclass.implProperty = 0
// CHECK: SwiftClientSubclass.defaultIntProperty = 17
// CHECK: SwiftClientSubclass.description = ImplClass(implProperty: 0, object: objc_implementation.LastWords)
// CHECK: SwiftClientSubclass.otherProperty = 2
// CHECK-LABEL: *** SwiftClientSubclass #2 ***
// CHECK: SwiftClientSubclass.someMethod() = SwiftClientSubclass
// CHECK: SwiftClientSubclass.implProperty = 42
// CHECK: SwiftClientSubclass.defaultIntProperty = 17
// CHECK: SwiftClientSubclass.description = ImplClass(implProperty: 42, object: objc_implementation.LastWords)
// CHECK: SwiftClientSubclass.otherProperty = 2
// CHECK-LABEL: *** SwiftClientSubclass #3 ***
// CHECK: SwiftClientSubclass.someMethod() = SwiftClientSubclass
// CHECK: SwiftClientSubclass.implProperty = 3
// CHECK: SwiftClientSubclass.defaultIntProperty = 17
// CHECK: SwiftClientSubclass.description = ImplClass(implProperty: 3, object: objc_implementation.LastWords)
// CHECK: SwiftClientSubclass.otherProperty = 9
// CHECK-LABEL: *** SwiftClientSubclass end ***
// CHECK: SwiftClientSubclass It's better to burn out than to fade away.

View File

@@ -563,6 +563,7 @@ Added: _swift_willThrowTypedImpl
Added: __swift_willThrowTypedImpl
Added: __swift_enableSwizzlingOfAllocationAndRefCountingFunctions_forInstrumentsOnly
Added: _swift_clearSensitive
Added: _swift_updatePureObjCClassMetadata
// Runtime bincompat functions for Concurrency runtime to detect legacy mode
Added: _swift_bincompat_useLegacyNonCrashingExecutorChecks

View File

@@ -563,6 +563,7 @@ Added: _swift_willThrowTypedImpl
Added: __swift_willThrowTypedImpl
Added: __swift_enableSwizzlingOfAllocationAndRefCountingFunctions_forInstrumentsOnly
Added: _swift_clearSensitive
Added: _swift_updatePureObjCClassMetadata
// Runtime bincompat functions for Concurrency runtime to detect legacy mode
Added: _swift_bincompat_useLegacyNonCrashingExecutorChecks