A formally virtual method still needs to provide the ABI of an overridable
method, including a dispatch thunk, method descriptor, and support in the
method lookup function for the class to handle `super.` calls from clients.
Previously, metadata prespecialization for classes only occurred when
all of a specialized generic class's ancestors were themselves generic.
Here, that requirement is lifted so that generic classes with concrete
ancestors are also eligible for prespecialization.
When generic metadata for a class is requested in the same module where
the class is defined, rather than a call to the generic metadata
accessor or to a variant of typeForMangledNode, a call to a new
accessor--a canonical specialized generic metadata accessor--is emitted.
The new function is defined schematically as follows:
MetadataResponse `canonical specialized metadata accessor for C<K>`(MetadataRequest request) {
(void)`canonical specialized metadata accessor for superclass(C<K>)`(::Complete)
(void)`canonical specialized metadata accessor for generic_argument_class(C<K>, 1)`(::Complete)
...
(void)`canonical specialized metadata accessor for generic_argument_class(C<K>, count)`(::Complete)
auto *metadata = objc_opt_self(`canonical specialized metadata for C<K>`);
return {metadata, MetadataState::Complete};
}
where generic_argument_class(C<K>, N) denotes the Nth generic argument
which is both (1) itself a specialized generic type and is also (2) a
class. These calls to the specialized metadata accessors for these
related types ensure that all generic class types are registered with
the Objective-C runtime.
To enable these new canonical specialized generic metadata accessors,
metadata for generic classes is prespecialized as needed. So are the
metaclasses and the corresponding rodata.
Previously, the lazy objc naming hook was registered during process
execution when the first generic class metadata was instantiated. Since
that instantiation may occur "before process launch" (i.e. if the
generic metadata is prespecialized), the lazy naming hook is now
installed at process launch.
The Objective-C runtime expects a signed pointer here. The existing test
would have caught this, except it was always disabled because the
symbol name passed to the dlsym() check should not have had the leading
'_'.
Fixes <rdar://problem/57679510>.
The problem was that HasObjCAncestry was not getting set if
HasResilientAncestry was true, and thus emitFieldOffsetGlobals() was
marking the field offset as const even though the Objective-C
runtime might slide it.
Fixes <rdar://problem/48031465>.
This reverts commit f0cdd76f18, reversing
changes made to 703fe0f1a1.
Revert "IRGen: Refactor getObjCEncodingForMethod and getObjectEncodingFromClangNode into one"
This reverts commit 0082682b0d.
Revert "Merge pull request #30438 from aschwaighofer/irgen_prefer_clang_type_encoding"
This reverts commit eeb7fa52b2, reversing
changes made to 77af77fa8a.
Revert "Merge pull request #30433 from aschwaighofer/irgen_no_duplicate_objc_method_descriptor_entries"
This reverts commit 77af77fa8a, reversing
changes made to 841eeb05b0.
This reverts the changes for
rdar://60461850, rdar://60474785, rdar://60778637
There is still at least an issue that we address with PR#30654.
Revert until we have confidence that this is the right fix set.
Before this patch we used to get duplicate entries because we would
define implicit function delcarations, e.g for
(func_decl "perform(_:)" interface type='<Self where Self : NSObjectProtocol> (Self) -> (Selector?) -> Unmanaged<AnyObject>?' access=public @objc
(parameter "self")
(parameter_list
(parameter "aSelector" type='Selector?' interface type='Selector?')))
we will define:
(func_decl implicit "performSelector(_:)" access=public @objc
(parameter "self")
(parameter_list
(parameter "aSelector" type='Selector?' interface type='Selector?')))
rdar://60461850
There were a couple of methods in LangOptions and some related ones in
Availability and ASTContext that were added more recently.
Refactor the three older checks to the newer scheme.
We used to crash for classes that have an empty and a resilient field
during intialization if the object was in the shared cache.
class CrashInInit {
var empty = EmptyStruct()
var resilient = ResilientThing()
}
What happened was that for such a class we we would compute a
instanceStart of 0. The shared cache builder would then slide the value
of the constant ivar offset for the empty field from 0 to 16. However,
the field offset for empty fields is assumed to be zero and the runtime
does not compute a different value for the empty field and so the field
offset for the empty field remains 0. The runtime then trys to reconcile
the field offset (0) and the ivar offset (16) trying to write to the ivar
offset. However, the ivar offset is marked as constant and so we
crashed.
This can be avoided by correctly computing the instanceStart for such a
class to be 16 such that the shared cache builder does not update the
value of the empty field.
rdar://rdar://58458169
This is a regression from recent changes to make finalizeDecl() do
less work. All these resolveDeclSignature() calls will hopefully go
away soon, once validateDecl() is refactored into a getInterfaceType()
request.
Since the return value of getAccessor() depends on mutable state, it
does not make sense in the request evaluator world. Let's begin by
removing some utility methods derived from getAccessor(), replacing
calls to them with calls to getAccessor().
This logic is no longer guarded by a flag. Sema will still emit certain
diagnostics if the flag is not specified though.
Progress on <rdar://problem/49090631>.
Previously even if a type's metadata was optimized away, we would still
emit a field descriptor, which in turn could reference nominal type
descriptors for other types via symbolic references, etc.
Non-generic classes with resilient ancestry do not have statically-emitted
metadata, so we can now emit an Objective-C resilient class stub instead.
Also, when emitting an Objective-C category, reference the class stub if
the class has resilient ancestry; previously this case would hit an assert.
Note that class stubs always start with a zero word, with the address point
pointing immediately after. This works around a linker issue, where the
linker tries to coalesce categories and gets confused upon encountering a
class stub.
Field offset vectors are always filled out with either zero or the static layout's offset, depending on the metadata initialization strategy. This change means that the static layout's offset will only be non-zero for properties with a statically-known layout. Existing runtimes doing dynamic class layout assign class properties a zero offset if the field offset vector entry is zero and the property is zero-sized. So this effectively brings the compiler into accord with the runtime (for all newly-compiled Swift code, which will eventually be all Swift code because the current public releases of Swift 5 are not yet considered ABI-stable) and guarantees a zero value for the offset everywhere.
Since the runtime will agree with the compiler about the zero value of the offset, the compiler can continue to emit such offset variables as constant. The exception to this rule is if the class has non-fragile ObjC ancestry, in which case the ObjC runtime (which is not aware of this special rule for empty fields) will attempt to slide it along with everything else.
Fixes rdar://48031465, in which the `FixedClassMetadataBuilder` for a class with a legacy-fixed layout was writing a non-zero offset for an empty field into the field offset vector, causing the runtime to not apply the special case and thus to compute a non-zero offset, which it then attempted to copy into the global field offset variable, which the compiler had emitted as a true-constant zero.