Skip to content

Commit 625c37e

Browse files
committed
Describe the technical design of metadata states and cycle resolution.
1 parent 50f8519 commit 625c37e

File tree

1 file changed

+233
-0
lines changed

1 file changed

+233
-0
lines changed

docs/ABI/TypeMetadata.rst

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,3 +509,236 @@ contains:
509509
3. Reserved for future use.
510510

511511
- A 32-bit value reserved for future use.
512+
513+
Recursive Type Metadata Dependencies
514+
------------------------------------
515+
516+
The Swift type system is built up inductively by the application of
517+
higher-kinded type constructors (such as "tuple" or "function", as well
518+
as user-defined generic types) to other, existing types. Crucially, it
519+
is the "least fixed point" of that inductive system, meaning that it
520+
does not include **infinite types** (µ-types) whose basic identity can
521+
only be defined in terms of themselves.
522+
523+
That is, it is possible to write the type::
524+
525+
typealias IntDict = Dictionary<String, Int>
526+
527+
but it is not possible to directly express the type::
528+
529+
typealias RecursiveDict = Dictionary<String, RecursiveDict>
530+
531+
However, Swift does permit the expression of types that have recursive
532+
dependencies upon themselves in ways other than their basic identity.
533+
For example, class ``A`` may inherit from a superclass ``Base<A>``,
534+
or it may contain a field of type ``(A, A)``. In order to support
535+
the dynamic reification of such types into type metadata, as well as
536+
to support the dynamic layout of such types, Swift's metadata runtime
537+
supports a system of metadata dependency and iterative initialization.
538+
539+
Metadata States
540+
~~~~~~~~~~~~~~~
541+
542+
A type metadata may be in one of several different dynamic states:
543+
544+
- An **abstract** metadata stores just enough information to allow the
545+
identity of the type to be recovered: namely, the metadata's kind
546+
(e.g. **struct**) and any kind-specific identity information it
547+
entails (e.g. the `nominal type descriptor`_ and any generic arguments).
548+
549+
- A **layout-complete** metadata additionally stores the components of
550+
the type's "external layout", necessary to compute the layout of any
551+
type that directly stores a value of the type. In particular, a
552+
metadata in this state has a meaningful value witness table.
553+
554+
- A **non-transitively complete** metadata has undergone any additional
555+
initialization that is required in order to support basic operations
556+
on the type. For example, a metadata in this state will have undergone
557+
any necessary "internal layout" that might be required in order to
558+
create values of the type but not to allocate storage to hold them.
559+
For example, a class metadata will have an instance layout, which is
560+
not required in order to compute the external layout, but is required
561+
in order to allocate instances or create a subclass.
562+
563+
- A **complete** metadata additionally makes certain guarantees of
564+
transitive completeness of the metadata referenced from the metadata.
565+
For example, a complete metadata for ``Array<T>`` guarantees that
566+
the metadata for ``T`` stored in the generic arguments vector is also
567+
complete.
568+
569+
Metadata never backtrack in their state. In particular, once metadata
570+
is complete, it remains complete forever.
571+
572+
Transitive Completeness Guarantees
573+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
574+
575+
A complete class metadata makes the following guarantees:
576+
577+
- Its superclass metadata (if it has a superclass) is complete.
578+
- Its generic arguments (if it has any) are complete.
579+
- By implication, the generic arguments of its superclasses are complete.
580+
581+
A complete struct, enum, or optional metadata makes the following guarantees:
582+
583+
- Its generic arguments (if it has any) are complete.
584+
585+
A complete tuple metadata makes the following guarantees:
586+
587+
- Its element types are complete.
588+
589+
Other kinds of type metadata do not make any completeness guarantees.
590+
The metadata kinds with transitive guarantees are the metadata kinds that
591+
potentially require two-phase initialization anyway. Other kinds of
592+
metadata could otherwise declare themselves complete immediately on
593+
allocation, so the transitive completeness guarantee would add significant
594+
complexity to both the runtime interface and its implementation, as well
595+
as adding probably-unrecoverable memory overhead to the allocation process.
596+
597+
It is also true that it is far more important to be able to efficiently
598+
recover complete metadata from the stored arguments of a generic type
599+
than it is to be able to recover such metadata from a function metadata.
600+
601+
Completeness Requirements
602+
~~~~~~~~~~~~~~~~~~~~~~~~~
603+
604+
Type metadata are required to be transitively complete when they are
605+
presented to most code. This allows that code to work with the metadata
606+
without explicitly checking for its completeness. Metadata in the other
607+
states are typically encountered only when initializing or building up
608+
metadata.
609+
610+
Specifically, a type metadata record is required to be complete when:
611+
612+
- It is passed as a generic argument to a function (other than a metadata
613+
access function, witness table access function, or metadata initialization
614+
function).
615+
- It is stored as a metatype value.
616+
- It is used to build an existential value.
617+
- It is passed as the ``Self`` argument to a ``static`` or ``class`` method,
618+
including an initializer.
619+
620+
Metadata Requests and Responses
621+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
622+
623+
When calling a metadata access function, code must provide the following
624+
information:
625+
626+
- the required state of the metadata, and
627+
- whether the callee should block until the metadata is available
628+
in that state.
629+
630+
The access function will then return:
631+
632+
- the metadata and
633+
- the current dynamic state of the metadata.
634+
635+
Access functions will always return the correct metadata record; they
636+
will never return a null pointer. If the metadata has not been allocated
637+
at the time of the request, it will at least be allocated before the
638+
access function returns. The runtime will block the current thread until
639+
the allocation completes if necessary, and there is currently no way to
640+
avoid this.
641+
642+
Since access functions always return metadata that is at least in the
643+
abstract state, it is not meaningful to make a non-blocking request
644+
for abstract metadata.
645+
646+
The returned dynamic state of the metadata may be less than the requested
647+
state if the request was non-blocking. It is not otherwise affected by
648+
the request; it is the known dynamic state of the metadata at the time of
649+
the call. Note that of course this dynamic state is just a lower bound
650+
on the actual dynamic state of the metadata, since the actual dynamic
651+
state may be getting concurrently advanced by another thread.
652+
653+
In general, most code should request metadata in the **complete**
654+
state (as discussed above) and should block until the metadata is
655+
available in that state. However:
656+
657+
- When requesting metadata solely to serve as a generic argument of
658+
another metadata, code should request **abstract** metadata. This
659+
can potentially unblock cycles involving the two metadata.
660+
661+
- Metadata initialization code should generally make non-blocking
662+
requests; see the next section.
663+
664+
Metadata access functions that cache their results should only cache
665+
if the dynamic state is complete; this substantially simplifies the caching
666+
logic, and in practice most metadata will be dynamically complete.
667+
Note that this rule can be applied without considering the request.
668+
669+
Code outside of the runtime should never attempt to ascertain a
670+
metadata's current state by inspecting it, e.g. to see if it has a value
671+
witness table. Metadata initialization is not required to use
672+
synchronization when initializing the metadata record; the necessary
673+
synchronization is done at a higher level in the structures which record
674+
the metadata's dynamic state. Because of this, code inspecting aspects
675+
of the metadata that have not been guaranteed by the returned dynamic
676+
state may observe partially-initialized state, such as a value witness
677+
table with a meaningless size value. Instead, that code should call
678+
the ``swift_checkMetadataState`` function.
679+
680+
Metadata Allocation and Initialization
681+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
682+
683+
In order to support recursive dependencies between type metadata,
684+
the creation of type metadata is divided into two phases:
685+
686+
- allocation, which creates an abstract metadata, and
687+
- initialization, which advances the metadata through the progression
688+
of states.
689+
690+
Allocation cannot fail. It should return relatively quickly and
691+
should not make any metadata requests.
692+
693+
The initialization phase will be repeatedly executed until it reaches
694+
completion. It is only executed by one thread at a time.
695+
Compiler-emitted initialization functions are given a certain amount
696+
of scratch space that is passed to all executions; this can be used
697+
to skip expensive or unrepeatable steps in later re-executions.
698+
699+
Any particular execution of the initialization phase can fail due
700+
to an unsatisfied dependency. It does so by returning a **metadata
701+
dependency**, which is a pair of a metadata and a required state for
702+
that metadata. The initialization phase is expected to make only
703+
non-blocking requests for metadata. If a response does not satisfy
704+
the requirement, the returned metadata and the requirement should
705+
be presented to the caller as a dependency. The runtime does two
706+
things with this dependency:
707+
708+
- It attempts to add the initialization to the **completion queue**
709+
of the dependent metadata. If this succeeds, the initialization
710+
is considered blocked; it will be unblocked as soon as the
711+
dependent metadata reaches the required state. But it can also
712+
fail if the dependency is already resolved due to concurrent
713+
initialization; if so, the initialization is immediately resumed.
714+
715+
- If it succeeds in blocking the initialization on the dependency,
716+
it will check for an unresolvable dependency cycle. If a cycle exists,
717+
it will be reported on stderr and the runtime will abort the process.
718+
This depends on the proper use of non-blocking requests; the runtime
719+
does not make any effort to detect deadlock due to cycles of blocking
720+
requests.
721+
722+
Initialization must not repeatedly report failure based on stale
723+
information about the dynamic state of a metadata. (For example,
724+
it must not cache metadata states from previous executions in the
725+
initialization scratch space.) If this happens, the runtime may spin,
726+
repeatedly executing the initialization phase only to have it fail
727+
in the same place due to the same stale dependency.
728+
729+
Compiler-emitted initialization functions are only responsible for
730+
ensuring that the metadata is **non-transitively complete**.
731+
They signal this by returning a null dependency to the runtime.
732+
The runtime will then ensure transitive completion. The initialization
733+
function should not try to "help out" by requesting complete metadata
734+
instead of non-transitively-complete metadata; it is impossible to
735+
resolve certain recursive transitive-closure problems without the
736+
more holistic information available to the runtime. In general, if
737+
an initialization function seems to require transitively-complete
738+
metadata for something, try to make it not.
739+
740+
If a compiler-emitted initialization function returns a dependency,
741+
the current state of the metadata (**abstract** vs. **layout-complete**)
742+
will be determined by inspecting the **incomplete** bit in the flags
743+
of the value witness table. Compiler-emitted initialization functions
744+
are therefore responsible for ensuring that this bit is set correctly.

0 commit comments

Comments
 (0)