- Create the value witness table as a separate global object instead
of concatenating it to the metadata pattern.
- Always pass the metadata to the runtime and let the runtime handle
instantiating or modifying the value witness table.
- Pass the right layout algorithm version to the runtime; currently
this is always "Swift 5".
- Create a runtime function to instantiate single-case enums.
Among other things, this makes the copying of the VWT, and any
modifications of it, explicit and in the runtime, which is more
future-proof.
We can reduce the uniquing header from 3–4 pointer-sized words down to 1–2 32-bit words + one pointer:
- The initialization function (when present) and name are always emitted into the same binary image, so we can use relative references to shrink these down to 32-bit fields.
- We don't ever simultaneously need the initialization flags and the initialized uniqued pointer. (Keeping the "initialization function" flag bit theoretically lets us turn a "consume" load into a "relaxed" load, but that makes no practical difference on most contemporary architectures.) 12 flag bits Ought To Be Enough For Anyone and lets us reliably tell a valid pointer from a flag set, so overlap the initialization flags with the eventual invasive cache value.
The invasive cache is left inline, since we've decided we're not going to make the rest of type metadata records ever be true-const, so they'll already be sitting on a dirty page. A dynamic linker that was sufficiently Swift-optimized to precalculate the other load-time-initialized entries in metadata could likely precompute the invasive cache value as well.
rdar://problem/22527141
NFC intended. The layout of trailing matter here is getting fairly complex, so it's good to use LLVM's existing library code to keep track of it. We use a fork of llvm's TrailingObjects.h header so that future changes to LLVM don't disturb the ABI of Swift runtime objects that use the template.
Don't emit placeholders for field offsets and vtable entries,
since they were always null. Instead, calculate the final size
of class metadata at runtime using the size of the superclass
metadata and the number of immediate members, and only copy
this prefix from the template to the instantiated metadata,
zero-filling the rest.
For this to work with non-generic resilient classes and
non-generic subclasses of generic classes, we need a new
runtime entry point to relocate non-generic class metadata,
calculating its size at runtime using the same strategy.
When allocating metadata for a generic class we would copy
any prefix matter from the superclass metadata, if the
superclass metadata's address point was greater than our
address point.
While we may use prefix matter for resilient metadata
in the future, I don't believe just copying bytes like
this will prove useful.
Switch most general endpoint to be `flags, parameters, parameterFlags, result`,
instead of opaque `void **`, more specialized ones to use follow argument scheme:
`flags, param0, [flags0], ..., paramN, [flagsN], result` and store parameter/flags
information separately in `FunctionCacheEntry::{Key, Data}` as well.
Currently only single 'inout' flag has been encoded into function
metadata, these changes extend function metadata to support up to
32 flags per parameter.
Switch most general endpoint to be `flags, parameters, parameterFlags, result`,
instead of opaque `void **`, more specialized ones to use follow argument scheme:
`flags, param0, [flags0], ..., paramN, [flagsN], result` and store parameter/flags
information separately in `FunctionCacheEntry::{Key, Data}` as well.
Currently only single 'inout' flag has been encoded into function
metadata, these changes extend function metadata to support up to
32 flags per parameter.
This is a small code size win, and also gives us some abstraction so that future cooperative ObjC compilers/runtimes might be able to interoperate ObjC class objects with Swift type metadata efficiently than they currently are in the fragile Swift runtime.
While I'm here, I also noticed that swift_getObjCClassMetadata was unnecessarily getting exposed in non-ObjC-interop runtime builds, so I fixed that as well.
So far single payload enums were implemented in terms of runtime functions which
internally emitted several calls to value witnesses.
This commit adds value witnesses to get and store the enum tag side stepping the
need for witness calls as this information is statically available in many cases
/// int (*getEnumTagSinglePayload)(const T* enum, UINT_TYPE emptyCases)
/// Given an instance of valid single payload enum with a payload of this
/// witness table's type (e.g Optional<ThisType>) , get the tag of the enum.
/// void (*storeEnumTagSinglePayload)(T* enum, INT_TYPE whichCase,
/// UINT_TYPE emptyCases)
/// Given uninitialized memory for an instance of a single payload enum with a
/// payload of this witness table's type (e.g Optional<ThisType>), store the
/// tag.
A simple 'for element in array' loop in generic code operating on a
ContigousArray of Int is ~25% faster on arm64.
rdar://31408033
This changes layout of the parameter metadata from single tuple record
(in case of materializable type) to N records each corresponding to
invididual function parameter, where functions with no parameters
`() -> Void` get 0 records allocated.
The NTD now references the metadata accessor function for the type, which is a better interface for most things one would want to do with type metadata from a nominal type. The only remaining use in the runtime self really has no requirement to do so. For now, don't disturb the binary layout to prevent breaking downstream clients.
Alter the value metadata layout to use an absolute pointer for the
nominal type descriptor rather than a relative offset relative to the
complete type metadata. Although this is slightly less efficient in
terms of load times, this is more portable across different
environments. For example, PE/COFF does not provide a cross-section
relative offset relocation. Other platform ports are unable to provide
a 64-bit relative offset encoding.
Given that the value witness table reference in the value metadata is
currently an absolute pointer, this page is most likely going to be
dirtied by the loader.
We no longer need this for anything, so remove it from metadata
altogether. This simplifies logic for emitting type metadata and
makes type metadata smaller.
We still pass the parent metadata pointer to type constructors;
removing that is a separate change.
This is a blanket pass replacing use of `__LP64__` with
`__POINTER_WIDTH__ == 64`. The latter is more expressive and also LLP64
clean. This change is needed to enable support for Windows x86_64 which
is a LLP64 environment.
- Always include an array of requirement descriptors in the protocol
descriptor. For now, this doesn't contain anything except a general
requirement kind and an optional default implementation, but eventually
this can be augmented with type / name metadata. This array is always
emitted as constant.
- Guarantee the value of the extent fields in a protocol descriptor and
slightly tweak their meaning.
- Move the private-data field out of line in a generic witness table
descriptor so that the main descriptor can be emitted as constant.
- Rely on IRGen's notion of the witness-table layout instead of assuming
that SILWitnessTable and SILDefaultWitnessTable match the actual
physical layout.
This version of the patch uses a hack in which we assign internal rather
than private linkage to certain symbols in order to work around a Darwin
linker bug.
Previous patches changed the runtime to copy the vtable from the
superclass rather than IRGen emitting it statically for generic
and resilient classes.
However for generic classes we would still copy the vtable entries
for methods defined in the immediate class from the template.
Instead, store them in the nominal type descriptor, where they use
less space since we can use relative pointers, and copy them out of
there.
This will allow us to 'slim down' generic class templates eventually.