/compilers/numba/numba/_dynfunc.c
C | 453 lines | 367 code | 39 blank | 47 comment | 32 complexity | 996e107f02d9c1e88bc94311d363dc48 MD5 | raw file
Possible License(s): GPL-3.0, BSD-3-Clause
1/*
2 * Definition of Environment and Closure objects.
3 * This module is included by _dynfuncmod.c and by pycc-compiled modules.
4 */
5
6#include "_pymodule.h"
7
8#include <string.h>
9
10/* NOTE: EnvironmentObject and ClosureObject must be kept in sync with
11 * the definitions in numba/targets/base.py (EnvBody and ClosureBody).
12 */
13
14/*
15 * EnvironmentObject hosts data needed for execution of compiled functions.
16 */
17typedef struct {
18 PyObject_HEAD
19 PyObject *globals;
20 /* Assorted "constants" that are needed at runtime to execute
21 the compiled function. This can include frozen closure variables,
22 lifted loops, etc. */
23 PyObject *consts;
24} EnvironmentObject;
25
26
27static PyMemberDef env_members[] = {
28 {"globals", T_OBJECT, offsetof(EnvironmentObject, globals), READONLY},
29 {"consts", T_OBJECT, offsetof(EnvironmentObject, consts), READONLY},
30 {NULL} /* Sentinel */
31};
32
33static int
34env_traverse(EnvironmentObject *env, visitproc visit, void *arg)
35{
36 Py_VISIT(env->globals);
37 Py_VISIT(env->consts);
38 return 0;
39}
40
41static int
42env_clear(EnvironmentObject *env)
43{
44 Py_CLEAR(env->globals);
45 Py_CLEAR(env->consts);
46 return 0;
47}
48
49static void
50env_dealloc(EnvironmentObject *env)
51{
52 _PyObject_GC_UNTRACK((PyObject *) env);
53 env_clear(env);
54 Py_TYPE(env)->tp_free((PyObject *) env);
55}
56
57static EnvironmentObject *
58env_new_empty(PyTypeObject* type)
59{
60 return (EnvironmentObject *) PyType_GenericNew(type, NULL, NULL);
61}
62
63static PyObject *
64env_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
65{
66 PyObject *globals;
67 EnvironmentObject *env;
68 static char *kwlist[] = {"globals", 0};
69
70 if (!PyArg_ParseTupleAndKeywords(
71 args, kwds, "O!:function", kwlist,
72 &PyDict_Type, &globals))
73 return NULL;
74
75 env = env_new_empty(type);
76 if (env == NULL)
77 return NULL;
78 Py_INCREF(globals);
79 env->globals = globals;
80 env->consts = PyList_New(0);
81 if (!env->consts) {
82 Py_DECREF(env);
83 return NULL;
84 }
85 return (PyObject *) env;
86}
87
88
89static PyTypeObject EnvironmentType = {
90#if (PY_MAJOR_VERSION < 3)
91 PyObject_HEAD_INIT(NULL)
92 0, /*ob_size*/
93#else
94 PyVarObject_HEAD_INIT(NULL, 0)
95#endif
96 "_dynfunc.Environment", /*tp_name*/
97 sizeof(EnvironmentObject), /*tp_basicsize*/
98 0, /*tp_itemsize*/
99 (destructor) env_dealloc, /*tp_dealloc*/
100 0, /*tp_print*/
101 0, /*tp_getattr*/
102 0, /*tp_setattr*/
103 0, /*tp_compare*/
104 0, /*tp_repr*/
105 0, /*tp_as_number*/
106 0, /*tp_as_sequence*/
107 0, /*tp_as_mapping*/
108 0, /*tp_hash */
109 0, /*tp_call*/
110 0, /*tp_str*/
111 0, /*tp_getattro*/
112 0, /*tp_setattro*/
113 0, /*tp_as_buffer*/
114 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
115 0, /* tp_doc */
116 (traverseproc) env_traverse, /* tp_traverse */
117 (inquiry) env_clear, /* tp_clear */
118 0, /* tp_richcompare */
119 0, /* tp_weaklistoffset */
120 0, /* tp_iter */
121 0, /* tp_iternext */
122 0, /* tp_methods */
123 env_members, /* tp_members */
124 0, /* tp_getset */
125 0, /* tp_base */
126 0, /* tp_dict */
127 0, /* tp_descr_get */
128 0, /* tp_descr_set */
129 0, /* tp_dictoffset */
130 0, /* tp_init */
131 0, /* tp_alloc */
132 env_new, /* tp_new */
133};
134
135/* A closure object is created for each call to make_function(), and stored
136 as the resulting PyCFunction object's "self" pointer. It points to an
137 EnvironmentObject which is constructed during compilation. This allows
138 for two things:
139 - lifetime management of dependent data (e.g. lifted loop dispatchers)
140 - access to the execution environment by the compiled function
141 (for example the globals module)
142 */
143
144/* Closure is a variable-sized object for binary compatibility with
145 Generator (see below). */
146#define CLOSURE_HEAD \
147 PyObject_VAR_HEAD \
148 EnvironmentObject *env;
149
150typedef struct {
151 CLOSURE_HEAD
152 /* The dynamically-filled method definition for the PyCFunction object
153 using this closure. */
154 PyMethodDef def;
155 /* Arbitrary object to keep alive during the closure's lifetime.
156 (put a tuple to put several objects alive).
157 In practice, this helps keep the LLVM module and its generated
158 code alive. */
159 PyObject *keepalive;
160 PyObject *weakreflist;
161} ClosureObject;
162
163
164static int
165closure_traverse(ClosureObject *clo, visitproc visit, void *arg)
166{
167 Py_VISIT(clo->env);
168 Py_VISIT(clo->keepalive);
169 return 0;
170}
171
172static void
173closure_dealloc(ClosureObject *clo)
174{
175 _PyObject_GC_UNTRACK((PyObject *) clo);
176 if (clo->weakreflist != NULL)
177 PyObject_ClearWeakRefs((PyObject *) clo);
178 PyObject_Free((void *) clo->def.ml_name);
179 PyObject_Free((void *) clo->def.ml_doc);
180 Py_XDECREF(clo->env);
181 Py_XDECREF(clo->keepalive);
182 Py_TYPE(clo)->tp_free((PyObject *) clo);
183}
184
185static PyTypeObject ClosureType = {
186#if (PY_MAJOR_VERSION < 3)
187 PyObject_HEAD_INIT(NULL)
188 0, /*ob_size*/
189#else
190 PyVarObject_HEAD_INIT(NULL, 0)
191#endif
192 "_dynfunc._Closure", /*tp_name*/
193 sizeof(ClosureObject), /*tp_basicsize*/
194 0, /*tp_itemsize*/
195 (destructor) closure_dealloc, /*tp_dealloc*/
196 0, /*tp_print*/
197 0, /*tp_getattr*/
198 0, /*tp_setattr*/
199 0, /*tp_compare*/
200 0, /*tp_repr*/
201 0, /*tp_as_number*/
202 0, /*tp_as_sequence*/
203 0, /*tp_as_mapping*/
204 0, /*tp_hash */
205 0, /*tp_call*/
206 0, /*tp_str*/
207 0, /*tp_getattro*/
208 0, /*tp_setattro*/
209 0, /*tp_as_buffer*/
210 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
211 0, /* tp_doc */
212 (traverseproc) closure_traverse, /* tp_traverse */
213 0, /* tp_clear */
214 0, /* tp_richcompare */
215 offsetof(ClosureObject, weakreflist), /* tp_weaklistoffset */
216 0, /* tp_iter */
217 0, /* tp_iternext */
218 0, /* tp_methods */
219 0, /* tp_members */
220 0, /* tp_getset */
221 0, /* tp_base */
222 0, /* tp_dict */
223 0, /* tp_descr_get */
224 0, /* tp_descr_set */
225 0, /* tp_dictoffset */
226 0, /* tp_init */
227 0, /* tp_alloc */
228 0, /* tp_new */
229};
230
231
232/* Return an owned piece of character data duplicating a Python string
233 object's value. */
234static char *
235dup_string(PyObject *strobj)
236{
237 char *tmp, *str;
238 tmp = PyString_AsString(strobj);
239 if (tmp == NULL)
240 return NULL;
241 /* Using PyObject_Malloc allows this memory to be tracked for
242 leaks. */
243 str = PyObject_Malloc(strlen(tmp) + 1);
244 if (str == NULL) {
245 PyErr_NoMemory();
246 return NULL;
247 }
248 strcpy(str, tmp);
249 return str;
250}
251
252/* Create and initialize a new Closure object */
253static ClosureObject *
254closure_new(PyObject *module, PyObject *name, PyObject *doc,
255 PyCFunction fnaddr, EnvironmentObject *env, PyObject *keepalive)
256{
257 ClosureObject *clo = (ClosureObject *) PyType_GenericAlloc(&ClosureType, 0);
258 if (clo == NULL)
259 return NULL;
260
261 clo->def.ml_name = dup_string(name);
262 if (!clo->def.ml_name) {
263 Py_DECREF(clo);
264 return NULL;
265 }
266 clo->def.ml_meth = fnaddr;
267 clo->def.ml_flags = METH_VARARGS | METH_KEYWORDS;
268 clo->def.ml_doc = dup_string(doc);
269 if (!clo->def.ml_doc) {
270 Py_DECREF(clo);
271 return NULL;
272 }
273 Py_INCREF(env);
274 clo->env = env;
275 Py_XINCREF(keepalive);
276 clo->keepalive = keepalive;
277 return clo;
278}
279
280/* Create a new PyCFunction object wrapping a closure defined by
281 the given arguments. */
282static PyObject *
283pycfunction_new(PyObject *module, PyObject *name, PyObject *doc,
284 PyCFunction fnaddr, EnvironmentObject *env, PyObject *keepalive)
285{
286 PyObject *funcobj;
287 PyObject *modname;
288 ClosureObject *closure;
289
290 closure = closure_new(module, name, doc, fnaddr, env, keepalive);
291 if (closure == NULL)
292 return NULL;
293
294 modname = PyString_FromString(PyModule_GetName(module));
295 funcobj = PyCFunction_NewEx(&closure->def, (PyObject *) closure, modname);
296 Py_DECREF(closure);
297 Py_DECREF(modname);
298 return funcobj;
299}
300
301/*
302 * Python-facing wrapper for Numba-compiled generator.
303 * Note the Environment's offset inside the struct is the same as in the
304 * Closure object. This is required to simplify generation of Python wrappers.
305 */
306
307typedef void (*gen_finalizer_t)(void *);
308
309typedef struct {
310 CLOSURE_HEAD
311 PyCFunctionWithKeywords nextfunc;
312 gen_finalizer_t finalizer;
313 PyObject *weakreflist;
314 union {
315 double dummy; /* Force alignment */
316 char state[0];
317 };
318} GeneratorObject;
319
320static int
321generator_traverse(GeneratorObject *gen, visitproc visit, void *arg)
322{
323 /* XXX this doesn't traverse the state, which can own references to
324 PyObjects */
325 Py_VISIT(gen->env);
326 return 0;
327}
328
329static int
330generator_clear(GeneratorObject *gen)
331{
332 if (gen->finalizer != NULL) {
333 gen->finalizer(gen->state);
334 gen->finalizer = NULL;
335 }
336 Py_CLEAR(gen->env);
337 gen->nextfunc = NULL;
338 return 0;
339}
340
341static void
342generator_dealloc(GeneratorObject *gen)
343{
344 _PyObject_GC_UNTRACK((PyObject *) gen);
345 if (gen->weakreflist != NULL)
346 PyObject_ClearWeakRefs((PyObject *) gen);
347 /* XXX The finalizer may be called after the LLVM module has been
348 destroyed (typically at interpreter shutdown) */
349#if PY_MAJOR_VERSION >= 3
350 if (!_Py_Finalizing)
351#endif
352 if (gen->finalizer != NULL)
353 gen->finalizer(gen->state);
354 Py_XDECREF(gen->env);
355 Py_TYPE(gen)->tp_free((PyObject *) gen);
356}
357
358static PyObject *
359generator_iternext(GeneratorObject *gen)
360{
361 PyObject *res, *args;
362 if (gen->nextfunc == NULL) {
363 PyErr_SetString(PyExc_RuntimeError,
364 "cannot call next() on finalized generator");
365 return NULL;
366 }
367 args = PyTuple_Pack(1, (PyObject *) gen);
368 if (args == NULL)
369 return NULL;
370 res = (*gen->nextfunc)((PyObject *) gen, args, NULL);
371 Py_DECREF(args);
372 return res;
373}
374
375static PyTypeObject GeneratorType = {
376#if (PY_MAJOR_VERSION < 3)
377 PyObject_HEAD_INIT(NULL)
378 0, /* ob_size*/
379#else
380 PyVarObject_HEAD_INIT(NULL, 0)
381#endif
382 "_dynfunc._Generator", /* tp_name*/
383 offsetof(GeneratorObject, state), /* tp_basicsize*/
384 1, /* tp_itemsize*/
385 (destructor) generator_dealloc, /* tp_dealloc*/
386 0, /* tp_print*/
387 0, /* tp_getattr*/
388 0, /* tp_setattr*/
389 0, /* tp_compare*/
390 0, /* tp_repr*/
391 0, /* tp_as_number*/
392 0, /* tp_as_sequence*/
393 0, /* tp_as_mapping*/
394 0, /* tp_hash */
395 0, /* tp_call*/
396 0, /* tp_str*/
397 0, /* tp_getattro*/
398 0, /* tp_setattro*/
399 0, /* tp_as_buffer*/
400 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
401 | Py_TPFLAGS_BASETYPE, /* tp_flags*/
402 0, /* tp_doc */
403 (traverseproc) generator_traverse, /* tp_traverse */
404 (inquiry) generator_clear, /* tp_clear */
405 0, /* tp_richcompare */
406 offsetof(GeneratorObject, weakreflist), /* tp_weaklistoffset */
407 PyObject_SelfIter, /* tp_iter */
408 (iternextfunc) generator_iternext, /* tp_iternext */
409 0, /* tp_methods */
410 0, /* tp_members */
411 0, /* tp_getset */
412 0, /* tp_base */
413 0, /* tp_dict */
414 0, /* tp_descr_get */
415 0, /* tp_descr_set */
416 0, /* tp_dictoffset */
417 0, /* tp_init */
418 0, /* tp_alloc */
419 0, /* tp_new */
420};
421
422/* Dynamically create a new generator object */
423static PyObject *
424Numba_make_generator(Py_ssize_t gen_state_size,
425 void *initial_state,
426 PyCFunctionWithKeywords nextfunc,
427 gen_finalizer_t finalizer,
428 EnvironmentObject *env)
429{
430 GeneratorObject *gen;
431 gen = (GeneratorObject *) PyType_GenericAlloc(&GeneratorType, gen_state_size);
432 if (gen == NULL)
433 return NULL;
434 memcpy(gen->state, initial_state, gen_state_size);
435 gen->nextfunc = nextfunc;
436 Py_XINCREF(env);
437 gen->env = env;
438 gen->finalizer = finalizer;
439 return (PyObject *) gen;
440}
441
442/* Initialization subroutine for use by modules including this */
443static int
444init_dynfunc_module(PyObject *module)
445{
446 if (PyType_Ready(&ClosureType))
447 return -1;
448 if (PyType_Ready(&EnvironmentType))
449 return -1;
450 if (PyType_Ready(&GeneratorType))
451 return -1;
452 return 0;
453}