MCPcopy Index your code
hub / github.com/python/mypy / generate_wrapper_function

Function generate_wrapper_function

mypyc/codegen/emitwrapper.py:134–210  ·  view source on GitHub ↗

Generate a CPython-compatible vectorcall wrapper for a native function. In particular, this handles unboxing the arguments, calling the native function, and then boxing the return value.

(
    fn: FuncIR, emitter: Emitter, source_path: str, module_name: str
)

Source from the content-addressed store, hash-verified

132
133
134def generate_wrapper_function(
135 fn: FuncIR, emitter: Emitter, source_path: str, module_name: str
136) -> None:
137 """Generate a CPython-compatible vectorcall wrapper for a native function.
138
139 In particular, this handles unboxing the arguments, calling the native function, and
140 then boxing the return value.
141 """
142 emitter.emit_line(f"{wrapper_function_header(fn, emitter.names)} {{")
143
144 # If fn is a method, then the first argument is a self param
145 real_args = list(fn.args)
146 if fn.sig.num_bitmap_args:
147 real_args = real_args[: -fn.sig.num_bitmap_args]
148 if fn.class_name and fn.decl.kind != FUNC_STATICMETHOD:
149 arg = real_args.pop(0)
150 emitter.emit_line(f"PyObject *obj_{arg.name} = self;")
151
152 # Need to order args as: required, optional, kwonly optional, kwonly required
153 # This is because CPyArg_ParseStackAndKeywords format string requires
154 # them grouped in that way.
155 groups = make_arg_groups(real_args)
156 reordered_args = reorder_arg_groups(groups)
157
158 emitter.emit_line(make_static_kwlist(reordered_args))
159 fmt = make_format_string(fn.name, groups)
160 # Define the arguments the function accepts (but no types yet)
161 emitter.emit_line(f'static CPyArg_Parser parser = {{"{fmt}", kwlist, 0}};')
162
163 for arg in real_args:
164 emitter.emit_line(
165 "PyObject *obj_{}{};".format(arg.name, " = NULL" if arg.optional else "")
166 )
167
168 cleanups = [f"CPy_DECREF(obj_{arg.name});" for arg in groups[ARG_STAR] + groups[ARG_STAR2]]
169
170 arg_ptrs: list[str] = []
171 if groups[ARG_STAR] or groups[ARG_STAR2]:
172 arg_ptrs += [f"&obj_{groups[ARG_STAR][0].name}" if groups[ARG_STAR] else "NULL"]
173 arg_ptrs += [f"&obj_{groups[ARG_STAR2][0].name}" if groups[ARG_STAR2] else "NULL"]
174 arg_ptrs += [f"&obj_{arg.name}" for arg in reordered_args]
175
176 if fn.name == "__call__":
177 nargs = "PyVectorcall_NARGS(nargs)"
178 else:
179 nargs = "nargs"
180 parse_fn = "CPyArg_ParseStackAndKeywords"
181 # Special case some common signatures
182 if not real_args:
183 # No args
184 parse_fn = "CPyArg_ParseStackAndKeywordsNoArgs"
185 elif len(real_args) == 1 and len(groups[ARG_POS]) == 1:
186 # Single positional arg
187 parse_fn = "CPyArg_ParseStackAndKeywordsOneArg"
188 elif len(real_args) == len(groups[ARG_POS]) + len(groups[ARG_OPT]):
189 # No keyword-only args, *args or **kwargs
190 parse_fn = "CPyArg_ParseStackAndKeywordsSimple"
191 emitter.emit_lines(

Callers 1

Calls 15

bitmap_nameFunction · 0.90
wrapper_function_headerFunction · 0.85
listClass · 0.85
make_arg_groupsFunction · 0.85
reorder_arg_groupsFunction · 0.85
make_static_kwlistFunction · 0.85
make_format_stringFunction · 0.85
lenFunction · 0.85
rangeClass · 0.85
generate_traceback_codeFunction · 0.85
generate_wrapper_coreFunction · 0.85
emit_lineMethod · 0.45

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…