Decls with a package access level are currently set to public SIL
linkages. This limits the ability to have more fine-grained control
and optimize around resilience and serialization.
This PR introduces a separate SIL linkage and FormalLinkage for
package decls, pipes them down to IRGen, and updates linkage checks
at call sites to include package linkage.
Resolves rdar://121409846
The old logic looked at each generic parameter, and each conformance
of that generic parameter. This missed conformance requirements where
the subject type is a dependent member type.
Also, the check for dependent witness tables was too strict, because
it should have skipped protocols without witness tables.
Refactor everything to instead walk the substitution map directly,
and check each replacement type and conformance. This simplifies
the logic and fixes failures with non-copyable generics enabled.
In preparation for moving to llvm's opaque pointer representation
replace getPointerElementType and CreateCall/CreateLoad/Store uses that
dependent on the address operand's pointer element type.
This means an `Address` carries the element type and we use
`FunctionPointer` in more places or read the function type off the
`llvm::Function`.
When a generic type from a different module is not resilient within the
current module and at least one of its arguments is from the current
module, emit a non-canonical prespecialized record, and access that
metadata via a call to swift_getCanonicalSpecializedMetadata, passing in
the non-canonical record.
rdar://problem/56996727
rdar://problem/56997022
Previously a bool argument was passed to
isCanonicalSpecializedNominalTypeMetadataStaticallyAddressable to
indicate whether the metadata was to be used only from a specialized
metadata accessor. Here, that bool is replaced with an enum.
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.
Some metadata may require instantiation, but not in a way that requires us to put an additional
cache layer in front of it. `Self` metadata is also trivial to access from the local cache, but
isn't statically referenceable. Split these concepts and update code to use one or the other
appropriately. This catches an issue with metadata prespecialization where it would try to
make records for dynamic `Self` incorrectly.
Metadata accessors are dependent on prespecializations of the metadata
of generic, in-module types. Those prespecializations are themselves
dependent on usages of the types in functions. Consequently, the
accessors must be emitted after all the functions are emitted.
When emitting a reference to the metadata for a generic type, prepare
to, rather than always inserting calls to the type metadata access
function, emit direct references to static specializations when possible
and emit calls to the forthcoming swift_getCanonicalSpecializedMetadata
when not possible.
For now, the metadata access function is always called.
Newer versions of clang are more reliable about emitting "used"
functions, but that means that newer versions of clang can break the
build if the dependencies of a "used" function aren't satisfied.
If we're allowed to know at IRGen time what the underlying type of an opaque type is, we can
satisfy references to the opaque type's metadata or protocol witness tables by directly referencing
the underlying type instead.
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.
In our initial approach for resolving metadata dependency cycles with classes, non-transitively complete superclass metadata was fetched by the subclass's metadata completion function and passed to `swift_initClassMetadata`. That could mean generating quite a lot of code in the completion function, and so we fairly recently changed it so that `swift_initClassMetadata` instead fetched the superclass metadata via a demangling. Unfortunately, the metadata demangler only fetches _abstract_ metadata by default, and class metadata cannot be considered even non-transitively complete when its superclass reference not at that stage. If the superclass metadata is being completed on one thread, and a subclass is being completed on another, and the subclass installs the incomplete superclass metadata in its superclass field and attempts to register the subclass with the Objective-C runtime, the runtime may crash reading the incompletely-initialized superclass.
The proper fix is to make `swift_initClassMetadata` fetch non-transitively complete metadata for the superclass, delaying completion if that metadata is unavailable. Unfortunately, that can't actually be implemented on top of `swift_initClassMetadata` because that function has no means of reporting an unsatisfied dependency to its caller, and we can no longer simply change its signature without worrying about a small of internal code that might still be using it. We cannot simply perform a blocking metadata request in `swift_initClassMetadata` because it is deeply problematic to block within a metadata completion function. The solution is therefore to add a `swift_initClassMetadata2` which has the ability to report unsatisfied dependencies. That was done in #22386; this patch builds on that by teaching the compiler to generate code to actually use it. It is therefore not safe to use this patch if you might be running on an OS that only provides the old runtime function, but that should be a temporary Apple-internal problem.
Fixes rdar://47549859.
Similar to the non-resilient case, except we also emit a 'relocation
function'. The class descriptor now contains this relocation function
if the class has resilient ancestry, and the relocation function
calls the runtime's swift_relocateClassMetadata() entry point.
The metadata completion function calls swift_initClassMetadata() and
does layout, just like the non-resilient case.
Fixes <rdar://problem/40810002>.
- `swift_getForeignTypeMetadata` is now a request/response function.
- The initialization function is now a completion function, and the
pointer to it has moved into the type descriptor.
- The cache variable is no longer part of the ABI; it's an
implementation detail of the access function.
- The two points above mean that there is no special header on foreign
type metadata and therefore that they can be marked constant when
there isn't something about them that needs to be initialized.
The only foreign-metadata initialization we actually do right now is
of the superclass field of a foreign class, and since that relationship
is a proper DAG, it's not actually possible to have recursive
initialization problems. But this is the right long-term thing to do,
and it removes one of the last two clients of once-based initialization.
The central thrust of this patch is to get these metadata initializations
off of `swift_once` and onto the metadata-request system where we can
properly detect and resolve dependencies. We do this by first introducing
runtime support for resolving metadata requests for "in-place"
initializations (committed previously) and then teaching IRGen to actually
generate code to use them (this patch).
A non-trivial amount of this patch is just renaming and refactoring some of
existing infrastructure that was being used for in-place initializations to
try to avoid unnecessary confusion.
The remaining cases that are still using `swift_once` resolution of
metadata initialization are:
- non-generic classes that can't statically fill their superclass or
have resilient internal layout
- foreign type metadata
Classes require more work because I'd like to switch at least the
resilient-superclass case over to using a pattern much more like what
we do with generic class instantiation. That is, I'd like in-place
initialization to be reserved for classes that actually don't need
relocation.
Foreign metadata should also be updated to the request/dependency scheme
before we declare ABI stability. I'm not sure why foreign metadata
would ever require a type to be resolved, but let's assume it's possible.
Fixes part of SR-7876.
Most of the work of this patch is just propagating metadata states
throughout the system, especially local-type-data caching and
metadata-path resolution. It took a few design revisions to get both
DynamicMetadataRequest and MetadataResponse to a shape that felt
right and seemed to make everything easier.
The design is laid out pretty clearly (I hope) in the comments on
DynamicMetadataRequest and MetadataResponse, so I'm not going to
belabor it again here. Instead, I'll list out the work that's still
outstanding:
- I'm sure there are places we're asking for complete metadata where
we could be asking for something weaker.
- I need to actually test the runtime behavior to verify that it's
breaking the cycles it's supposed to, instead of just not regressing
anything else.
- I need to add something to the runtime to actually force all the
generic arguments of a generic type to be complete before reporting
completion. I think we can get away with this for now because all
existing types construct themselves completely on the first request,
but there might be a race condition there if another asks for the
type argument, gets an abstract metadata, and constructs a type with
it without ever needing it to be completed.
- Non-generic resilient types need to be switched over to an IRGen
pattern that supports initialization suspension.
- We should probably space out the MetadataStates so that there's some
space between Abstract and Complete.
- The runtime just calmly sits there, never making progress and
permanently blocking any waiting threads, if you actually form an
unresolvable metadata dependency cycle. It is possible to set up such
a thing in a way that Sema can't diagnose, and we should detect it at
runtime. I've set up some infrastructure so that it should be
straightforward to diagnose this, but I haven't actually implemented
the diagnostic yet.
- It's not clear to me that swift_checkMetadataState is really cheap
enough that it doesn't make sense to use a cache for type-fulfilled
metadata in associated type access functions. Fortunately this is not
ABI-affecting, so we can evaluate it anytime.
- Type layout really seems like a lot of code now that we sometimes
need to call swift_checkMetadataState for generic arguments. Maybe
we can have the runtime do this by marking low bits or something, so
that a TypeLayoutRef is actually either (1) a TypeLayout, (2) a known
layout-complete metadata, or (3) a metadata of unknown state. We could
do that later with a flag, but we'll need to at least future-proof by
allowing the runtime functions to return a MetadataDependency.
I de-templated MetadataState and MetadataRequest because we weren't
relying on the template and because using the template was causing
conversion problems due to the inability to directly template an enum
in C++.
Abstract type/heap metadata access goes into MetadataRequest.
Metadata access starting from a heap object goes into GenHeap.
Accessing various components of class metadata goes into GenClass
or MetadataLayout.
This includes global generic and non-generic global access
functions, protocol associated type access functions,
swift_getGenericMetadata, and generic type completion functions.
The main part of this change is that the functions now need to take
a MetadataRequest and return a MetadataResponse, which is capable
of expressing that the request can fail. The state of the returned
metadata is reported as an second, independent return value; this
allows the caller to easily check the possibility of failure without
having to mask it out from the returned metadata pointer, as well
as allowing it to be easily ignored.
Also, change metadata access functions to use swiftcc to ensure that
this return value is indeed returned in two separate registers.
Also, change protocol associated conformance access functions to use
swiftcc. This isn't really related, but for some reason it snuck in.
Since it's clearly the right thing to do, and since I really didn't
want to retroactively tease that back out from all the rest of the
test changes, I've left it in.
Also, change generic metadata access functions to either pass all
the generic arguments directly or pass them all indirectly. I don't
know how we ended up with the hybrid approach. I needed to change all
the code-generation and calls here anyway in order to pass the request
parameter, and I figured I might as well change the ABI to something
sensible.