mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
//
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user