Generate a native function that allocates an instance of a class.
(
cl: ClassIR,
defaults_fn: FuncIR | None,
vtable_name: str,
shadow_vtable_name: str | None,
emitter: Emitter,
)
| 606 | |
| 607 | |
| 608 | def generate_setup_for_class( |
| 609 | cl: ClassIR, |
| 610 | defaults_fn: FuncIR | None, |
| 611 | vtable_name: str, |
| 612 | shadow_vtable_name: str | None, |
| 613 | emitter: Emitter, |
| 614 | ) -> None: |
| 615 | """Generate a native function that allocates an instance of a class.""" |
| 616 | emitter.emit_line(native_function_header(cl.setup, emitter)) |
| 617 | emitter.emit_line("{") |
| 618 | type_arg_name = REG_PREFIX + cl.setup.sig.args[0].name |
| 619 | emitter.emit_line(f"PyTypeObject *type = (PyTypeObject*){type_arg_name};") |
| 620 | struct_name = cl.struct_name(emitter.names) |
| 621 | emitter.emit_line(f"{struct_name} *self;") |
| 622 | |
| 623 | prefix = cl.name_prefix(emitter.names) |
| 624 | if cl.reuse_freed_instance: |
| 625 | # Attempt to use a per-type free list first (a free "list" with up to one object only). |
| 626 | emitter.emit_line(f"if ({prefix}_free_instance != NULL) {{") |
| 627 | emitter.emit_line(f"self = {prefix}_free_instance;") |
| 628 | emitter.emit_line(f"{prefix}_free_instance = NULL;") |
| 629 | emitter.emit_line("Py_SET_REFCNT(self, 1);") |
| 630 | if not cl.is_acyclic: |
| 631 | emitter.emit_line("PyObject_GC_Track(self);") |
| 632 | if defaults_fn is not None: |
| 633 | emit_attr_defaults_func_call(defaults_fn, "self", emitter) |
| 634 | emitter.emit_line("return (PyObject *)self;") |
| 635 | emitter.emit_line("}") |
| 636 | |
| 637 | emitter.emit_line(f"self = ({cl.struct_name(emitter.names)} *)type->tp_alloc(type, 0);") |
| 638 | emitter.emit_line("if (self == NULL)") |
| 639 | emitter.emit_line(" return NULL;") |
| 640 | |
| 641 | if shadow_vtable_name: |
| 642 | emitter.emit_line(f"if (type != {emitter.type_struct_name(cl)}) {{") |
| 643 | emitter.emit_line(f"self->vtable = {shadow_vtable_name};") |
| 644 | emitter.emit_line("} else {") |
| 645 | emitter.emit_line(f"self->vtable = {vtable_name};") |
| 646 | emitter.emit_line("}") |
| 647 | else: |
| 648 | emitter.emit_line(f"self->vtable = {vtable_name};") |
| 649 | |
| 650 | emit_clear_bitmaps(cl, emitter) |
| 651 | |
| 652 | if cl.has_method("__call__"): |
| 653 | name = cl.method_decl("__call__").cname(emitter.names) |
| 654 | emitter.emit_line(f"self->vectorcall = {PREFIX}{name};") |
| 655 | |
| 656 | for base in reversed(cl.base_mro): |
| 657 | for attr, rtype in base.attributes.items(): |
| 658 | value = emitter.c_undefined_value(rtype) |
| 659 | |
| 660 | # We don't need to set this field to NULL since tp_alloc() already |
| 661 | # zero-initializes `self`. |
| 662 | if value != "NULL": |
| 663 | emitter.set_undefined_value(f"self->{emitter.attr(attr)}", rtype) |
| 664 | |
| 665 | # Initialize attributes to default values, if necessary |
no test coverage detected
searching dependent graphs…