Skip to content

Handle resilient stored properties in objcImpl #73128

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
May 1, 2024
11 changes: 11 additions & 0 deletions include/swift/AST/DiagnosticsIRGen.def
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,16 @@ NOTE(layout_strings_blocked,none,
"Layout string value witnesses have been disabled for module '%0' "
"through block list entry", (StringRef))

ERROR(attr_objc_implementation_resilient_property_not_supported, none,
"'@implementation' does not support stored properties whose size can "
"change due to library evolution; store this value in an object or 'any' "
"type",
())
ERROR(attr_objc_implementation_resilient_property_deployment_target, none,
"'@implementation' on %0 %1 does not support stored properties whose "
"size can change due to library evolution; raise the minimum deployment "
"target to %0 %2 or store this value in an object or 'any' type",
(StringRef, const llvm::VersionTuple, const llvm::VersionTuple))

#define UNDEFINE_DIAGNOSTIC_MACROS
#include "DefineDiagnosticMacros.h"
4 changes: 4 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -1796,6 +1796,10 @@ ERROR(attr_objc_implementation_no_conformance,none,
"add this conformance %select{with an ordinary extension|"
"in the Objective-C header}1",
(Type, bool))
ERROR(attr_objc_implementation_raise_minimum_deployment_target,none,
"'@implementation' of an Objective-C class requires a minimum deployment "
"target of at least %0 %1",
(StringRef, llvm::VersionTuple))

ERROR(member_of_objc_implementation_not_objc_or_final,none,
"%kind0 does not match any %kindonly0 declared in the headers for %1; "
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/FeatureAvailability.def
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ FEATURE(TaskExecutor, FUTURE)
FEATURE(Differentiation, FUTURE)
FEATURE(InitRawStructMetadata, FUTURE)
FEATURE(ClearSensitive, FUTURE)
FEATURE(UpdatePureObjCClassMetadata, FUTURE)

#undef FEATURE
#undef FUTURE
5 changes: 5 additions & 0 deletions include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,11 @@ EXPERIMENTAL_FEATURE(GlobalActorIsolatedTypesUsability, true)
// Enable @implementation on extensions of ObjC classes.
EXPERIMENTAL_FEATURE(ObjCImplementation, true)

// Enable @implementation on extensions of ObjC classes with non-fixed layout
// due to resilient stored properties. Requires OS support; this flag exists for
// staging purposes.
EXPERIMENTAL_FEATURE(ObjCImplementationWithResilientStorage, true)

// Enable @implementation on @_cdecl functions.
EXPERIMENTAL_FEATURE(CImplementation, true)

Expand Down
7 changes: 7 additions & 0 deletions include/swift/Runtime/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,13 @@ 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);
#endif

/// Given class metadata, a class descriptor and a method descriptor, look up
Expand Down
13 changes: 13 additions & 0 deletions include/swift/Runtime/RuntimeFunctions.def
Original file line number Diff line number Diff line change
Expand Up @@ -1437,6 +1437,19 @@ FUNCTION(UpdateClassMetadata2,
EFFECT(MetaData),
UNKNOWN_MEMEFFECTS)

// objc_class *swift_updatePureObjCClassMetadata(
// objc_class *self,
// ClassLayoutFlags flags,
// size_t numFields,
// TypeLayout * const *fieldTypes);
FUNCTION(UpdatePureObjCClassMetadata,
swift_updatePureObjCClassMetadata, SwiftCC, AlwaysAvailable,
RETURNS(ObjCClassPtrTy),
ARGS(ObjCClassPtrTy, SizeTy, SizeTy, Int8PtrPtrTy->getPointerTo()),
ATTRS(NoUnwind),
EFFECT(MetaData),
UNKNOWN_MEMEFFECTS)

// void *swift_lookUpClassMethod(Metadata *metadata,
// ClassDescriptor *description,
// MethodDescriptor *method);
Expand Down
1 change: 1 addition & 0 deletions lib/AST/FeatureSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,7 @@ static bool usesFeatureGlobalActorIsolatedTypesUsability(Decl *decl) {
}

UNINTERESTING_FEATURE(ObjCImplementation)
UNINTERESTING_FEATURE(ObjCImplementationWithResilientStorage)
UNINTERESTING_FEATURE(CImplementation)

static bool usesFeatureSensitive(Decl *decl) {
Expand Down
14 changes: 14 additions & 0 deletions lib/IRGen/ClassMetadataVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#define SWIFT_IRGEN_CLASSMETADATAVISITOR_H

#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/SubstitutionMap.h"
#include "swift/SIL/SILDeclRef.h"
#include "swift/SIL/SILModule.h"
Expand Down Expand Up @@ -67,6 +68,9 @@ template <class Impl> class ClassMetadataVisitor
: super(IGM), Target(target), VTable(vtable) {}

public:
bool isPureObjC() const {
return Target->getObjCImplementationDecl();
}

// Layout in embedded mode while considering the class type.
// This is important for adding the right superclass pointer.
Expand All @@ -93,6 +97,16 @@ template <class Impl> class ClassMetadataVisitor
return;
}

if (isPureObjC()) {
assert(IGM.ObjCInterop);
asImpl().noteAddressPoint();
asImpl().addMetadataFlags();
asImpl().addSuperclass();
asImpl().addClassCacheData();
asImpl().addClassDataPointer();
return;
}

// Pointer to layout string
asImpl().addLayoutStringPointer();

Expand Down
27 changes: 21 additions & 6 deletions lib/IRGen/GenClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
Loading