-
Notifications
You must be signed in to change notification settings - Fork 10.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SR-3928] Resilient super.foo() calls #46513
Comments
To be clear, some part of "vtables" is ABI, in that subclasses provide a list of methods they want to override and a list of new override points somehow. But that information can be versioned. The more important thing to decide is if calling a dynamically-dispatched method on a class directly accesses the vtable from client code. |
@swift-ci create |
TL;DR: vtables are not ABI! Here is a plan for the initial method dispatch ABI and implementation that meets
Each method declaration can be identified by a "method index". Method Each nominal class
Each nominal class exports a method dispatch entry point: resolve_method_for_<public_class_name>(isa, method_index) Invoking a method declared in a base class would be done like this: resolve_method_for_Base(isa_for_Derived, index_of_Base_foo) At the caller side, dispatch requires this code pattern: isa = load self
f = resolve_method_for_<public_class_name>(isa, method_index)
f(self, ...) Dispatch will initially be implemented as these steps:
Notes: Slava wants a separate sybol for each member so that SIL can be Why this is good:
|
What's the form of the metadata that gets emitted for a subclass that overrides some of its superclass's methods? |
I only explained dispatch above, not metadata initialization. All we (a) An ABI-exposed metadata field for the size reserved in the (b) An exported per-class metadata member initializer helper. I'll explain metadata initialization now and that should answer Jordan's question. To initialize class `Sub` derived from `Base`: (1) Initialize metadata for `Base`. (2) Load the size of `Base`'s member metadata from an ABI-exposed field in its base_meta_member_size = *(base_nominal_metadata + const_member_size_offset) (3) Repeat 1-2 for all base classes of `Sub`. (4) Allocate `Sub` metadata (with size += base_meta_member_size) (5) Initialize members of each class in the hierarchy with overrides overrides = {{methodID, funcPtr}, ...}
global_init_meta_members_for_Base(overrides) (6) Repeat 5 for all base classes of `Sub` and `Sub` itself. @slavapestov I don't see a need to export a global per-class member offset variable for either method dispatch or metadata initialization. It seems like an implementation detail. We probably still want to export it for property access though. |
Property access is done with accessors so we don't want to export field offset globals either. |
Correction to the proposal discussed above. The following is not true: "Each nominal class exports a "member offset" global variable." A global "member offset" variable will be associated with each nominal class, but it will not be exported as ABI. |
We still need to expose a base offset variable or some other mechanism to resiliently access generic argument metadata, so that you can define extensions of generic classes in other modules. But yeah, I don't think we need this for virtual methods or field offsets. Thanks for taking the time to do the writeup! |
Indeed. Thanks, Andy! |
Resolved -> Closed. |
Attachment: Download
Additional Detail from JIRA
md5: 347473c6e30dd29ed2a52565f931a4d5
Issue Description:
Ahead of ABI Stability, decide if vtables are ABI and lock it down if so.
Invoking a non-final instance method involves calling a function that is not known at compile time: it must be resolved at run time. This is solved through the use of a vtable, or virtual method table (so called because overridable methods are also known as "virtual" methods). A vtable is a table of function pointers to a class or subclass's implementation of overridable methods. If the vtable is determined to be part of ABI, it needs a layout algorithm that also provides flexibility for library evolution.
Alternatively, we may decide to perform inter-module calls through opaque thunks, or compiler-created intermediary functions, which then perform either direct or vtable dispatch as needed. This enables greater library evolution without breaking binary compatibility by allowing internal class hierarchies to change. This would also unify non-final method dispatch between open and non-open classes while still allowing for aggressive compiler optimizations like de-virtualization for non-open classes. This approach would make vtables not be ABI, as that part of the type metadata would effectively be opaque to another module.
The text was updated successfully, but these errors were encountered: