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