Emit the vtables and vtable setup functions for a class. This includes both the primary vtable and any trait implementation vtables. The trait vtables go before the main vtable, and have the following layout: { CPyType_T1, // pointer to type object C_
(
base: ClassIR, vtable_setup_name: str, vtable_name: str, emitter: Emitter, shadow: bool
)
| 469 | |
| 470 | |
| 471 | def generate_vtables( |
| 472 | base: ClassIR, vtable_setup_name: str, vtable_name: str, emitter: Emitter, shadow: bool |
| 473 | ) -> str: |
| 474 | """Emit the vtables and vtable setup functions for a class. |
| 475 | |
| 476 | This includes both the primary vtable and any trait implementation vtables. |
| 477 | The trait vtables go before the main vtable, and have the following layout: |
| 478 | { |
| 479 | CPyType_T1, // pointer to type object |
| 480 | C_T1_trait_vtable, // pointer to array of method pointers |
| 481 | C_T1_offset_table, // pointer to array of attribute offsets |
| 482 | CPyType_T2, |
| 483 | C_T2_trait_vtable, |
| 484 | C_T2_offset_table, |
| 485 | ... |
| 486 | } |
| 487 | The method implementations are calculated at the end of IR pass, attribute |
| 488 | offsets are {offsetof(native__C, _x1), offsetof(native__C, _y1), ...}. |
| 489 | |
| 490 | To account for both dynamic loading and dynamic class creation, |
| 491 | vtables are populated dynamically at class creation time, so we |
| 492 | emit empty array definitions to store the vtables and a function to |
| 493 | populate them. |
| 494 | |
| 495 | If shadow is True, generate "shadow vtables" that point to the |
| 496 | shadow glue methods (which should dispatch via the Python C-API). |
| 497 | |
| 498 | Returns the expression to use to refer to the vtable, which might be |
| 499 | different than the name, if there are trait vtables. |
| 500 | """ |
| 501 | |
| 502 | def trait_vtable_name(trait: ClassIR) -> str: |
| 503 | return "{}_{}_trait_vtable{}".format( |
| 504 | base.name_prefix(emitter.names), |
| 505 | trait.name_prefix(emitter.names), |
| 506 | "_shadow" if shadow else "", |
| 507 | ) |
| 508 | |
| 509 | def trait_offset_table_name(trait: ClassIR) -> str: |
| 510 | return "{}_{}_offset_table".format( |
| 511 | base.name_prefix(emitter.names), trait.name_prefix(emitter.names) |
| 512 | ) |
| 513 | |
| 514 | # Emit array definitions with enough space for all the entries |
| 515 | emitter.emit_line( |
| 516 | "static CPyVTableItem {}[{}];".format( |
| 517 | vtable_name, max(1, len(base.vtable_entries) + 3 * len(base.trait_vtables)) |
| 518 | ) |
| 519 | ) |
| 520 | |
| 521 | for trait, vtable in base.trait_vtables.items(): |
| 522 | # Trait methods entry (vtable index -> method implementation). |
| 523 | emitter.emit_line( |
| 524 | f"static CPyVTableItem {trait_vtable_name(trait)}[{max(1, len(vtable))}];" |
| 525 | ) |
| 526 | # Trait attributes entry (attribute number in trait -> offset in actual struct). |
| 527 | emitter.emit_line( |
| 528 | "static size_t {}[{}];".format( |
no test coverage detected
searching dependent graphs…