PageRenderTime 40ms CodeModel.GetById 18ms app.highlight 18ms RepoModel.GetById 0ms app.codeStats 0ms

/compilers/numba/numba/_dynfunc.c

https://bitbucket.org/genekh/python
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}