|
1 | 1 | """Code generation for native classes and related wrappers."""
|
2 | 2 |
|
3 |
| - |
4 | 3 | from typing import Optional, List, Tuple, Dict, Callable, Mapping, Set
|
| 4 | + |
5 | 5 | from mypy.ordered_dict import OrderedDict
|
6 | 6 |
|
7 |
| -from mypyc.common import PREFIX, NATIVE_PREFIX, REG_PREFIX, USE_FASTCALL |
| 7 | +from mypyc.common import PREFIX, NATIVE_PREFIX, REG_PREFIX, USE_FASTCALL, USE_VECTORCALL |
8 | 8 | from mypyc.codegen.emit import Emitter, HeaderDeclaration
|
9 | 9 | from mypyc.codegen.emitfunc import native_function_header
|
10 | 10 | from mypyc.codegen.emitwrapper import (
|
@@ -35,7 +35,7 @@ def wrapper_slot(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str:
|
35 | 35 |
|
36 | 36 | SLOT_DEFS = {
|
37 | 37 | '__init__': ('tp_init', lambda c, t, e: generate_init_for_class(c, t, e)),
|
38 |
| - '__call__': ('tp_call', wrapper_slot), |
| 38 | + '__call__': ('tp_call', lambda c, t, e: generate_call_wrapper(c, t, e)), |
39 | 39 | '__str__': ('tp_str', native_slot),
|
40 | 40 | '__repr__': ('tp_repr', native_slot),
|
41 | 41 | '__next__': ('tp_iternext', native_slot),
|
@@ -71,6 +71,15 @@ def wrapper_slot(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str:
|
71 | 71 | }
|
72 | 72 |
|
73 | 73 |
|
| 74 | +def generate_call_wrapper(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str: |
| 75 | + if USE_VECTORCALL: |
| 76 | + # Use vectorcall wrapper if supported (PEP 590). |
| 77 | + return 'PyVectorcall_Call' |
| 78 | + else: |
| 79 | + # On older Pythons use the legacy wrapper. |
| 80 | + return wrapper_slot(cl, fn, emitter) |
| 81 | + |
| 82 | + |
74 | 83 | def generate_slots(cl: ClassIR, table: SlotTable, emitter: Emitter) -> Dict[str, str]:
|
75 | 84 | fields = OrderedDict() # type: Dict[str, str]
|
76 | 85 | # Sort for determinism on Python 3.5
|
@@ -241,6 +250,10 @@ def emit_line() -> None:
|
241 | 250 | flags = ['Py_TPFLAGS_DEFAULT', 'Py_TPFLAGS_HEAPTYPE', 'Py_TPFLAGS_BASETYPE']
|
242 | 251 | if generate_full:
|
243 | 252 | flags.append('Py_TPFLAGS_HAVE_GC')
|
| 253 | + if cl.has_method('__call__') and USE_VECTORCALL: |
| 254 | + fields['tp_vectorcall_offset'] = 'offsetof({}, vectorcall)'.format( |
| 255 | + cl.struct_name(emitter.names)) |
| 256 | + flags.append('_Py_TPFLAGS_HAVE_VECTORCALL') |
244 | 257 | fields['tp_flags'] = ' | '.join(flags)
|
245 | 258 |
|
246 | 259 | emitter.emit_line("static PyTypeObject {}_template_ = {{".format(emitter.type_struct_name(cl)))
|
@@ -277,6 +290,8 @@ def generate_object_struct(cl: ClassIR, emitter: Emitter) -> None:
|
277 | 290 | lines += ['typedef struct {',
|
278 | 291 | 'PyObject_HEAD',
|
279 | 292 | 'CPyVTableItem *vtable;']
|
| 293 | + if cl.has_method('__call__') and USE_VECTORCALL: |
| 294 | + lines.append('vectorcallfunc vectorcall;') |
280 | 295 | for base in reversed(cl.base_mro):
|
281 | 296 | if not base.is_trait:
|
282 | 297 | for attr, rtype in base.attributes.items():
|
@@ -451,6 +466,10 @@ def generate_setup_for_class(cl: ClassIR,
|
451 | 466 | else:
|
452 | 467 | emitter.emit_line('self->vtable = {};'.format(vtable_name))
|
453 | 468 |
|
| 469 | + if cl.has_method('__call__') and USE_VECTORCALL: |
| 470 | + name = cl.method_decl('__call__').cname(emitter.names) |
| 471 | + emitter.emit_line('self->vectorcall = {}{};'.format(PREFIX, name)) |
| 472 | + |
454 | 473 | for base in reversed(cl.base_mro):
|
455 | 474 | for attr, rtype in base.attributes.items():
|
456 | 475 | emitter.emit_line('self->{} = {};'.format(
|
|
0 commit comments