emitclass.py 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061
  1. """Code generation for native classes and related wrappers."""
  2. from __future__ import annotations
  3. from typing import Callable, Mapping, Tuple
  4. from mypyc.codegen.emit import Emitter, HeaderDeclaration, ReturnHandler
  5. from mypyc.codegen.emitfunc import native_function_header
  6. from mypyc.codegen.emitwrapper import (
  7. generate_bin_op_wrapper,
  8. generate_bool_wrapper,
  9. generate_contains_wrapper,
  10. generate_dunder_wrapper,
  11. generate_get_wrapper,
  12. generate_hash_wrapper,
  13. generate_ipow_wrapper,
  14. generate_len_wrapper,
  15. generate_richcompare_wrapper,
  16. generate_set_del_item_wrapper,
  17. )
  18. from mypyc.common import BITMAP_BITS, BITMAP_TYPE, NATIVE_PREFIX, PREFIX, REG_PREFIX, use_fastcall
  19. from mypyc.ir.class_ir import ClassIR, VTableEntries
  20. from mypyc.ir.func_ir import FUNC_CLASSMETHOD, FUNC_STATICMETHOD, FuncDecl, FuncIR
  21. from mypyc.ir.rtypes import RTuple, RType, object_rprimitive
  22. from mypyc.namegen import NameGenerator
  23. from mypyc.sametype import is_same_type
  24. def native_slot(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str:
  25. return f"{NATIVE_PREFIX}{fn.cname(emitter.names)}"
  26. def wrapper_slot(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str:
  27. return f"{PREFIX}{fn.cname(emitter.names)}"
  28. # We maintain a table from dunder function names to struct slots they
  29. # correspond to and functions that generate a wrapper (if necessary)
  30. # and return the function name to stick in the slot.
  31. # TODO: Add remaining dunder methods
  32. SlotGenerator = Callable[[ClassIR, FuncIR, Emitter], str]
  33. SlotTable = Mapping[str, Tuple[str, SlotGenerator]]
  34. SLOT_DEFS: SlotTable = {
  35. "__init__": ("tp_init", lambda c, t, e: generate_init_for_class(c, t, e)),
  36. "__call__": ("tp_call", lambda c, t, e: generate_call_wrapper(c, t, e)),
  37. "__str__": ("tp_str", native_slot),
  38. "__repr__": ("tp_repr", native_slot),
  39. "__next__": ("tp_iternext", native_slot),
  40. "__iter__": ("tp_iter", native_slot),
  41. "__hash__": ("tp_hash", generate_hash_wrapper),
  42. "__get__": ("tp_descr_get", generate_get_wrapper),
  43. }
  44. AS_MAPPING_SLOT_DEFS: SlotTable = {
  45. "__getitem__": ("mp_subscript", generate_dunder_wrapper),
  46. "__setitem__": ("mp_ass_subscript", generate_set_del_item_wrapper),
  47. "__delitem__": ("mp_ass_subscript", generate_set_del_item_wrapper),
  48. "__len__": ("mp_length", generate_len_wrapper),
  49. }
  50. AS_SEQUENCE_SLOT_DEFS: SlotTable = {"__contains__": ("sq_contains", generate_contains_wrapper)}
  51. AS_NUMBER_SLOT_DEFS: SlotTable = {
  52. # Unary operations.
  53. "__bool__": ("nb_bool", generate_bool_wrapper),
  54. "__int__": ("nb_int", generate_dunder_wrapper),
  55. "__float__": ("nb_float", generate_dunder_wrapper),
  56. "__neg__": ("nb_negative", generate_dunder_wrapper),
  57. "__pos__": ("nb_positive", generate_dunder_wrapper),
  58. "__abs__": ("nb_absolute", generate_dunder_wrapper),
  59. "__invert__": ("nb_invert", generate_dunder_wrapper),
  60. # Binary operations.
  61. "__add__": ("nb_add", generate_bin_op_wrapper),
  62. "__radd__": ("nb_add", generate_bin_op_wrapper),
  63. "__sub__": ("nb_subtract", generate_bin_op_wrapper),
  64. "__rsub__": ("nb_subtract", generate_bin_op_wrapper),
  65. "__mul__": ("nb_multiply", generate_bin_op_wrapper),
  66. "__rmul__": ("nb_multiply", generate_bin_op_wrapper),
  67. "__mod__": ("nb_remainder", generate_bin_op_wrapper),
  68. "__rmod__": ("nb_remainder", generate_bin_op_wrapper),
  69. "__truediv__": ("nb_true_divide", generate_bin_op_wrapper),
  70. "__rtruediv__": ("nb_true_divide", generate_bin_op_wrapper),
  71. "__floordiv__": ("nb_floor_divide", generate_bin_op_wrapper),
  72. "__rfloordiv__": ("nb_floor_divide", generate_bin_op_wrapper),
  73. "__divmod__": ("nb_divmod", generate_bin_op_wrapper),
  74. "__rdivmod__": ("nb_divmod", generate_bin_op_wrapper),
  75. "__lshift__": ("nb_lshift", generate_bin_op_wrapper),
  76. "__rlshift__": ("nb_lshift", generate_bin_op_wrapper),
  77. "__rshift__": ("nb_rshift", generate_bin_op_wrapper),
  78. "__rrshift__": ("nb_rshift", generate_bin_op_wrapper),
  79. "__and__": ("nb_and", generate_bin_op_wrapper),
  80. "__rand__": ("nb_and", generate_bin_op_wrapper),
  81. "__or__": ("nb_or", generate_bin_op_wrapper),
  82. "__ror__": ("nb_or", generate_bin_op_wrapper),
  83. "__xor__": ("nb_xor", generate_bin_op_wrapper),
  84. "__rxor__": ("nb_xor", generate_bin_op_wrapper),
  85. "__matmul__": ("nb_matrix_multiply", generate_bin_op_wrapper),
  86. "__rmatmul__": ("nb_matrix_multiply", generate_bin_op_wrapper),
  87. # In-place binary operations.
  88. "__iadd__": ("nb_inplace_add", generate_dunder_wrapper),
  89. "__isub__": ("nb_inplace_subtract", generate_dunder_wrapper),
  90. "__imul__": ("nb_inplace_multiply", generate_dunder_wrapper),
  91. "__imod__": ("nb_inplace_remainder", generate_dunder_wrapper),
  92. "__itruediv__": ("nb_inplace_true_divide", generate_dunder_wrapper),
  93. "__ifloordiv__": ("nb_inplace_floor_divide", generate_dunder_wrapper),
  94. "__ilshift__": ("nb_inplace_lshift", generate_dunder_wrapper),
  95. "__irshift__": ("nb_inplace_rshift", generate_dunder_wrapper),
  96. "__iand__": ("nb_inplace_and", generate_dunder_wrapper),
  97. "__ior__": ("nb_inplace_or", generate_dunder_wrapper),
  98. "__ixor__": ("nb_inplace_xor", generate_dunder_wrapper),
  99. "__imatmul__": ("nb_inplace_matrix_multiply", generate_dunder_wrapper),
  100. # Ternary operations. (yes, really)
  101. # These are special cased in generate_bin_op_wrapper().
  102. "__pow__": ("nb_power", generate_bin_op_wrapper),
  103. "__rpow__": ("nb_power", generate_bin_op_wrapper),
  104. "__ipow__": ("nb_inplace_power", generate_ipow_wrapper),
  105. }
  106. AS_ASYNC_SLOT_DEFS: SlotTable = {
  107. "__await__": ("am_await", native_slot),
  108. "__aiter__": ("am_aiter", native_slot),
  109. "__anext__": ("am_anext", native_slot),
  110. }
  111. SIDE_TABLES = [
  112. ("as_mapping", "PyMappingMethods", AS_MAPPING_SLOT_DEFS),
  113. ("as_sequence", "PySequenceMethods", AS_SEQUENCE_SLOT_DEFS),
  114. ("as_number", "PyNumberMethods", AS_NUMBER_SLOT_DEFS),
  115. ("as_async", "PyAsyncMethods", AS_ASYNC_SLOT_DEFS),
  116. ]
  117. # Slots that need to always be filled in because they don't get
  118. # inherited right.
  119. ALWAYS_FILL = {"__hash__"}
  120. def generate_call_wrapper(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str:
  121. if emitter.use_vectorcall():
  122. # Use vectorcall wrapper if supported (PEP 590).
  123. return "PyVectorcall_Call"
  124. else:
  125. # On older Pythons use the legacy wrapper.
  126. return wrapper_slot(cl, fn, emitter)
  127. def slot_key(attr: str) -> str:
  128. """Map dunder method name to sort key.
  129. Sort reverse operator methods and __delitem__ after others ('x' > '_').
  130. """
  131. if (attr.startswith("__r") and attr != "__rshift__") or attr == "__delitem__":
  132. return "x" + attr
  133. return attr
  134. def generate_slots(cl: ClassIR, table: SlotTable, emitter: Emitter) -> dict[str, str]:
  135. fields: dict[str, str] = {}
  136. generated: dict[str, str] = {}
  137. # Sort for determinism on Python 3.5
  138. for name, (slot, generator) in sorted(table.items(), key=lambda x: slot_key(x[0])):
  139. method_cls = cl.get_method_and_class(name)
  140. if method_cls and (method_cls[1] == cl or name in ALWAYS_FILL):
  141. if slot in generated:
  142. # Reuse previously generated wrapper.
  143. fields[slot] = generated[slot]
  144. else:
  145. # Generate new wrapper.
  146. name = generator(cl, method_cls[0], emitter)
  147. fields[slot] = name
  148. generated[slot] = name
  149. return fields
  150. def generate_class_type_decl(
  151. cl: ClassIR, c_emitter: Emitter, external_emitter: Emitter, emitter: Emitter
  152. ) -> None:
  153. context = c_emitter.context
  154. name = emitter.type_struct_name(cl)
  155. context.declarations[name] = HeaderDeclaration(
  156. f"PyTypeObject *{emitter.type_struct_name(cl)};", needs_export=True
  157. )
  158. # If this is a non-extension class, all we want is the type object decl.
  159. if not cl.is_ext_class:
  160. return
  161. generate_object_struct(cl, external_emitter)
  162. generate_full = not cl.is_trait and not cl.builtin_base
  163. if generate_full:
  164. context.declarations[emitter.native_function_name(cl.ctor)] = HeaderDeclaration(
  165. f"{native_function_header(cl.ctor, emitter)};", needs_export=True
  166. )
  167. def generate_class(cl: ClassIR, module: str, emitter: Emitter) -> None:
  168. """Generate C code for a class.
  169. This is the main entry point to the module.
  170. """
  171. name = cl.name
  172. name_prefix = cl.name_prefix(emitter.names)
  173. setup_name = f"{name_prefix}_setup"
  174. new_name = f"{name_prefix}_new"
  175. members_name = f"{name_prefix}_members"
  176. getseters_name = f"{name_prefix}_getseters"
  177. vtable_name = f"{name_prefix}_vtable"
  178. traverse_name = f"{name_prefix}_traverse"
  179. clear_name = f"{name_prefix}_clear"
  180. dealloc_name = f"{name_prefix}_dealloc"
  181. methods_name = f"{name_prefix}_methods"
  182. vtable_setup_name = f"{name_prefix}_trait_vtable_setup"
  183. fields: dict[str, str] = {}
  184. fields["tp_name"] = f'"{name}"'
  185. generate_full = not cl.is_trait and not cl.builtin_base
  186. needs_getseters = cl.needs_getseters or not cl.is_generated
  187. if not cl.builtin_base:
  188. fields["tp_new"] = new_name
  189. if generate_full:
  190. fields["tp_dealloc"] = f"(destructor){name_prefix}_dealloc"
  191. fields["tp_traverse"] = f"(traverseproc){name_prefix}_traverse"
  192. fields["tp_clear"] = f"(inquiry){name_prefix}_clear"
  193. if needs_getseters:
  194. fields["tp_getset"] = getseters_name
  195. fields["tp_methods"] = methods_name
  196. def emit_line() -> None:
  197. emitter.emit_line()
  198. emit_line()
  199. # If the class has a method to initialize default attribute
  200. # values, we need to call it during initialization.
  201. defaults_fn = cl.get_method("__mypyc_defaults_setup")
  202. # If there is a __init__ method, we'll use it in the native constructor.
  203. init_fn = cl.get_method("__init__")
  204. # Fill out slots in the type object from dunder methods.
  205. fields.update(generate_slots(cl, SLOT_DEFS, emitter))
  206. # Fill out dunder methods that live in tables hanging off the side.
  207. for table_name, type, slot_defs in SIDE_TABLES:
  208. slots = generate_slots(cl, slot_defs, emitter)
  209. if slots:
  210. table_struct_name = generate_side_table_for_class(cl, table_name, type, slots, emitter)
  211. fields[f"tp_{table_name}"] = f"&{table_struct_name}"
  212. richcompare_name = generate_richcompare_wrapper(cl, emitter)
  213. if richcompare_name:
  214. fields["tp_richcompare"] = richcompare_name
  215. # If the class inherits from python, make space for a __dict__
  216. struct_name = cl.struct_name(emitter.names)
  217. if cl.builtin_base:
  218. base_size = f"sizeof({cl.builtin_base})"
  219. elif cl.is_trait:
  220. base_size = "sizeof(PyObject)"
  221. else:
  222. base_size = f"sizeof({struct_name})"
  223. # Since our types aren't allocated using type() we need to
  224. # populate these fields ourselves if we want them to have correct
  225. # values. PyType_Ready will inherit the offsets from tp_base but
  226. # that isn't what we want.
  227. # XXX: there is no reason for the __weakref__ stuff to be mixed up with __dict__
  228. if cl.has_dict and not has_managed_dict(cl, emitter):
  229. # __dict__ lives right after the struct and __weakref__ lives right after that
  230. # TODO: They should get members in the struct instead of doing this nonsense.
  231. weak_offset = f"{base_size} + sizeof(PyObject *)"
  232. emitter.emit_lines(
  233. f"PyMemberDef {members_name}[] = {{",
  234. f'{{"__dict__", T_OBJECT_EX, {base_size}, 0, NULL}},',
  235. f'{{"__weakref__", T_OBJECT_EX, {weak_offset}, 0, NULL}},',
  236. "{0}",
  237. "};",
  238. )
  239. fields["tp_members"] = members_name
  240. fields["tp_basicsize"] = f"{base_size} + 2*sizeof(PyObject *)"
  241. if emitter.capi_version < (3, 12):
  242. fields["tp_dictoffset"] = base_size
  243. fields["tp_weaklistoffset"] = weak_offset
  244. else:
  245. fields["tp_basicsize"] = base_size
  246. if generate_full:
  247. # Declare setup method that allocates and initializes an object. type is the
  248. # type of the class being initialized, which could be another class if there
  249. # is an interpreted subclass.
  250. emitter.emit_line(f"static PyObject *{setup_name}(PyTypeObject *type);")
  251. assert cl.ctor is not None
  252. emitter.emit_line(native_function_header(cl.ctor, emitter) + ";")
  253. emit_line()
  254. init_fn = cl.get_method("__init__")
  255. generate_new_for_class(cl, new_name, vtable_name, setup_name, init_fn, emitter)
  256. emit_line()
  257. generate_traverse_for_class(cl, traverse_name, emitter)
  258. emit_line()
  259. generate_clear_for_class(cl, clear_name, emitter)
  260. emit_line()
  261. generate_dealloc_for_class(cl, dealloc_name, clear_name, emitter)
  262. emit_line()
  263. if cl.allow_interpreted_subclasses:
  264. shadow_vtable_name: str | None = generate_vtables(
  265. cl, vtable_setup_name + "_shadow", vtable_name + "_shadow", emitter, shadow=True
  266. )
  267. emit_line()
  268. else:
  269. shadow_vtable_name = None
  270. vtable_name = generate_vtables(cl, vtable_setup_name, vtable_name, emitter, shadow=False)
  271. emit_line()
  272. if needs_getseters:
  273. generate_getseter_declarations(cl, emitter)
  274. emit_line()
  275. generate_getseters_table(cl, getseters_name, emitter)
  276. emit_line()
  277. if cl.is_trait:
  278. generate_new_for_trait(cl, new_name, emitter)
  279. generate_methods_table(cl, methods_name, emitter)
  280. emit_line()
  281. flags = ["Py_TPFLAGS_DEFAULT", "Py_TPFLAGS_HEAPTYPE", "Py_TPFLAGS_BASETYPE"]
  282. if generate_full:
  283. flags.append("Py_TPFLAGS_HAVE_GC")
  284. if cl.has_method("__call__") and emitter.use_vectorcall():
  285. fields["tp_vectorcall_offset"] = "offsetof({}, vectorcall)".format(
  286. cl.struct_name(emitter.names)
  287. )
  288. flags.append("_Py_TPFLAGS_HAVE_VECTORCALL")
  289. if not fields.get("tp_vectorcall"):
  290. # This is just a placeholder to please CPython. It will be
  291. # overridden during setup.
  292. fields["tp_call"] = "PyVectorcall_Call"
  293. if has_managed_dict(cl, emitter):
  294. flags.append("Py_TPFLAGS_MANAGED_DICT")
  295. fields["tp_flags"] = " | ".join(flags)
  296. emitter.emit_line(f"static PyTypeObject {emitter.type_struct_name(cl)}_template_ = {{")
  297. emitter.emit_line("PyVarObject_HEAD_INIT(NULL, 0)")
  298. for field, value in fields.items():
  299. emitter.emit_line(f".{field} = {value},")
  300. emitter.emit_line("};")
  301. emitter.emit_line(
  302. "static PyTypeObject *{t}_template = &{t}_template_;".format(
  303. t=emitter.type_struct_name(cl)
  304. )
  305. )
  306. emitter.emit_line()
  307. if generate_full:
  308. generate_setup_for_class(
  309. cl, setup_name, defaults_fn, vtable_name, shadow_vtable_name, emitter
  310. )
  311. emitter.emit_line()
  312. generate_constructor_for_class(cl, cl.ctor, init_fn, setup_name, vtable_name, emitter)
  313. emitter.emit_line()
  314. if needs_getseters:
  315. generate_getseters(cl, emitter)
  316. def getter_name(cl: ClassIR, attribute: str, names: NameGenerator) -> str:
  317. return names.private_name(cl.module_name, f"{cl.name}_get_{attribute}")
  318. def setter_name(cl: ClassIR, attribute: str, names: NameGenerator) -> str:
  319. return names.private_name(cl.module_name, f"{cl.name}_set_{attribute}")
  320. def generate_object_struct(cl: ClassIR, emitter: Emitter) -> None:
  321. seen_attrs: set[tuple[str, RType]] = set()
  322. lines: list[str] = []
  323. lines += ["typedef struct {", "PyObject_HEAD", "CPyVTableItem *vtable;"]
  324. if cl.has_method("__call__") and emitter.use_vectorcall():
  325. lines.append("vectorcallfunc vectorcall;")
  326. bitmap_attrs = []
  327. for base in reversed(cl.base_mro):
  328. if not base.is_trait:
  329. if base.bitmap_attrs:
  330. # Do we need another attribute bitmap field?
  331. if emitter.bitmap_field(len(base.bitmap_attrs) - 1) not in bitmap_attrs:
  332. for i in range(0, len(base.bitmap_attrs), BITMAP_BITS):
  333. attr = emitter.bitmap_field(i)
  334. if attr not in bitmap_attrs:
  335. lines.append(f"{BITMAP_TYPE} {attr};")
  336. bitmap_attrs.append(attr)
  337. for attr, rtype in base.attributes.items():
  338. if (attr, rtype) not in seen_attrs:
  339. lines.append(f"{emitter.ctype_spaced(rtype)}{emitter.attr(attr)};")
  340. seen_attrs.add((attr, rtype))
  341. if isinstance(rtype, RTuple):
  342. emitter.declare_tuple_struct(rtype)
  343. lines.append(f"}} {cl.struct_name(emitter.names)};")
  344. lines.append("")
  345. emitter.context.declarations[cl.struct_name(emitter.names)] = HeaderDeclaration(
  346. lines, is_type=True
  347. )
  348. def generate_vtables(
  349. base: ClassIR, vtable_setup_name: str, vtable_name: str, emitter: Emitter, shadow: bool
  350. ) -> str:
  351. """Emit the vtables and vtable setup functions for a class.
  352. This includes both the primary vtable and any trait implementation vtables.
  353. The trait vtables go before the main vtable, and have the following layout:
  354. {
  355. CPyType_T1, // pointer to type object
  356. C_T1_trait_vtable, // pointer to array of method pointers
  357. C_T1_offset_table, // pointer to array of attribute offsets
  358. CPyType_T2,
  359. C_T2_trait_vtable,
  360. C_T2_offset_table,
  361. ...
  362. }
  363. The method implementations are calculated at the end of IR pass, attribute
  364. offsets are {offsetof(native__C, _x1), offsetof(native__C, _y1), ...}.
  365. To account for both dynamic loading and dynamic class creation,
  366. vtables are populated dynamically at class creation time, so we
  367. emit empty array definitions to store the vtables and a function to
  368. populate them.
  369. If shadow is True, generate "shadow vtables" that point to the
  370. shadow glue methods (which should dispatch via the Python C-API).
  371. Returns the expression to use to refer to the vtable, which might be
  372. different than the name, if there are trait vtables.
  373. """
  374. def trait_vtable_name(trait: ClassIR) -> str:
  375. return "{}_{}_trait_vtable{}".format(
  376. base.name_prefix(emitter.names),
  377. trait.name_prefix(emitter.names),
  378. "_shadow" if shadow else "",
  379. )
  380. def trait_offset_table_name(trait: ClassIR) -> str:
  381. return "{}_{}_offset_table".format(
  382. base.name_prefix(emitter.names), trait.name_prefix(emitter.names)
  383. )
  384. # Emit array definitions with enough space for all the entries
  385. emitter.emit_line(
  386. "static CPyVTableItem {}[{}];".format(
  387. vtable_name, max(1, len(base.vtable_entries) + 3 * len(base.trait_vtables))
  388. )
  389. )
  390. for trait, vtable in base.trait_vtables.items():
  391. # Trait methods entry (vtable index -> method implementation).
  392. emitter.emit_line(
  393. f"static CPyVTableItem {trait_vtable_name(trait)}[{max(1, len(vtable))}];"
  394. )
  395. # Trait attributes entry (attribute number in trait -> offset in actual struct).
  396. emitter.emit_line(
  397. "static size_t {}[{}];".format(
  398. trait_offset_table_name(trait), max(1, len(trait.attributes))
  399. )
  400. )
  401. # Emit vtable setup function
  402. emitter.emit_line("static bool")
  403. emitter.emit_line(f"{NATIVE_PREFIX}{vtable_setup_name}(void)")
  404. emitter.emit_line("{")
  405. if base.allow_interpreted_subclasses and not shadow:
  406. emitter.emit_line(f"{NATIVE_PREFIX}{vtable_setup_name}_shadow();")
  407. subtables = []
  408. for trait, vtable in base.trait_vtables.items():
  409. name = trait_vtable_name(trait)
  410. offset_name = trait_offset_table_name(trait)
  411. generate_vtable(vtable, name, emitter, [], shadow)
  412. generate_offset_table(offset_name, emitter, trait, base)
  413. subtables.append((trait, name, offset_name))
  414. generate_vtable(base.vtable_entries, vtable_name, emitter, subtables, shadow)
  415. emitter.emit_line("return 1;")
  416. emitter.emit_line("}")
  417. return vtable_name if not subtables else f"{vtable_name} + {len(subtables) * 3}"
  418. def generate_offset_table(
  419. trait_offset_table_name: str, emitter: Emitter, trait: ClassIR, cl: ClassIR
  420. ) -> None:
  421. """Generate attribute offset row of a trait vtable."""
  422. emitter.emit_line(f"size_t {trait_offset_table_name}_scratch[] = {{")
  423. for attr in trait.attributes:
  424. emitter.emit_line(f"offsetof({cl.struct_name(emitter.names)}, {emitter.attr(attr)}),")
  425. if not trait.attributes:
  426. # This is for msvc.
  427. emitter.emit_line("0")
  428. emitter.emit_line("};")
  429. emitter.emit_line(
  430. "memcpy({name}, {name}_scratch, sizeof({name}));".format(name=trait_offset_table_name)
  431. )
  432. def generate_vtable(
  433. entries: VTableEntries,
  434. vtable_name: str,
  435. emitter: Emitter,
  436. subtables: list[tuple[ClassIR, str, str]],
  437. shadow: bool,
  438. ) -> None:
  439. emitter.emit_line(f"CPyVTableItem {vtable_name}_scratch[] = {{")
  440. if subtables:
  441. emitter.emit_line("/* Array of trait vtables */")
  442. for trait, table, offset_table in subtables:
  443. emitter.emit_line(
  444. "(CPyVTableItem){}, (CPyVTableItem){}, (CPyVTableItem){},".format(
  445. emitter.type_struct_name(trait), table, offset_table
  446. )
  447. )
  448. emitter.emit_line("/* Start of real vtable */")
  449. for entry in entries:
  450. method = entry.shadow_method if shadow and entry.shadow_method else entry.method
  451. emitter.emit_line(
  452. "(CPyVTableItem){}{}{},".format(
  453. emitter.get_group_prefix(entry.method.decl),
  454. NATIVE_PREFIX,
  455. method.cname(emitter.names),
  456. )
  457. )
  458. # msvc doesn't allow empty arrays; maybe allowing them at all is an extension?
  459. if not entries:
  460. emitter.emit_line("NULL")
  461. emitter.emit_line("};")
  462. emitter.emit_line("memcpy({name}, {name}_scratch, sizeof({name}));".format(name=vtable_name))
  463. def generate_setup_for_class(
  464. cl: ClassIR,
  465. func_name: str,
  466. defaults_fn: FuncIR | None,
  467. vtable_name: str,
  468. shadow_vtable_name: str | None,
  469. emitter: Emitter,
  470. ) -> None:
  471. """Generate a native function that allocates an instance of a class."""
  472. emitter.emit_line("static PyObject *")
  473. emitter.emit_line(f"{func_name}(PyTypeObject *type)")
  474. emitter.emit_line("{")
  475. emitter.emit_line(f"{cl.struct_name(emitter.names)} *self;")
  476. emitter.emit_line(f"self = ({cl.struct_name(emitter.names)} *)type->tp_alloc(type, 0);")
  477. emitter.emit_line("if (self == NULL)")
  478. emitter.emit_line(" return NULL;")
  479. if shadow_vtable_name:
  480. emitter.emit_line(f"if (type != {emitter.type_struct_name(cl)}) {{")
  481. emitter.emit_line(f"self->vtable = {shadow_vtable_name};")
  482. emitter.emit_line("} else {")
  483. emitter.emit_line(f"self->vtable = {vtable_name};")
  484. emitter.emit_line("}")
  485. else:
  486. emitter.emit_line(f"self->vtable = {vtable_name};")
  487. for i in range(0, len(cl.bitmap_attrs), BITMAP_BITS):
  488. field = emitter.bitmap_field(i)
  489. emitter.emit_line(f"self->{field} = 0;")
  490. if cl.has_method("__call__") and emitter.use_vectorcall():
  491. name = cl.method_decl("__call__").cname(emitter.names)
  492. emitter.emit_line(f"self->vectorcall = {PREFIX}{name};")
  493. for base in reversed(cl.base_mro):
  494. for attr, rtype in base.attributes.items():
  495. value = emitter.c_undefined_value(rtype)
  496. # We don't need to set this field to NULL since tp_alloc() already
  497. # zero-initializes `self`.
  498. if value != "NULL":
  499. emitter.emit_line(rf"self->{emitter.attr(attr)} = {value};")
  500. # Initialize attributes to default values, if necessary
  501. if defaults_fn is not None:
  502. emitter.emit_lines(
  503. "if ({}{}((PyObject *)self) == 0) {{".format(
  504. NATIVE_PREFIX, defaults_fn.cname(emitter.names)
  505. ),
  506. "Py_DECREF(self);",
  507. "return NULL;",
  508. "}",
  509. )
  510. emitter.emit_line("return (PyObject *)self;")
  511. emitter.emit_line("}")
  512. def generate_constructor_for_class(
  513. cl: ClassIR,
  514. fn: FuncDecl,
  515. init_fn: FuncIR | None,
  516. setup_name: str,
  517. vtable_name: str,
  518. emitter: Emitter,
  519. ) -> None:
  520. """Generate a native function that allocates and initializes an instance of a class."""
  521. emitter.emit_line(f"{native_function_header(fn, emitter)}")
  522. emitter.emit_line("{")
  523. emitter.emit_line(f"PyObject *self = {setup_name}({emitter.type_struct_name(cl)});")
  524. emitter.emit_line("if (self == NULL)")
  525. emitter.emit_line(" return NULL;")
  526. args = ", ".join(["self"] + [REG_PREFIX + arg.name for arg in fn.sig.args])
  527. if init_fn is not None:
  528. emitter.emit_line(
  529. "char res = {}{}{}({});".format(
  530. emitter.get_group_prefix(init_fn.decl),
  531. NATIVE_PREFIX,
  532. init_fn.cname(emitter.names),
  533. args,
  534. )
  535. )
  536. emitter.emit_line("if (res == 2) {")
  537. emitter.emit_line("Py_DECREF(self);")
  538. emitter.emit_line("return NULL;")
  539. emitter.emit_line("}")
  540. # If there is a nontrivial ctor that we didn't define, invoke it via tp_init
  541. elif len(fn.sig.args) > 1:
  542. emitter.emit_line(f"int res = {emitter.type_struct_name(cl)}->tp_init({args});")
  543. emitter.emit_line("if (res < 0) {")
  544. emitter.emit_line("Py_DECREF(self);")
  545. emitter.emit_line("return NULL;")
  546. emitter.emit_line("}")
  547. emitter.emit_line("return self;")
  548. emitter.emit_line("}")
  549. def generate_init_for_class(cl: ClassIR, init_fn: FuncIR, emitter: Emitter) -> str:
  550. """Generate an init function suitable for use as tp_init.
  551. tp_init needs to be a function that returns an int, and our
  552. __init__ methods return a PyObject. Translate NULL to -1,
  553. everything else to 0.
  554. """
  555. func_name = f"{cl.name_prefix(emitter.names)}_init"
  556. emitter.emit_line("static int")
  557. emitter.emit_line(f"{func_name}(PyObject *self, PyObject *args, PyObject *kwds)")
  558. emitter.emit_line("{")
  559. if cl.allow_interpreted_subclasses or cl.builtin_base:
  560. emitter.emit_line(
  561. "return {}{}(self, args, kwds) != NULL ? 0 : -1;".format(
  562. PREFIX, init_fn.cname(emitter.names)
  563. )
  564. )
  565. else:
  566. emitter.emit_line("return 0;")
  567. emitter.emit_line("}")
  568. return func_name
  569. def generate_new_for_class(
  570. cl: ClassIR,
  571. func_name: str,
  572. vtable_name: str,
  573. setup_name: str,
  574. init_fn: FuncIR | None,
  575. emitter: Emitter,
  576. ) -> None:
  577. emitter.emit_line("static PyObject *")
  578. emitter.emit_line(f"{func_name}(PyTypeObject *type, PyObject *args, PyObject *kwds)")
  579. emitter.emit_line("{")
  580. # TODO: Check and unbox arguments
  581. if not cl.allow_interpreted_subclasses:
  582. emitter.emit_line(f"if (type != {emitter.type_struct_name(cl)}) {{")
  583. emitter.emit_line(
  584. 'PyErr_SetString(PyExc_TypeError, "interpreted classes cannot inherit from compiled");'
  585. )
  586. emitter.emit_line("return NULL;")
  587. emitter.emit_line("}")
  588. if not init_fn or cl.allow_interpreted_subclasses or cl.builtin_base or cl.is_serializable():
  589. # Match Python semantics -- __new__ doesn't call __init__.
  590. emitter.emit_line(f"return {setup_name}(type);")
  591. else:
  592. # __new__ of a native class implicitly calls __init__ so that we
  593. # can enforce that instances are always properly initialized. This
  594. # is needed to support always defined attributes.
  595. emitter.emit_line(f"PyObject *self = {setup_name}(type);")
  596. emitter.emit_lines("if (self == NULL)", " return NULL;")
  597. emitter.emit_line(
  598. f"PyObject *ret = {PREFIX}{init_fn.cname(emitter.names)}(self, args, kwds);"
  599. )
  600. emitter.emit_lines("if (ret == NULL)", " return NULL;")
  601. emitter.emit_line("return self;")
  602. emitter.emit_line("}")
  603. def generate_new_for_trait(cl: ClassIR, func_name: str, emitter: Emitter) -> None:
  604. emitter.emit_line("static PyObject *")
  605. emitter.emit_line(f"{func_name}(PyTypeObject *type, PyObject *args, PyObject *kwds)")
  606. emitter.emit_line("{")
  607. emitter.emit_line(f"if (type != {emitter.type_struct_name(cl)}) {{")
  608. emitter.emit_line(
  609. "PyErr_SetString(PyExc_TypeError, "
  610. '"interpreted classes cannot inherit from compiled traits");'
  611. )
  612. emitter.emit_line("} else {")
  613. emitter.emit_line('PyErr_SetString(PyExc_TypeError, "traits may not be directly created");')
  614. emitter.emit_line("}")
  615. emitter.emit_line("return NULL;")
  616. emitter.emit_line("}")
  617. def generate_traverse_for_class(cl: ClassIR, func_name: str, emitter: Emitter) -> None:
  618. """Emit function that performs cycle GC traversal of an instance."""
  619. emitter.emit_line("static int")
  620. emitter.emit_line(
  621. f"{func_name}({cl.struct_name(emitter.names)} *self, visitproc visit, void *arg)"
  622. )
  623. emitter.emit_line("{")
  624. for base in reversed(cl.base_mro):
  625. for attr, rtype in base.attributes.items():
  626. emitter.emit_gc_visit(f"self->{emitter.attr(attr)}", rtype)
  627. if has_managed_dict(cl, emitter):
  628. emitter.emit_line("_PyObject_VisitManagedDict((PyObject *)self, visit, arg);")
  629. elif cl.has_dict:
  630. struct_name = cl.struct_name(emitter.names)
  631. # __dict__ lives right after the struct and __weakref__ lives right after that
  632. emitter.emit_gc_visit(
  633. f"*((PyObject **)((char *)self + sizeof({struct_name})))", object_rprimitive
  634. )
  635. emitter.emit_gc_visit(
  636. f"*((PyObject **)((char *)self + sizeof(PyObject *) + sizeof({struct_name})))",
  637. object_rprimitive,
  638. )
  639. emitter.emit_line("return 0;")
  640. emitter.emit_line("}")
  641. def generate_clear_for_class(cl: ClassIR, func_name: str, emitter: Emitter) -> None:
  642. emitter.emit_line("static int")
  643. emitter.emit_line(f"{func_name}({cl.struct_name(emitter.names)} *self)")
  644. emitter.emit_line("{")
  645. for base in reversed(cl.base_mro):
  646. for attr, rtype in base.attributes.items():
  647. emitter.emit_gc_clear(f"self->{emitter.attr(attr)}", rtype)
  648. if has_managed_dict(cl, emitter):
  649. emitter.emit_line("_PyObject_ClearManagedDict((PyObject *)self);")
  650. elif cl.has_dict:
  651. struct_name = cl.struct_name(emitter.names)
  652. # __dict__ lives right after the struct and __weakref__ lives right after that
  653. emitter.emit_gc_clear(
  654. f"*((PyObject **)((char *)self + sizeof({struct_name})))", object_rprimitive
  655. )
  656. emitter.emit_gc_clear(
  657. f"*((PyObject **)((char *)self + sizeof(PyObject *) + sizeof({struct_name})))",
  658. object_rprimitive,
  659. )
  660. emitter.emit_line("return 0;")
  661. emitter.emit_line("}")
  662. def generate_dealloc_for_class(
  663. cl: ClassIR, dealloc_func_name: str, clear_func_name: str, emitter: Emitter
  664. ) -> None:
  665. emitter.emit_line("static void")
  666. emitter.emit_line(f"{dealloc_func_name}({cl.struct_name(emitter.names)} *self)")
  667. emitter.emit_line("{")
  668. emitter.emit_line("PyObject_GC_UnTrack(self);")
  669. # The trashcan is needed to handle deep recursive deallocations
  670. emitter.emit_line(f"CPy_TRASHCAN_BEGIN(self, {dealloc_func_name})")
  671. emitter.emit_line(f"{clear_func_name}(self);")
  672. emitter.emit_line("Py_TYPE(self)->tp_free((PyObject *)self);")
  673. emitter.emit_line("CPy_TRASHCAN_END(self)")
  674. emitter.emit_line("}")
  675. def generate_methods_table(cl: ClassIR, name: str, emitter: Emitter) -> None:
  676. emitter.emit_line(f"static PyMethodDef {name}[] = {{")
  677. for fn in cl.methods.values():
  678. if fn.decl.is_prop_setter or fn.decl.is_prop_getter:
  679. continue
  680. emitter.emit_line(f'{{"{fn.name}",')
  681. emitter.emit_line(f" (PyCFunction){PREFIX}{fn.cname(emitter.names)},")
  682. if use_fastcall(emitter.capi_version):
  683. flags = ["METH_FASTCALL"]
  684. else:
  685. flags = ["METH_VARARGS"]
  686. flags.append("METH_KEYWORDS")
  687. if fn.decl.kind == FUNC_STATICMETHOD:
  688. flags.append("METH_STATIC")
  689. elif fn.decl.kind == FUNC_CLASSMETHOD:
  690. flags.append("METH_CLASS")
  691. emitter.emit_line(" {}, NULL}},".format(" | ".join(flags)))
  692. # Provide a default __getstate__ and __setstate__
  693. if not cl.has_method("__setstate__") and not cl.has_method("__getstate__"):
  694. emitter.emit_lines(
  695. '{"__setstate__", (PyCFunction)CPyPickle_SetState, METH_O, NULL},',
  696. '{"__getstate__", (PyCFunction)CPyPickle_GetState, METH_NOARGS, NULL},',
  697. )
  698. emitter.emit_line("{NULL} /* Sentinel */")
  699. emitter.emit_line("};")
  700. def generate_side_table_for_class(
  701. cl: ClassIR, name: str, type: str, slots: dict[str, str], emitter: Emitter
  702. ) -> str | None:
  703. name = f"{cl.name_prefix(emitter.names)}_{name}"
  704. emitter.emit_line(f"static {type} {name} = {{")
  705. for field, value in slots.items():
  706. emitter.emit_line(f".{field} = {value},")
  707. emitter.emit_line("};")
  708. return name
  709. def generate_getseter_declarations(cl: ClassIR, emitter: Emitter) -> None:
  710. if not cl.is_trait:
  711. for attr in cl.attributes:
  712. emitter.emit_line("static PyObject *")
  713. emitter.emit_line(
  714. "{}({} *self, void *closure);".format(
  715. getter_name(cl, attr, emitter.names), cl.struct_name(emitter.names)
  716. )
  717. )
  718. emitter.emit_line("static int")
  719. emitter.emit_line(
  720. "{}({} *self, PyObject *value, void *closure);".format(
  721. setter_name(cl, attr, emitter.names), cl.struct_name(emitter.names)
  722. )
  723. )
  724. for prop, (getter, setter) in cl.properties.items():
  725. if getter.decl.implicit:
  726. continue
  727. # Generate getter declaration
  728. emitter.emit_line("static PyObject *")
  729. emitter.emit_line(
  730. "{}({} *self, void *closure);".format(
  731. getter_name(cl, prop, emitter.names), cl.struct_name(emitter.names)
  732. )
  733. )
  734. # Generate property setter declaration if a setter exists
  735. if setter:
  736. emitter.emit_line("static int")
  737. emitter.emit_line(
  738. "{}({} *self, PyObject *value, void *closure);".format(
  739. setter_name(cl, prop, emitter.names), cl.struct_name(emitter.names)
  740. )
  741. )
  742. def generate_getseters_table(cl: ClassIR, name: str, emitter: Emitter) -> None:
  743. emitter.emit_line(f"static PyGetSetDef {name}[] = {{")
  744. if not cl.is_trait:
  745. for attr in cl.attributes:
  746. emitter.emit_line(f'{{"{attr}",')
  747. emitter.emit_line(
  748. " (getter){}, (setter){},".format(
  749. getter_name(cl, attr, emitter.names), setter_name(cl, attr, emitter.names)
  750. )
  751. )
  752. emitter.emit_line(" NULL, NULL},")
  753. for prop, (getter, setter) in cl.properties.items():
  754. if getter.decl.implicit:
  755. continue
  756. emitter.emit_line(f'{{"{prop}",')
  757. emitter.emit_line(f" (getter){getter_name(cl, prop, emitter.names)},")
  758. if setter:
  759. emitter.emit_line(f" (setter){setter_name(cl, prop, emitter.names)},")
  760. emitter.emit_line("NULL, NULL},")
  761. else:
  762. emitter.emit_line("NULL, NULL, NULL},")
  763. emitter.emit_line("{NULL} /* Sentinel */")
  764. emitter.emit_line("};")
  765. def generate_getseters(cl: ClassIR, emitter: Emitter) -> None:
  766. if not cl.is_trait:
  767. for i, (attr, rtype) in enumerate(cl.attributes.items()):
  768. generate_getter(cl, attr, rtype, emitter)
  769. emitter.emit_line("")
  770. generate_setter(cl, attr, rtype, emitter)
  771. if i < len(cl.attributes) - 1:
  772. emitter.emit_line("")
  773. for prop, (getter, setter) in cl.properties.items():
  774. if getter.decl.implicit:
  775. continue
  776. rtype = getter.sig.ret_type
  777. emitter.emit_line("")
  778. generate_readonly_getter(cl, prop, rtype, getter, emitter)
  779. if setter:
  780. arg_type = setter.sig.args[1].type
  781. emitter.emit_line("")
  782. generate_property_setter(cl, prop, arg_type, setter, emitter)
  783. def generate_getter(cl: ClassIR, attr: str, rtype: RType, emitter: Emitter) -> None:
  784. attr_field = emitter.attr(attr)
  785. emitter.emit_line("static PyObject *")
  786. emitter.emit_line(
  787. "{}({} *self, void *closure)".format(
  788. getter_name(cl, attr, emitter.names), cl.struct_name(emitter.names)
  789. )
  790. )
  791. emitter.emit_line("{")
  792. attr_expr = f"self->{attr_field}"
  793. # HACK: Don't consider refcounted values as always defined, since it's possible to
  794. # access uninitialized values via 'gc.get_objects()'. Accessing non-refcounted
  795. # values is benign.
  796. always_defined = cl.is_always_defined(attr) and not rtype.is_refcounted
  797. if not always_defined:
  798. emitter.emit_undefined_attr_check(rtype, attr_expr, "==", "self", attr, cl, unlikely=True)
  799. emitter.emit_line("PyErr_SetString(PyExc_AttributeError,")
  800. emitter.emit_line(f' "attribute {repr(attr)} of {repr(cl.name)} undefined");')
  801. emitter.emit_line("return NULL;")
  802. emitter.emit_line("}")
  803. emitter.emit_inc_ref(f"self->{attr_field}", rtype)
  804. emitter.emit_box(f"self->{attr_field}", "retval", rtype, declare_dest=True)
  805. emitter.emit_line("return retval;")
  806. emitter.emit_line("}")
  807. def generate_setter(cl: ClassIR, attr: str, rtype: RType, emitter: Emitter) -> None:
  808. attr_field = emitter.attr(attr)
  809. emitter.emit_line("static int")
  810. emitter.emit_line(
  811. "{}({} *self, PyObject *value, void *closure)".format(
  812. setter_name(cl, attr, emitter.names), cl.struct_name(emitter.names)
  813. )
  814. )
  815. emitter.emit_line("{")
  816. deletable = cl.is_deletable(attr)
  817. if not deletable:
  818. emitter.emit_line("if (value == NULL) {")
  819. emitter.emit_line("PyErr_SetString(PyExc_AttributeError,")
  820. emitter.emit_line(
  821. f' "{repr(cl.name)} object attribute {repr(attr)} cannot be deleted");'
  822. )
  823. emitter.emit_line("return -1;")
  824. emitter.emit_line("}")
  825. # HACK: Don't consider refcounted values as always defined, since it's possible to
  826. # access uninitialized values via 'gc.get_objects()'. Accessing non-refcounted
  827. # values is benign.
  828. always_defined = cl.is_always_defined(attr) and not rtype.is_refcounted
  829. if rtype.is_refcounted:
  830. attr_expr = f"self->{attr_field}"
  831. if not always_defined:
  832. emitter.emit_undefined_attr_check(rtype, attr_expr, "!=", "self", attr, cl)
  833. emitter.emit_dec_ref(f"self->{attr_field}", rtype)
  834. if not always_defined:
  835. emitter.emit_line("}")
  836. if deletable:
  837. emitter.emit_line("if (value != NULL) {")
  838. if rtype.is_unboxed:
  839. emitter.emit_unbox("value", "tmp", rtype, error=ReturnHandler("-1"), declare_dest=True)
  840. elif is_same_type(rtype, object_rprimitive):
  841. emitter.emit_line("PyObject *tmp = value;")
  842. else:
  843. emitter.emit_cast("value", "tmp", rtype, declare_dest=True)
  844. emitter.emit_lines("if (!tmp)", " return -1;")
  845. emitter.emit_inc_ref("tmp", rtype)
  846. emitter.emit_line(f"self->{attr_field} = tmp;")
  847. if rtype.error_overlap and not always_defined:
  848. emitter.emit_attr_bitmap_set("tmp", "self", rtype, cl, attr)
  849. if deletable:
  850. emitter.emit_line("} else")
  851. emitter.emit_line(f" self->{attr_field} = {emitter.c_undefined_value(rtype)};")
  852. if rtype.error_overlap:
  853. emitter.emit_attr_bitmap_clear("self", rtype, cl, attr)
  854. emitter.emit_line("return 0;")
  855. emitter.emit_line("}")
  856. def generate_readonly_getter(
  857. cl: ClassIR, attr: str, rtype: RType, func_ir: FuncIR, emitter: Emitter
  858. ) -> None:
  859. emitter.emit_line("static PyObject *")
  860. emitter.emit_line(
  861. "{}({} *self, void *closure)".format(
  862. getter_name(cl, attr, emitter.names), cl.struct_name(emitter.names)
  863. )
  864. )
  865. emitter.emit_line("{")
  866. if rtype.is_unboxed:
  867. emitter.emit_line(
  868. "{}retval = {}{}((PyObject *) self);".format(
  869. emitter.ctype_spaced(rtype), NATIVE_PREFIX, func_ir.cname(emitter.names)
  870. )
  871. )
  872. emitter.emit_error_check("retval", rtype, "return NULL;")
  873. emitter.emit_box("retval", "retbox", rtype, declare_dest=True)
  874. emitter.emit_line("return retbox;")
  875. else:
  876. emitter.emit_line(
  877. f"return {NATIVE_PREFIX}{func_ir.cname(emitter.names)}((PyObject *) self);"
  878. )
  879. emitter.emit_line("}")
  880. def generate_property_setter(
  881. cl: ClassIR, attr: str, arg_type: RType, func_ir: FuncIR, emitter: Emitter
  882. ) -> None:
  883. emitter.emit_line("static int")
  884. emitter.emit_line(
  885. "{}({} *self, PyObject *value, void *closure)".format(
  886. setter_name(cl, attr, emitter.names), cl.struct_name(emitter.names)
  887. )
  888. )
  889. emitter.emit_line("{")
  890. if arg_type.is_unboxed:
  891. emitter.emit_unbox("value", "tmp", arg_type, error=ReturnHandler("-1"), declare_dest=True)
  892. emitter.emit_line(
  893. f"{NATIVE_PREFIX}{func_ir.cname(emitter.names)}((PyObject *) self, tmp);"
  894. )
  895. else:
  896. emitter.emit_line(
  897. f"{NATIVE_PREFIX}{func_ir.cname(emitter.names)}((PyObject *) self, value);"
  898. )
  899. emitter.emit_line("return 0;")
  900. emitter.emit_line("}")
  901. def has_managed_dict(cl: ClassIR, emitter: Emitter) -> bool:
  902. """Should the class get the Py_TPFLAGS_MANAGED_DICT flag?"""
  903. # On 3.11 and earlier the flag doesn't exist and we use
  904. # tp_dictoffset instead. If a class inherits from Exception, the
  905. # flag conflicts with tp_dictoffset set in the base class.
  906. return (
  907. emitter.capi_version >= (3, 12)
  908. and cl.has_dict
  909. and cl.builtin_base != "PyBaseExceptionObject"
  910. )