Previously, when a tuple type had non-fixed layout, we would compute
a layout by building the metadata for that tuple type and then
extracting the layout from the VWT. This can be quite expensive
because it involves constructing the exact metadata for types like
arrays and functions despite those types being fixed-layout across
all instantiations. It also tends to cause unnecessary recursive-type
issues, especially with enums where tuples are currently used to model
cases with mutliple payloads. Since we just need a layout, computing
it directly from element layouts instead of constructing metadata for
the formal type lets us take advantage of all the other fast paths for
layout construction, e.g. for fixed types and single-field aggregates.
This is a good improvement overall, but it also serves to alleviate
some of the problems of rdar://40810002 / SR-7876 in a way that
might be suitable for integration to 4.2.
- `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 prefab'ed value witness tables for reference storage types are a
premature optimization. Not all scenarios are covered, and those that
are "look suspect" according to John McCall.
From what I see the only fields are DATA_VALUE_WITNESS which
all have type size_t. I converted them to use the target-dependent
`StoredSize`. While I was around I fixed also isValueInline()
to do the right thing (it was using ValueBuffer instead of
TargetValueBuffer) and all the getters for the data value witnesses.
<rdar://problem/41546568>
Switch one entry point in the runtime (swift_getExistentialTypeMetadata)
to use ProtocolDescriptorRef rather than a protocol descriptor. Update
IRGen to produce ProtocolDescriptorRef instances for its calls, setting
the discriminator bit appropriately.
Within the runtime, verify that all instances of ProtocolDescriptorRef have
the right layout, i.e., the discriminator bit is set for @objc protocols
but not Swift protocols.
Runtime/Metadata.h collected a large number of metadata data
structures that are actually part of the ABI. Move those data
structures into a new header, ABI/Metadata.h, and keep the in-process,
runtime-specific bits in Runtime/Metadata.h.
We want to be able to potentially introduce new metadata kinds in future Swift compilers, so a runtime ought to be able to degrade gracefully in the face of metadata kinds it doesn't know about. Remove attempts to exhaustively switch over metadata kinds and instead treat unknown metadata kinds as opaque.
- Add swift_getForeignWitnessTable to unique non-unique foreign type
witness tables
- IRGen: Call the foreign witness uniquing runtime function
rdar://24958043
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.
Type of elements contained by field offsets vector can be adjusted
to 32-bit integers (from being pointer sized) to safe space in the
binary since segment size is limited to 4 GB.
Resolves: rdar://problem/36560486
I was going to put this off for awhile, but it turns out that a lot of
my testcases are enums with multi-payload cases, which we currently
compile as tuples, so they were all still hanging until this patch.
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++.
These will be used as lookup keys for order-independent witness
table instantiation. In the future, a reflective call mechanism
could make use of this metadata as well.
Rename it to swift_initClassMetadata() just like we recently did
swift_initStructMetadata(), and add a StructLayoutFlags parameter
so we can version calls to this function in the future.
Maybe at some point this will become a separate ClassLayoutFlags
type, but at this point it doesn't matter because IRGen always
passes a value of 0.
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.
Now that every foreign type has a type context descriptor, we can use that for a uniquing key instead of a dedicated mangled string, saving some code size especially in code that makes heavy use of imported types. rdar://problem/37537241
The allocation phase is guaranteed to succeed and just puts enough
of the structure together to make things work.
The completion phase does any component metadata lookups that are
necessary (for the superclass, fields, etc.) and performs layout;
it can fail and require restart.
Next up is to support this in the runtime; then we can start the
process of making metadata accessors actually allow incomplete
metadata to be fetched.
The layout changes to become relative-address based. For this to be
truly immutable (at least on Darwin), things like the RO data patterns
must be moved out of the pattern header. Additionally, compress the
pattern header so that we do not include metadata about patterns that
are not needed for the type.
Value metadata patterns just include the metadata kind and VWT.
The design here is meant to accomodate non-default instantiation
patterns should that become an interesting thing to support in the
future, e.g. for v-table specialization.
This is simpler, because the native form of that last argument is: a
pointer to a buffer (*) of pointers (*) to witness tables, which is
modelled as a buffer of void *s. Thus, void ***.
Change the "metadata base offset" variable into a "class metadata bounds"
variable that contains the base offset and the +/- bounds on the class.
Link this variable from the class descriptor when the class has a resilient
superclass; otherwise, store the +/- bounds there. Use this variable to
compute the immediate-members offset for various runtime queries. Teach the
runtime to fill it in lazily and remove the code to compute it from the
generated code for instantiation. Identify generic arguments with the start
of the immediate class metadata members / end of the {struct,enum} metadata
header and remove the generic-arguments offset from generic type descriptors.
Minimize the generic class metadata template by removing the
class header and base-class members. Add back the set of
information that's really required for instantiation.
Teach swift_allocateGenericClass how to allocate classes without
superclass metadata. Reorder generic initialization to establish
a stronger phase-ordering between allocation (the part that doesn't
really care about the generic arguments) and initialization (the
part that really does care about the generic arguments and therefore
might need to be delayed to handle metadata cycles).
A similar thing needs to happen for resilient class relocation.