The majority of support comes in the form of emitting partial
application forwarders for partial applications of async functions.
Such a partial application forwarder must take an async context which
has been partially populated at the apply site. It is responsible for
populating it "the rest of the way". To do so, like sync partial
application forwarders, it takes a second argument, its context, from
which it pulls the additional arguments which were capture at
partial_apply time.
The size of the async context that is passed to the forwarder, however,
can't be known at the apply site by simply looking at the signature of
the function to be applied (not even by looking at the size associated
with the function in the special async function pointer constant which
will soon be emitted). The reason is that there are an unknown (at the
apply site) number of additional arguments which will be filled by the
partial apply forwarder (and in the case of repeated partial
applications, further filled in incrementally at each level). To enable
this, there will always be a heap object for thick async functions.
These heap objects will always store the size of the async context to be
allocated as their first element. (Note that it may be possible to
apply the same optimization that was applied for thick sync functions
where a single refcounted object could be used as the context; doing so,
however, must be made to interact properly with the async context size
stored in the heap object.)
To continue to allow promoting thin async functions to thick async
functions without incurring a thunk, at the apply site, a null-check
will be performed on the context pointer. If it is null, then the async
context size will be determined based on the signature. (When async
function pointers become pointers to a constant with a size i32 and a
relative address to the underlying function, the size will be read from
that constant.) When it is not-null, the size will be pulled from the
first field of the context (which will in that case be cast to
<{%swift.refcounted, i32}>).
To facilitate sharing code and preserving the original structure of
emitPartialApplicationForwarder (which weighed in at roughly 700 lines
prior to this change), a new small class hierarchy, descending from
PartialApplicationForwarderEmission has been added, with subclasses for
the sync and async case. The shuffling of arguments into and out of the
final explosion that was being performed in the synchronous case has
been preserved there, though the arguments are added and removed through
a number of methods on the superclass with more descriptive names. That
was necessary to enable the async class to handle these different
flavors of parameters correctly.
To get some initial test coverage, the preexisting
IRGen/partial_apply.sil and IRGen/partial_apply_forwarder.sil tests have
been duplicated into the async folder. Those tests cases within these
files which happened to have been crashing have each been extracted into
its own runnable test that both verifies that the compiler does not
crash and also that the partial application forwarder behaves correctly.
The FileChecks in these tests are extremely minimal, providing only
enough information to be sure that arguments are in fact squeezed into
an async context.
In too many places, we were calling into `emitDynamicTypeOfOpaqueHeapObject` even when we had
more specific type information about the heap object we were querying. Replace all calls with
`emitDynamicTypeOfHeapObject`, which uses the best available access path and completely avoids
runtime calls for pure Swift classes and heap objects. When targeting non-ObjC-interop platforms,
we also know we never need to call `swift_getObjectType`, so avoid doing so altogether.
A Swift subclass of an ObjC class can be dynamically subclassed, but `type(of:)` shouldn't return the artificial subclass, since that's not what -class does for ObjC classes, and people expect `Bundle(for: type(of: c))` to work like `[NSBundle bundleForClass: [c class]]` would in ObjC. Fixes rdar://problem/37319860.
When we use type(of: x) on a class in an ObjC bridged context, the optimizer turns this into a SIL `value_metatype @objc` operation, which is supposed to get the dynamic type of the object as an ObjC class. This was previously lowered by IRGen into a `object_getClass` call, which extracts the isa pointer from the object, but is inconsistent with the `-class` method in ObjC or with the Swift-native behavior, which both look through artificial subclasses, proxies, and so on. This inconsistency led to observably different behavior between debug and release builds and between ObjC-bridged and native entry points, so provide an alternative runtime entry point that replicates the behavior of getting a native Swift class. Fixes SR-7258.
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.
Officially kick SILBoxType over to be "nominal" in its layout, with generic layouts structurally parameterized only by formal types. Change SIL to lower a capture to a nongeneric box when possible, or a box capturing the enclosing generic context when necessary.
We were recovering metadata from generic boxes by reading
the instantiated payload metadata from the box's metadata,
but this approach doesn't work for fixed-size boxes, whose
metadata does not store the payload metadata at all.
Instead, emit a capture descriptor with no metadata sources
and a single capture, using the lowered AST type appearing
in the alloc_box instruction that emitted the box.
Since box metadata is shared by all POD types of the same
size, and all single-retainable pointer payloads, the
AST type might not accurately reflect what is actually in
the box.
However, this type is *layout compatible* with the box
payload, at least enough to know where the retainable
pointers are, because after all IRGen uses this type to
synthesize the destructor.
Fixes <rdar://problem/26314060>.
Now we can discern the types of values in heap boxes at runtime!
Closure reference captures are a common way of creating reference
cycles, so this provides some basic infrastructure for detecting those
someday.
A closure capture descriptor has the following:
- The number of captures.
- The number of sources of metadata reachable from the closure.
This is important for substituting generics at runtime since we
can't know precisely what will get captured until we observe a
closure.
- The number of types in the NecessaryBindings structure.
This is a holding tank in a closure for sources of metadata that
can't be gotten from the captured values themselves.
- The metadata source map, a list of pairs, for each
source of metadata for every generic argument needed to perform
substitution at runtime.
Key: The typeref for the generic parameter visible from the closure
in the Swift source.
Value: The metadata source, which describes how to crawl the heap from
the closure to get to the metadata for that generic argument.
- A list of typerefs for the captured values themselves.
Follow-up: IRGen tests for various capture scenarios, which will include
MetadataSource encoding tests.
rdar://problem/24989531
dealloc_ref [destructor] is the existing behavior. It expects the
reference count to have reached zero and the isDeallocating bit to
be set.
The new [constructor] variant first drops the initial strong
reference.
This allows DI to properly free uninitialized instances in
constructors. Previously this would fail with an assertion if the
runtime was built with debugging enabled.
Progress on <rdar://problem/21991742>.
Swift SVN r31142
When producing TypeInfo for a box, try to reuse instantiations for common type structures:
- any POD type with the same stride and alignment can share a fixed HeapLayout;
- any single-refcounted-pointer type can share a fixed HeapLayout with types that have the same ReferenceCounting;
- dynamically-sized types can share a runtime-based box implementation.
For the runtime implementation, use new to-be-implemented variants of allocBox/deallocBox that will produce polymorphically-projectable boxes using instantiated metadata.
Swift SVN r29612
OpaqueStorageTypeInfo uses iNNN types that don't always have the correct alloc size for an expected
size at the LLVM level. This needs to be fixed before my partial apply closure fixes can hold.
Swift SVN r24551
In order to deal with generic indirect value captures, we need to be able to bind their type metadata in the partial apply forwarder and heap object destructor to have access to the value operations for that type. NecessaryBindings gives us a way to do that and clean up our ad-hoc polymorphic argument forwarding we had before. N(intended)FC yet, aside from some harmless reordering of operations, since we also need to implement NonFixedOffsets for heap objects to be fully operational.
Swift SVN r24526
- A spot fix in SILGen for reabstracting the result of a downcast, which fixes checked casts to function types.
- Associate the layout information in type metadata records with the most abstract representation of the type. This is the correct thing to do in cases where we need the metadata as a tag for an opaque value--if we store a value in an Any, or pass it as an unconstrained generic parameter, we must maximally reabstract it. This fixes the value semantics of existentials containing trivial metatypes.
- To ensure that we get runtime layout of structs and enums correct when they contain reabstractable types, introduce a "metadata for layout" concept, which doesn't need to describe the canonical metadata for the type, but only needs to describe a type with equivalent layout and value semantics. This is a correctness fix that allows us to correctly lay out generic types containing dependent tuples and functions, and although we don't really take advantage of it here, it's also a potential runtime performance win down the road, because we could potentially produce direct metadata for a primitive type that's layout-equivalent with a runtime-instantiated type. To aid in type safety here, push SILType deeper into IRGen in places where we potentially care about specific representations of types.
- Finally, fix an inconsistency between the runtime and IRGen's concept of what spare bits unmanaged references and thick metatypes have.
Together, these fixes address rdar://problem/16406907, rdar://problem/17822208, rdar://problem/18189508, and likely many other related issues, and also fixes crash suite cases 012 and 024.
Swift SVN r21963
IRGen type conversion is invariant with respect to archetypes with the same set of constraints, so instead of redundantly generating a TypeInfo object and IR type for Optional<T> for every T everywhere, key TypeInfo objects using an "exemplar type" that we form using a folding set to collapse together archetypes with the same class-ness, superclass constraint, and protocol constraints.
This is a nice memory and IR size optimization, but will be essential for correctness when lowering interface types, because there is no unique context to ground a dependent type, and we need to lower the same generic parameter with the same context requirements to the same type whenever we instantiate it in order for the IR to type-check.
In this revision, we profile the nested archetypes of each recursively, which I neglected to take into account originally in r12112, causing failures when archetypes that differed by associated type constraints were incorrectly collapsed.
Swift SVN r12116
IRGen type conversion is invariant with respect to archetypes with the same set of constraints, so instead of redundantly generating a TypeInfo object and IR type for Optional<T> for every T everywhere, key TypeInfo objects using an "exemplar type" that we form using a folding set to collapse together archetypes with the same class-ness, superclass constraint, and protocol constraints.
This is a nice memory and IR size optimization, but will be essential for correctness when lowering interface types, because there is no unique context to ground a dependent type, and we need to lower the same generic parameter with the same context requirements to the same type whenever we instantiate it in order for the IR to type-check.
Swift SVN r12112
Emit the deallocObject runtime call inside the deallocating destructor for a heap object, instead of inside swift_release. This will allow for heap objects with known size to directly call fast deallocator entry points and potentially custom deallocators in the future.
Swift SVN r5027
handling non-fixed layouts.
This uncovered a bug where we weren't rounding up the header
size to the element alignment when allocating an array of archetypes.
Writing up a detailed test case for *that* revealed that we were
never initializing the length field of heap arrays. Fixing that
caused a bunch of tests to crash trying to release stuff. So...
I've left this in a workaround state right now because I have to
catch a plane.
Swift SVN r4804
Implement ElementAddrInst for lvalue tuples, and implement the AllocArray, IndexAddr, and IntegerValue insts used to lower variadic tuples. (Actually compiling code that uses variadic tuples still requires support for SpecializeInst and generic functions.)
Swift SVN r3781
The test changes are that we're setting a class body on
some types that we weren't before. For some of these,
this is okay; for others, it's more questionable, but
ultimately not *harmful*.
Swift SVN r3746
The principal difficulty here is that we need accessing the
value witness table for a type to be an efficient operation,
but there (obviously) isn't a VWT field for ObjC classes.
Placing this field after the metatype would tend to bloat
metatypes by quite a bit. Placing it before is best, but
it introduces an unfortunate difference between the address
point of a metatype and the address of the global symbol.
That, however, can be fixed with appropriate linker support.
Still, for now this is rather unfortunately over-subtle.
Swift SVN r3307
The motivations here are that (1) the parametric types
that actually need the 'self' argument don't necessarily
all want to do what tuples do and put the VWT relative
to the metatype at some definable offset and (2)
recovering type parameters from the metatype is much
better defined than also hopping some relationship back.
Plus this allows VWTs to be shared across instances of
generic types. Also, I'm going to need to add a VW
that takes a metatype, and consistency seems right here.
If keeping two values live is actually punishing, I
might have to reconsider this. But the VWT is at least
always recoverable from the metatype, so....
I ended up abstracting the thing that GenHeap was doing
in order to save archetypes for arrays, because I
needed it to save metatypes instead of VWTs and because
it really needed abstractin'.
Swift SVN r3096
This is kindof a pain in a few places where the type system
doesn't propagate canonicality. Also, member initializations
are always direct-initializations and so are allowed to use
explicit constructors, which is a hole in our canonicality
tracking. But overall I like the idea of always working
with canonical types.
Swift SVN r2893
heap allocations it makes, and switch swift_alloc over to pass
that pointer in as well as the alignment. Also, compute
whether a type is POD during its generation and cache that in
the object, and introduce a method on TypeInfo to destroy an
object in memory.
Swift SVN r1356