Implement name mangling, type metadata, runtime demangling, etc. for
global-actor qualified function types. Ensure that the manglings
round-trip through the various subsystems.
Implements rdar://78269642.
* Move differentiability kinds from target function type metadata to trailing objects so that we don't exhaust all remaining bits of function type metadata.
* Differentiability kind is now stored in a tail-allocated word when function type flags say it's differentiable, located immediately after the normal function type metadata's contents (with proper alignment in between).
* Add new runtime function `swift_getFunctionTypeMetadataDifferentiable` which handles differentiable function types.
* Fix mangling of different differentiability kinds in function types. Mangle it like `ConcurrentFunctionType` so that we can drop special cases for escaping functions.
```
function-signature ::= params-type params-type async? sendable? throws? differentiable? // results and parameters
...
differentiable ::= 'jf' // @differentiable(_forward) on function type
differentiable ::= 'jr' // @differentiable(reverse) on function type
differentiable ::= 'jd' // @differentiable on function type
differentiable ::= 'jl' // @differentiable(_linear) on function type
```
Resolves rdar://75240064.
Add a new entry point for getting generic metadata which adds the
canonical metadata records attached to the nominal type descriptor to
the metadata cache.
Change the implementation of the primary entry-point
swift_getGenericMetadata to stop looking through canonical
prespecialized records.
Change the implementation of swift_getCanonicalSpecializedMetadata to
use the caching token attached to the nominal type descriptor to add
canonical prespecialized metadata records to the metadata cache only
once rather than using the cache variables to limit the number of times
the attempt was made.
The new function swift_getCanonicalSpecializedMetadata takes a metadata
request, a prespecialized non-canonical metadata, and a cache as its
arguments. The idea of the function is either to bless the provided
prespecialized metadata as canonical if there is not currently a
canonical metadata record for the type it describes or else to return
the actual canonical metadata.
When called, the metadata cache checks for a preexisting entry for this
metadata. If none is found, the passed-in prespecialized metadata is
added to the cache. Otherwise, the metadata record found in the cache
is returned.
rdar://problem/56995359
The new function swift_compareProtocolConformanceDescriptors calls
through to the preexisting code in MetadataCacheKey which has been
extracted out from MetadataCacheKey::compareWitnessTables into a new
public static function
MetadataCacheKey::compareProtocolConformanceDescriptors.
The new function's availability is "future" for now.
The new function `swift_compareTypeContextDescriptors` is equivalent to
a call through to swift::equalContexts. The implementation it the same
as that of swift::equalContexts with the following removals:
- Handling of context descriptors of kind other outside of
ContextDescriptorKind::Type_First...ContextDescriptorKind::Type_Last.
Because the arguments are both TypeContextDescriptors, the kinds are
known to fall within that range.
- Casting to TypeContextDescriptor. The arguments are already of that
type.
For now, the new function has "future" availability.
When constructing the metadata for a type Gen<T : Super>
where Super is a superclass constraint, the generic argument K at which
the metadata for Gen is being instantiated is verified to be a subclass
of Super via _checkGenericRequirements.
Previously, that check was done using swift_dynamicCastMetatype. That
worked for the most part but provided an incorrect answer if the
metadata for K was not yet complete. These classes are incomplete more
often thanks to __swift_instantiateConcreteTypeFromMangledNameAbstract.
That issue occurred concretely in the following case:
Framework with Library Evolution enabled:
open class Super { ... }
public struct Gen<T : Super> {
}
Target in a different resilience domain from that framework:
class Sub : Super {
var gen: Gen<Sub>?
}
Here, the mechanism for checking whether the generic argument K at which
the metadata for Gen is being instantiated handles the case where K's
metadata is incomplete. At worst, every superclass name from super(K)
up to Super are demangled to instantiate metadata. A number of faster
paths are included as well.
rdar://problem/60790020
The host tools may be built with the host compiler. cl objects to the
"extern C" function returning a C++ type which the keypath functions do.
However, these declarations are needed only in the runtime, which is
always built with clang. Preprocess away the declarations during the
build of the compiler. This allows us to build with cl once more.
This is essentially a long-belated follow-up to Arnold's #12606.
The key observation here is that the enum-tag-single-payload witnesses
are strictly more powerful than the XI witnesses: you can simulate
the XI witnesses by using an extra case count that's <= the XI count.
Of course the result is less efficient than the XI witnesses, but
that's less important than overall code size, and we can work on
fast-paths for that.
The extra inhabitant count is stored in a 32-bit field (always present)
following the ValueWitnessFlags, which now occupy a fixed 32 bits.
This inflates non-XI VWTs on 32-bit targets by a word, but the net effect
on XI VWTs is to shrink them by two words, which is likely to be the
more important change. Also, being able to access the XI count directly
should be a nice win.
We've been running doxygen with the autobrief option for a couple of
years now. This makes the \brief markers into our comments
redundant. Since they are a visual distraction and we don't want to
encourage more \brief markers in new code either, this patch removes
them all.
Patch produced by
for i in $(git grep -l '\\brief'); do perl -pi -e 's/\\brief //g' $i & done
libobjc needs to look up classes by name. Some Swift classes, such as
instantiated generics and their subclasses, are created only on demand.
Now a by-name lookup from libobjc counts as a demand for those classes.
rdar://problem/27808571
The current representation of an associated conformance in a witness
tables (e.g., Iterator: IteratorProtocol within a witness table for
Sequence) is a function that the client calls.
Replace this with something more like what we do for associated types:
an associated conformance is either a pointer to the witness table (once
it is known) or a pointer to a mangled name that describes that
conformance. On first access, demangle the mangled name and replace the
entry with the resulting witness table. This will give us a more compact
representation of associated conformances, as well as always caching
them.
For now, the mangled name is a sham: it’s a mangled relative reference to
the existing witness table accessors, not a true mangled name. In time,
we’ll extend the support here to handle proper mangled names.
Part of rdar://problem/38038799.
Previously, the stdlib provided:
- getters for AnyKeyPath and PartialKeyPath, which have remained;
- a getter for KeyPath, which still exists alongside a new read
coroutine; and
- a pair of owned mutable addressors that provided modify-like behavior
for WritableKeyPath and ReferenceWritableKeyPath, which have been
replaced with modify coroutines and augmented with dedicated setters.
SILGen then uses the most efficient accessor available for the access
it's been asked to do: for example, if it's been asked to produce a
borrowed r-value, it uses the read accessor.
Providing a broad spectrum of accessor functions here seems acceptable
because the code-size hit is fixed-size: we don't need to generate
extra code per storage declaration to support more alternatives for
key paths.
Note that this is just the compiler ABI; the implementation is still
basically what it was. That means the implementation of the setters
and the read accessor is pretty far from optimal. But we can improve
the implementation later; we can't improve the ABI.
The coroutine accessors have to be implemented in C++ and used via
hand-rolled declarations in SILGen because it's not currently possible
to declare independent coroutine accessors in Swift.
Introduce a new runtime entry point, swift_getAssociatedConformanceWitness(),
which extracts an associated conformance witness from a witness table.
Teach IRGen to use this entry point rather than loading the witness
from the witness table and calling it directly.
There’s no advantage to doing this now, but it is staging for changing the
representation of associated conformances in witness tables.
Runtime functions need to use the Swift calling convention for any function
returning MetadataResponse, so that we get the two values returned in separate
registers.
Fixes rdar://problem/45042971 and rdar://problem/45851050.
Expose symbols for metadata for the various builtin floating point types
and vector types. This is used by the demangler to handle builtin names.
This is a narrow fix for rdar://problem/45569984 (where we couldn’t
demangle a builtin vector type). A more extensive fix will require us
to add a general runtime facility for creating opaque type metadata
with specific size/alignment/stride/uniquing name.
This runtime function doesn’t always perform instantiation; it’s how we
get a witness table given a conformance, type, and set of instantiation
arguments. Name it accordingly.
Witness table accessors return a witness table for a given type's
conformance to a protocol. They are called directly from IRGen
(when we need the witness table instance) and from runtime conformance
checking (swift_conformsToProtocol digs the access function out of the
protocol conformance record). They have two interesting functions:
1) For witness tables requiring instantiation, they call
swift_instantiateWitnessTable directly.
2) For synthesized witness tables that might not be unique, they call
swift_getForeignWitnessTable.
Extend swift_instantiateWitnessTable() to handle both runtime
uniquing (for #2) as well as handling witness tables that don't have
a "generic table", i.e., don't need any actual instantiation. Use it
as the universal entry point for "get a witness table given a specific
conformance descriptor and type", eliminating witness table accessors
entirely.
Make a few related simplifications:
* Drop the "pattern" from the generic witness table. Instead, store
the pattern in the main part of the conformance descriptor, always.
* Drop the "conformance kind" from the protocol conformance
descriptor, since it was only there to distinguish between witness
table (pattern) vs. witness table accessor.
* Internalize swift_getForeignWitnessTable(); IRGen no longer needs to
call it.
Reduces the code size of the standard library (+assertions build) by
~149k.
Addresses rdar://problem/45489388.
Collapse the generic witness table, which was used only as a uniquing
data structure during witness table instantiation, into the protocol
conformance record. This colocates all of the constant protocol conformance
metadata and makes it possible for us to recover the generic witness table
from the conformance descriptor (including looking at the pattern itself).
Rename swift_getGenericWitnessTable() to swift_instantiateWitnessTable()
to make it clearer what its purpose is, and take the conformance descriptor
directly.
Have clients pass the requirement base descriptor to
swift_getAssociatedTypeWitness(), so that the witness index is just one
subtraction away, avoiding several dependent loads (witness table ->
conformance descriptor -> protocol descriptor -> requirement offset)
in the hot path.
Rather than rely on the metadata initialization function to compute and
fill in the superclass, use the mangled superclass name to construct the
superclass metadata.
The functions in LibcShims are used externally, some directly and some through @inlineable functions. These are changed to SWIFT_RUNTIME_STDLIB_SPI to better match their actual usage. Their names are also changed to add "_swift" to the front to match our naming conventions.
Three functions from SwiftObject.mm are changed to SPI and get a _swift prefix.
A few other support functions are also changed to SPI. They already had a prefix and look like they were meant to be SPI anyway. It was just hard to notice any mixup when they were #defined to the same thing.
rdar://problem/35863717
Rather than storing associated type metadata access functions in
witness tables, initially store a pointer to a mangled type name.
On first access, demangle that type name and replace the witness
table entry with the resulting type metadata.
This reduces the code size of protocol conformances, because we no
longer need to create associated type metadata access functions for
every associated type, and the mangled names are much smaller (and
sharable). The same code size improvements apply to defaulted
associated types for resilient protocols, although those are more
rare. Witness tables themselves are slightly smaller, because we
don’t need separate private entries in them to act as caches.
On the caller side, associated type metadata is always produced via
a call to swift_getAssociatedTypeWitness(), which handles the demangling
and caching behavior.
In all, this reduces the size of the standard library by ~70k. There
are additional code-size wins that are possible with follow-on work:
* We can stop emitting type metadata access functions for non-resilient
types that have constant metadata (like `Int`), because they’re only
currently used as associated type metadata access functions.
* We can stop emitting separate associated type reflection metadata,
because the reflection infrastructure can use these mangled names
directly.
If a class has a backward deployment layout:
- We still want to emit it using the FixedClassMetadataBuilder.
- We still want it to appear in the objc_classes section, and get an
OBJC_CLASS_$_ symbol if its @objc.
- However, we want to use the singleton metadata initialization pattern
in the metadata accessor.
- We want to emit metadata for all field types, and call the
swift_updateClassMetadata() function to initialize the class
metadata.
For now, this function just performs the idempotent initialization of
invoking a static method on the class, causing it to be realized with
the Objective-C runtime.
- Rename _swift_initializeSuperclass() to copySuperclassMetadataToSubclass(),
- Factor out initClassFieldOffsetVector()
- Factor out initClassVTable()
- Factor out initGenericObjCClass()
Previously we would emit class metadata for classes with resilient
ancestry, and relocate it at runtime once the correct size was known.
However most of the fields were blank, so it makes more sense to
construct the metadata from scratch, and store the few bits that we
do need in a true-const pattern where we can use relative pointers.
Now that we don't need the superclass before calling
swift_relocateClassMetadata(), it seems simpler to set it
here instead of doing it in various places in IRGen.
Using the superclass metadata here no longer makes sense with two-phase
init, in case the superclass metadata depends on the class being
instantiated.
It would also be nice to rework the resilient class metadata 'pattern'
to be its own data structure that's true const, instead of just the
prefix of a real class metadata, but for now let's keep the existing
crappy design.