#include "Python.h" #ifdef STACKLESS #include "compile.h" #include "stackless_impl.h" #include "prickelpit.h" /* platform specific constants */ #include "slp_platformselect.h" /****************************************************** support code for post-installing of pickling *******************************************************/ static int meth_table_len(PyMethodDef *ml) { int len = 0; while (ml->ml_meth != NULL) { ++len; ++ml; } return len; } static PyMethodDef * merge_meth_tables(PyMethodDef *ml1, PyMethodDef *ml2) { int len1 = meth_table_len(ml1), len2 = meth_table_len(ml2); int len = len1 + len2 + 1; int i; PyMethodDef *ml = malloc(sizeof(PyMethodDef)*len); if (ml == NULL) return NULL; for (i = 0; itp_new == NULL); /* note that type_ready might fill it in, so we test it here */ if (ml != NULL) { if (t->tp_methods != NULL) { /* create a new merged method table */ if ((ml = merge_meth_tables(t->tp_methods, ml)) == NULL) return -1; } t->tp_methods = ml; } /* we cannot use the __module__ attribute, since this is no heap type */ if (strncmp(stackless, t->tp_name, strlen(stackless))) { new_name = malloc(strlen(stackless)+strlen(t->tp_name)+1); if (new_name == NULL) return -1; strcpy(new_name, stackless); strcat(new_name, t->tp_name); t->tp_name = new_name; } /* enforce the dict and type to be initialized */ if (PyType_Ready(t)) return -1; if (_new != NULL) { t->tp_new = _new; t->tp_init = NULL; } return 0; } /****************************************************** default execute function for invalid frames *******************************************************/ /* * note that every new execute function should also create * a different call of this function. */ PyObject * slp_cannot_execute(PyFrameObject *f, char *exec_name) { /* * show an error message and raise exception. */ PyObject *message; PyThreadState *tstate = PyThreadState_GET(); message = PyString_FromFormat( "cannot execute invalid frame with '%.100s': frame had a C state that can't be restored.", exec_name); if (message == NULL) { /* try at least something */ PyErr_SetString(PyExc_RuntimeError, "invalid frame, cannot build error message."); goto err_exit; } PyErr_SetObject(PyExc_RuntimeError, message); Py_DECREF(message); err_exit: tstate->frame = f->f_back; return NULL; } /* registering and retrieval of frame exec functions */ /* unfortunately, this object is not public, * so we need to repeat it here: */ typedef struct { PyObject_HEAD PyObject *dict; } proxyobject; int slp_register_execute(PyTypeObject *t, char *name, PyFrame_ExecFunc *good, PyFrame_ExecFunc *bad) { PyObject *g = NULL, *b = NULL, *nameobj = NULL, *tup = NULL, *dic = NULL; proxyobject *dp = NULL; int ret = -1; assert(PyObject_IsSubclass((PyObject *)t, (PyObject *)&PyBaseFrame_Type) || PyObject_IsSubclass((PyObject *)t, (PyObject *)&PyFrame_Type)); if (0 || PyType_Ready(t) || name == NULL || (nameobj = PyString_FromString(name)) == NULL || (g = PyLong_FromVoidPtr(good)) == NULL || (b = PyLong_FromVoidPtr(bad)) == NULL || (tup = Py_BuildValue("OO", g, b)) == NULL ) goto err_exit; dp = (proxyobject*) PyDict_GetItemString(t->tp_dict, "_exec_map"); if ((dic = dp ? dp->dict : NULL) == NULL) { if (0 || (dic = PyDict_New()) == NULL || (dp = (proxyobject *) PyDictProxy_New(dic)) == NULL || PyDict_SetItemString(t->tp_dict, "_exec_map", (PyObject *) dp) ) goto err_exit; } else { Py_INCREF(dic); Py_INCREF(dp); } if (0 || PyDict_GetItem(dp->dict, nameobj) != NULL || PyDict_GetItem(dp->dict, g) != NULL || PyDict_GetItem(dp->dict, b) != NULL ) { PyErr_SetString(PyExc_SystemError, "duplicate/ambiguous exec func"); goto err_exit; } if (0 || PyDict_SetItem(dp->dict, nameobj, tup) || PyDict_SetItem(dp->dict, g, nameobj) || PyDict_SetItem(dp->dict, b, nameobj) ) goto err_exit; PyErr_Clear(); ret = 0; err_exit: Py_XDECREF(nameobj); Py_XDECREF(g); Py_XDECREF(b); Py_XDECREF(tup); Py_XDECREF(dic); Py_XDECREF(dp); return ret; } int slp_find_execfuncs(PyTypeObject *type, PyObject *exec_name, PyFrame_ExecFunc **good, PyFrame_ExecFunc **bad) { PyObject *g, *b; proxyobject *dp = (proxyobject *) PyDict_GetItemString(type->tp_dict, "_exec_map"); PyObject *dic = dp ? dp->dict : NULL; PyObject *exec_tup = dic ? PyDict_GetItem(dic, exec_name) : NULL; if (exec_tup == NULL || !PyArg_ParseTuple(exec_tup, "OO", &g, &b) || (*good = PyLong_AsVoidPtr(g)) == NULL || (*bad = PyLong_AsVoidPtr(b)) == NULL) { char msg[500]; PyErr_Clear(); sprintf(msg, "Frame exec function '%.20s' not defined for %s", PyString_AS_STRING(exec_name), type->tp_name); PyErr_SetString(PyExc_ValueError, msg); return -1; } return 0; } PyObject * slp_find_execname(PyFrameObject *f, int *valid) { PyObject *exec_name = NULL; proxyobject *dp = (proxyobject *) PyDict_GetItemString(f->ob_type->tp_dict, "_exec_map"); PyObject *dic = dp ? dp->dict : NULL; PyObject *exec_addr = PyLong_FromVoidPtr(f->f_execute); if (exec_addr == NULL) return NULL; exec_name = dic ? PyDict_GetItem(dic, exec_addr) : NULL; if (exec_name == NULL) { char msg[500]; PyErr_Clear(); sprintf(msg, "frame exec function at %08p is not registered!", f->f_execute); PyErr_SetString(PyExc_ValueError, msg); valid = 0; } else { PyFrame_ExecFunc *good, *bad; if (slp_find_execfuncs(f->ob_type, exec_name, &good, &bad)) { exec_name = NULL; goto err_exit; } if (f->f_execute == bad) valid = 0; else if (f->f_execute != good) { PyErr_SetString(PyExc_SystemError, "inconsistent registration of frame functions"); goto err_exit; } } err_exit: Py_XDECREF(exec_addr); Py_XINCREF(exec_name); return exec_name; } /****************************************************** pickling of objects that may contain NULLs *******************************************************/ /* * To restore arrays which can contain NULLs, we add an extra * tuple at the beginning, which contains the positions of * all objects which are meant to be a real NULL. */ PyObject * slp_into_tuple_with_nulls(PyObject **start, int length) { PyObject *res = PyTuple_New(length+1); PyObject *nulls = PyTuple_New(0); int i, nullcount = 0; if (res == NULL) return NULL; for (i=0; i= 0 && p < length) { Py_XDECREF(start[p]); start[p] = NULL; } } } return length; } /****************************************************** pickling addition to code objects *******************************************************/ #define codetuplefmt "iiiiSOOOSSiSOO" static PyObject * codeobject_reduce(PyCodeObject * co) { PyObject *tup = Py_BuildValue("(O(" codetuplefmt "))", &PyCode_Type, co->co_argcount, co->co_nlocals, co->co_stacksize, co->co_flags, co->co_code, co->co_consts, co->co_names, co->co_varnames, co->co_filename, co->co_name, co->co_firstlineno, co->co_lnotab, co->co_freevars, co->co_cellvars ); return tup; } static PyMethodDef codeobject_methods[] = { {"__reduce__", (PyCFunction)codeobject_reduce, METH_NOARGS, NULL}, {NULL, NULL} }; static int init_codetype(void) { /* initialization of codeobject pickling support */ return init_type(&PyCode_Type, codeobject_methods, NULL); } /****************************************************** pickling addition to cell objects *******************************************************/ /* * cells create cycles via function closures. * We therefore need to use the 3-element protocol * of __reduce__ */ static PyObject * cell_reduce(PyCellObject *cell) { PyObject *tup = NULL; if (cell->ob_ref == NULL) { tup = Py_BuildValue("(O()())", &PyCell_Type); } else { tup = Py_BuildValue("(O()(O))", &PyCell_Type, cell->ob_ref); } return tup; } static PyObject * cell_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *ob = NULL; if (!PyArg_ParseTuple (args, "|O", &ob)) return NULL; return PyCell_New(ob); } /* note that args is a tuple, although we use METH_O */ static PyObject * cell_setstate(PyObject *self, PyObject *args) { PyCellObject *cell = (PyCellObject *) self; PyObject *ob = NULL; if (!PyArg_ParseTuple (args, "|O", &ob)) return NULL; Py_XDECREF(cell->ob_ref); cell->ob_ref = ob; Py_XINCREF(cell->ob_ref); Py_INCREF(self); return self; } static PyMethodDef cell_methods[] = { {"__reduce__", (PyCFunction)cell_reduce, METH_NOARGS, NULL}, {"__setstate__", (PyCFunction)cell_setstate, METH_O, NULL}, {NULL, NULL} }; static int init_celltype(void) { /* initialization of cellobject pickling support */ return init_type(&PyCell_Type, cell_methods, cell_new); } /****************************************************** pickling addition to function objects *******************************************************/ #define functuplefmt "OOOOO" static PyObject * funcobject_reduce(PyFunctionObject * func) { PyObject *tup = Py_BuildValue("(O(" functuplefmt "))", &PyFunction_Type, func->func_code != NULL ? func->func_code : Py_None, func->func_globals != NULL ? func->func_globals : Py_None, func->func_name != NULL ? func->func_name : Py_None, func->func_defaults != NULL ? func->func_defaults : Py_None, func->func_closure != NULL ? func->func_closure : Py_None ); return tup; } static PyMethodDef funcobject_methods[] = { {"__reduce__", (PyCFunction)funcobject_reduce, METH_NOARGS, NULL}, {NULL, NULL} }; static int init_functype(void) { /* initialization of function object pickling support */ return init_type(&PyFunction_Type, funcobject_methods, NULL); } /****************************************************** pickling addition to frame objects *******************************************************/ #define frametuplefmt "iSOiOOOiOiiOO" DEF_INVALID_EXEC(eval_frame) DEF_INVALID_EXEC(eval_frame_value) DEF_INVALID_EXEC(eval_frame_noval) DEF_INVALID_EXEC(eval_frame_iter) static PyObject * frameobject_reduce(PyFrameObject *f) { int i; PyObject **f_stacktop; PyObject *blockstack_as_tuple = NULL, *localsplus_as_tuple = NULL, *res = NULL, *exec_name = NULL, *exc_as_tuple = NULL; int valid = 1; int have_locals = f->f_locals != NULL; PyObject * dummy_locals = NULL; if (!have_locals) if ((dummy_locals = PyDict_New()) == NULL) return NULL; if ((exec_name = slp_find_execname(f, &valid)) == NULL) return NULL; if (f->f_exc_type != NULL && f->f_exc_type != Py_None) { exc_as_tuple = slp_into_tuple_with_nulls(&f->f_exc_type, 3); if (exc_as_tuple == NULL) goto err_exit; } else { Py_INCREF(Py_None); exc_as_tuple = Py_None; } blockstack_as_tuple = PyTuple_New (f->f_iblock); if (blockstack_as_tuple == NULL) goto err_exit; for (i = 0; i < f->f_iblock; i++) { /* PyTuple_SetItem steals the reference, so no DECREF(o) */ PyObject *o, *tripel; tripel = PyTuple_New(3); if (tripel == NULL) goto err_exit; PyTuple_SET_ITEM(blockstack_as_tuple, i, tripel); PyTuple_SET_ITEM(tripel, 0, o = Py_BuildValue("i", f->f_blockstack[i].b_type)); if (o == NULL) goto err_exit; PyTuple_SET_ITEM(tripel, 1, o = Py_BuildValue("i", f->f_blockstack[i].b_handler)); if (o == NULL) goto err_exit; PyTuple_SET_ITEM(tripel, 2, o = Py_BuildValue("i", f->f_blockstack[i].b_level)); if (o == NULL) goto err_exit; } f_stacktop = f->f_stacktop; if (f_stacktop != NULL) { if (f_stacktop < f->f_valuestack) { PyErr_SetString(PyExc_ValueError, "stack underflow"); goto err_exit; } localsplus_as_tuple = slp_into_tuple_with_nulls( f->f_localsplus, f_stacktop - f->f_localsplus); if (localsplus_as_tuple == NULL) goto err_exit; } else { localsplus_as_tuple = Py_None; Py_INCREF(Py_None); /* frames without a stacktop cannot be run */ valid = 0; } res = Py_BuildValue ("(O(" frametuplefmt "))", &PyFrame_Type, valid, exec_name, f->f_globals, have_locals, have_locals ? f->f_locals : dummy_locals, f->f_code, f->f_trace != NULL ? f->f_trace : Py_None, f->f_restricted, exc_as_tuple, f->f_lasti, f->f_lineno, blockstack_as_tuple, localsplus_as_tuple ); err_exit: Py_XDECREF(exec_name); Py_XDECREF(exc_as_tuple); Py_XDECREF(blockstack_as_tuple); Py_XDECREF(localsplus_as_tuple); Py_XDECREF(dummy_locals); return res; } static PyMethodDef frameobject_methods[] = { {"__reduce__", (PyCFunction)frameobject_reduce, METH_NOARGS, NULL}, {NULL, NULL} }; #define frametuplenewfmt "iSO!iO!O!OiOiiO!O:frame_new" static PyObject * frame_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyThreadState *ts; PyFrameObject *f = NULL; int f_restricted, f_lasti, f_lineno, i; PyObject *f_globals, *f_locals, *f_code, *blockstack_as_tuple, *localsplus_as_tuple, *exc_as_tuple, *trace; PyObject *exec_name = NULL; PyFrame_ExecFunc *good_func, *bad_func; int valid, have_locals; if (kwds != NULL) { PyErr_SetString(PyExc_ValueError, "Keyword parameters not supported for frame_new"); return NULL; } if (!PyArg_ParseTuple (args, frametuplenewfmt, &valid, &exec_name, &PyDict_Type, &f_globals, &have_locals, &PyDict_Type, &f_locals, &PyCode_Type, &f_code, &trace, &f_restricted, &exc_as_tuple, &f_lasti, &f_lineno, &PyTuple_Type, &blockstack_as_tuple, &localsplus_as_tuple )) return NULL; if (slp_find_execfuncs(type, exec_name, &good_func, &bad_func)) return NULL; /* We are borrowing f_code, blockstack_as_tuple, localsplus_as_tuple; no DECREF them. */ ts = PyThreadState_GET(); if (!have_locals) f_locals = NULL; f = PyFrame_New (ts, (PyCodeObject *) f_code, f_globals, f_locals); if (f == NULL) return NULL; if (trace != Py_None) { if (!PyCallable_Check(trace)) { PyErr_SetString(PyExc_TypeError, "trace must be a function for frame"); goto err_exit; } Py_INCREF(trace); f->f_trace = trace; } f->f_restricted = f_restricted; if (exc_as_tuple != Py_None) { if (PyTuple_GET_SIZE(exc_as_tuple) != 4) { PyErr_SetString(PyExc_ValueError, "bad exception tuple for frame"); goto err_exit; } slp_from_tuple_with_nulls(&f->f_exc_type, exc_as_tuple); } if (PyTuple_Check(localsplus_as_tuple)) { int space = f->f_stacksize + (f->f_valuestack - f->f_localsplus); if (PyTuple_GET_SIZE(localsplus_as_tuple)-1 > space) { PyErr_SetString(PyExc_ValueError, "invalid localsplus for frame"); goto err_exit; } f->f_stacktop = f->f_localsplus; f->f_stacktop += slp_from_tuple_with_nulls(f->f_localsplus, localsplus_as_tuple); } else if (localsplus_as_tuple == Py_None) { f->f_stacktop = NULL; valid = 0; /* cannot run frame without stack */ } else { PyErr_SetString(PyExc_TypeError, "stack must be tuple or None for frame"); goto err_exit; } Py_XDECREF(f->f_back); /* mark this frame to come from unpickling */ Py_INCREF(Py_None); f->f_back = (PyFrameObject *) Py_None; f->f_lasti = f_lasti; f->f_lineno = f_lineno; f->f_iblock = PyTuple_GET_SIZE(blockstack_as_tuple); if (f->f_iblock < 0 || f->f_iblock > CO_MAXBLOCKS) { PyErr_SetString(PyExc_ValueError, "invalid blockstack for frame"); goto err_exit; } for (i = 0; i < CO_MAXBLOCKS; i++) { if (i < f->f_iblock) { if (!PyArg_ParseTuple( PyTuple_GET_ITEM(blockstack_as_tuple, i), "iii", &f->f_blockstack[i].b_type, &f->f_blockstack[i].b_handler, &f->f_blockstack[i].b_level)) goto err_exit; } else { f->f_blockstack[i].b_type = f->f_blockstack[i].b_handler = f->f_blockstack[i].b_level = 0; } } /* see if this frame is valid to be run */ f->f_execute = valid ? good_func : bad_func; return (PyObject *) f; err_exit: Py_XDECREF(f); return NULL; } PyFrameObject * slp_clone_frame(PyFrameObject *f) { PyObject *tup, *func, *args; PyFrameObject *fnew; tup = PyObject_CallMethod((PyObject *) f, "__reduce__", ""); if (tup == NULL) return NULL; func = PyTuple_GET_ITEM(tup, 0); args = PyTuple_GET_ITEM(tup, 1); fnew = (PyFrameObject *) PyObject_CallObject(func, args); Py_DECREF(tup); return fnew; } /* * return a usable reference to the frame. * If the frame doesn't come from unpickling, * a clone is created. * Otherwise, the frame is increffed. */ PyFrameObject * slp_ensure_new_frame(PyFrameObject *f) { /* the type check for tasklets is included here for brevity */ if (! (PyBaseFrame_Check(f) || PyFrame_Check(f)) ) { PyErr_SetString(PyExc_TypeError, "tasklet unpickle needs list of frames last parameter."); return NULL; } if ((PyObject *) f->f_back != Py_None) { f = slp_clone_frame(f); if (f==NULL) { return NULL; } } else { Py_INCREF(f); } Py_XDECREF(f->f_back); f->f_back = NULL; return f; } static int init_frametype(void) { /* initialization of frame pickling support */ return init_type(&PyFrame_Type, frameobject_methods, frame_new) || slp_register_execute(&PyFrame_Type, "eval_frame", PyEval_EvalFrame, REF_INVALID_EXEC(eval_frame)) || slp_register_execute(&PyFrame_Type, "eval_frame_value", PyEval_EvalFrame_value, REF_INVALID_EXEC(eval_frame_value)) || slp_register_execute(&PyFrame_Type, "eval_frame_noval", PyEval_EvalFrame_noval, REF_INVALID_EXEC(eval_frame_noval)) || slp_register_execute(&PyFrame_Type, "eval_frame_iter", PyEval_EvalFrame_iter, REF_INVALID_EXEC(eval_frame_iter)); } /****************************************************** pickling of tracebacks ******************************************************/ /* * Has been all transferred to traceback.c :-) * * XXX revert this as much as possible and keep the patch small !! */ static int init_tracebacktype(void) { /* initialization of traceback pickling support */ return init_type(&PyTraceBack_Type, NULL, NULL); } /****************************************************** pickling of modules ******************************************************/ static PyObject * module_reduce(PyObject * m) { PyObject *globals = NULL; PyObject *builtins = NULL; PyObject *import = NULL; PyObject *tup = NULL; static PyObject *builtins_str = NULL; static PyObject *import_str = NULL; char *name = PyModule_GetName(m); if (name == NULL) return NULL; if (builtins_str == NULL) { builtins_str = PyString_InternFromString("__builtins__"); if (builtins_str == NULL) return NULL; import_str = PyString_InternFromString("__import__"); if (import_str == NULL) return NULL; } globals = PyEval_GetGlobals(); if (globals != NULL) { Py_INCREF(globals); builtins = PyObject_GetItem(globals, builtins_str); if (builtins == NULL) goto err; } /* Get the __import__ function from the builtins */ if (PyDict_Check(builtins)) { import = PyObject_GetItem(builtins, import_str); if (import == NULL) PyErr_SetObject(PyExc_KeyError, import_str); } else import = PyObject_GetAttr(builtins, import_str); if (import == NULL) goto err; tup = Py_BuildValue("(O(s))", import, name); err: Py_XDECREF(globals); Py_XDECREF(builtins); Py_XDECREF(import); return tup; } static PyMethodDef module_methods[] = { {"__reduce__", (PyCFunction)module_reduce, METH_NOARGS, NULL}, {NULL, NULL} }; static int init_moduletype(void) { /* initialization of module pickling support */ return init_type(&PyModule_Type, module_methods, NULL); } /****************************************************** unpickling of enumerators ******************************************************/ /* * unfortunately we have to copy here. * XXX automate checking such situations. */ typedef struct { PyObject_HEAD long en_index; /* current index of enumeration */ PyObject* en_sit; /* secondary iterator of enumeration */ PyObject* en_result; /* result tuple */ } enumobject; PyTypeObject PyEnumFactory_Type; static PyObject * enumfactory_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *seq=NULL, *tup=NULL, *rval=NULL; long index; if (!PyArg_ParseTuple (args, "Ol:enumerate-factory", &seq, &index)) return NULL; tup = PyTuple_New(1); if (tup == NULL) return NULL; Py_INCREF(seq); PyTuple_SET_ITEM(tup, 0, seq); rval = PyEnum_Type.tp_new(&PyEnumFactory_Type, tup, NULL); Py_DECREF(tup); if (rval == NULL) { return NULL; } ((enumobject*)rval)->en_index = index; return rval; } static int init_enumfactorytype(void) { PyTypeObject *t = &PyEnumFactory_Type; memcpy(t, &PyEnum_Type, sizeof(PyEnum_Type)); t->tp_name = "enumerate-factory"; t->tp_new = NULL; if (init_type(&PyEnumFactory_Type, NULL, enumfactory_new)) return -1; return 0; } /****************************************************** pickling of module dictionaries ******************************************************/ typedef struct _modictobject PyModuleDictObject; struct _modictobject { PyDictObject dict; PyObject *modname; }; PyTypeObject PyModuleDict_Type; static PyObject * modict_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *module, *dict; if (!PyArg_ParseTuple (args, "O!", &PyModule_Type, &module)) return NULL; dict = PyModule_GetDict(module); Py_INCREF(dict); return dict; } static PyObject * modict_reduce(PyModuleDictObject * d) { PyObject *tup; PyObject *module = PySys_GetObject("modules"); if (module == NULL) return NULL; module = PyDict_GetItem(module, d->modname); if (module == NULL) return NULL; tup = Py_BuildValue("(O(O))", &PyModuleDict_Type, module); return tup; } static PyMethodDef modict_methods[] = { {"__reduce__", (PyCFunction)modict_reduce, METH_NOARGS, "md.__reduce__() -- reduce modict for pickling"}, {NULL, NULL} }; static PyObject * modict_repr(PyModuleDictObject *d) { char *name = PyString_AS_STRING(d->modname); return PyString_FromFormat("", name); } static void modict_dealloc(PyModuleDictObject *mp) { Py_XDECREF(mp->modname); mp->dict.ob_type->tp_base->tp_dealloc((PyObject *) mp); } /* this init must go very early */ #define OFF(x) offsetof(PyModuleDictObject, x) static PyMemberDef modict_memberlist[] = { {"__module__", T_OBJECT, OFF(modname), RO}, {NULL} /* Sentinel */ }; #undef OFF PyObject * PyModuleDict_New(PyObject *name) { PyObject *d; if (name == NULL) return NULL; if (PyType_Ready(&PyDict_Type)) return NULL; d = PyDict_Type.tp_new(&PyModuleDict_Type, NULL, NULL); if (d == NULL) return NULL; Py_INCREF(name); ((PyModuleDictObject *) d)->modname = name; return (PyObject *) d; } static int init_moduledicttype(void) { PyTypeObject *t = &PyModuleDict_Type; /* if (t->tp_name != NULL) return 0; */ memcpy(t, &PyDict_Type, sizeof(PyDict_Type)); t->tp_name = "modict"; t->tp_basicsize = sizeof(PyModuleDictObject); t->tp_base = &PyDict_Type; t->tp_dealloc = (destructor)modict_dealloc; t->tp_members = modict_memberlist; t->tp_repr = (reprfunc)modict_repr; t->tp_methods = NULL; /* will be set in init_type */ t->tp_new = NULL; if (init_type(&PyModuleDict_Type, modict_methods, modict_new)) return -1; t->tp_print = NULL; t->tp_init = NULL; return 0; } /****************************************************** pickling of iterators ******************************************************/ /* XXX make sure this copy is always up to date */ typedef struct { PyObject_HEAD long it_index; PyObject *it_seq; } seqiterobject; static PyObject * iter_reduce(seqiterobject *iterator) { PyObject *tup; tup = Py_BuildValue("(O(lO))", &PySeqIter_Type, iterator->it_index, iterator->it_seq ); return tup; } static PyObject * iter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { seqiterobject *it; long it_index; PyObject *it_seq; if (kwds != NULL) { PyErr_SetString(PyExc_ValueError, "Keyword parameters not supported for iter_new"); return NULL; } if (!PyArg_ParseTuple(args, "lO:iter", &it_index, &it_seq)) return NULL; it = (seqiterobject *) PySeqIter_New(it_seq); if (it == NULL) return NULL; it->it_index = it_index; return (PyObject *) it; } static PyMethodDef iter_methods[] = { {"__reduce__", (PyCFunction)iter_reduce, METH_NOARGS, "it.__reduce__() -- reduce iterator for pickling"}, {NULL, NULL} /* sentinel */ }; /* XXX make sure this copy is always up to date */ typedef struct { PyObject_HEAD PyObject *it_callable; PyObject *it_sentinel; } calliterobject; static PyObject * calliter_reduce(calliterobject *iterator) { PyObject *tup; tup = Py_BuildValue("(O(OO))", &PyCallIter_Type, iterator->it_callable, iterator->it_sentinel ); return tup; } static PyObject * calliter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { calliterobject *it; PyObject *it_callable; PyObject *it_sentinel; if (kwds != NULL) { PyErr_SetString(PyExc_ValueError, "Keyword parameters not supported for calliter_new"); return NULL; } if (!PyArg_ParseTuple(args, "OO:calliter", &it_callable, &it_sentinel)) return NULL; it = (calliterobject *) PyCallIter_New(it_callable, it_sentinel); return (PyObject *) it; } static PyMethodDef calliter_methods[] = { {"__reduce__", (PyCFunction)calliter_reduce, METH_NOARGS, "it.__reduce__() -- reduce iterator for pickling"}, {NULL, NULL} /* sentinel */ }; static int init_itertype(void) { return init_type(&PySeqIter_Type, iter_methods, iter_new) || init_type(&PyCallIter_Type, calliter_methods, calliter_new); } /****************************************************** pickling of class/instance methods (PyMethod) ******************************************************/ static PyObject * method_reduce(PyObject * m, PyObject *args) { PyObject *tup, *func, *self, *clas; char *fmt = "(O(OOO))"; int proto = 0; if (!PyArg_ParseTuple(args, "|i:__reduce_ex__", &proto)) return NULL; func = PyMethod_GET_FUNCTION(m); self = PyMethod_GET_SELF(m); clas = PyMethod_GET_CLASS(m); if (self == NULL) self = Py_None; if (clas == NULL) fmt = "(O(OO))"; tup = Py_BuildValue(fmt, &PyMethod_Type, func, self, clas); return tup; } static PyMethodDef method_methods[] = { {"__reduce__", (PyCFunction)method_reduce, METH_VARARGS, PyDoc_STR("meth.__reduce__() -- reduce method for pickling")}, {"__reduce_ex__", (PyCFunction)method_reduce, METH_VARARGS, PyDoc_STR("meth.__reduce_ex__() -- reduce method for pickling")}, {NULL, NULL} }; static int init_methodtype(void) { return init_type(&PyMethod_Type, method_methods, NULL); } /****************************************************** pickling of dictiter ******************************************************/ /* * unfortunately we have to copy here. * XXX automate checking such situations. */ typedef struct { PyObject_HEAD PyDictObject *di_dict; /* Set to NULL when iterator is exhausted */ int di_used; int di_pos; binaryfunc di_select; } dictiterobject; /* binaryfunc is a big problem. we don't have access to the function pointers, so what we have to do is exhaust the dictionary iterator by copying it. when we unpickle, we return an entirely different kind of object. */ static PyObject * dictiterkey_reduce(dictiterobject *di) { PyObject *tup, *list, *key; int i; list = PyList_New(0); if (list == NULL) return PyErr_NoMemory(); /* is this dictiter is already exhausted? */ if (di->di_dict != NULL) { if (di->di_used != di->di_dict->ma_used) { PyErr_SetString(PyExc_RuntimeError, "dictionary changed size during iteration"); di->di_used = -1; /* Make this state sticky */ return NULL; } i = di->di_pos; while (PyDict_Next((PyObject *)di->di_dict, &i, &key, NULL)) { Py_INCREF(key); if (key == NULL) { Py_DECREF(list); return NULL; } if (PyList_Append(list, key) == -1) { return NULL; } } } /* masquerade as a PySeqIter */ tup = Py_BuildValue("(O(lO))", &PySeqIter_Type, 0, list ); Py_DECREF(list); return tup; } static PyObject * dictitervalue_reduce(dictiterobject *di) { PyObject *tup, *list, *value; int i; list = PyList_New(0); if (list == NULL) return PyErr_NoMemory(); /* is this dictiter is already exhausted? */ if (di->di_dict != NULL) { if (di->di_used != di->di_dict->ma_used) { PyErr_SetString(PyExc_RuntimeError, "dictionary changed size during iteration"); di->di_used = -1; /* Make this state sticky */ return NULL; } i = di->di_pos; while (PyDict_Next((PyObject *)di->di_dict, &i, NULL, &value)) { Py_INCREF(value); if (value == NULL) { Py_DECREF(list); return NULL; } if (PyList_Append(list, value) == -1) { return NULL; } } } /* masquerade as a PySeqIter */ tup = Py_BuildValue("(O(lO))", &PySeqIter_Type, 0, list ); Py_DECREF(list); return tup; } static PyObject * dictiteritem_reduce(dictiterobject *di) { PyObject *tup, *list, *key, *value, *res; int i; list = PyList_New(0); if (list == NULL) return PyErr_NoMemory(); /* is this dictiter is already exhausted? */ if (di->di_dict != NULL) { if (di->di_used != di->di_dict->ma_used) { PyErr_SetString(PyExc_RuntimeError, "dictionary changed size during iteration"); di->di_used = -1; /* Make this state sticky */ return NULL; } i = di->di_pos; while (PyDict_Next((PyObject *)di->di_dict, &i, &key, &value)) { res = PyTuple_New(2); if (res != NULL) { Py_INCREF(key); Py_INCREF(value); PyTuple_SET_ITEM(res, 0, key); PyTuple_SET_ITEM(res, 1, value); } if (res == NULL) { Py_DECREF(list); return NULL; } if (PyList_Append(list, res) == -1) { return NULL; } } } /* masquerade as a PySeqIter */ tup = Py_BuildValue("(O(lO))", &PySeqIter_Type, 0, list ); Py_DECREF(list); return tup; } static struct PyMethodDef dictiterkey_methods[] = { {"__reduce__", (PyCFunction)dictiterkey_reduce, METH_NOARGS, "di.__reduce__() -- reduce dictionary-key-iterator for pickling"}, {NULL, NULL} /* Sentinel */ }; static int init_dictiterkeytype(void) { return init_type(&PyDictIterKey_Type, dictiterkey_methods, NULL); } static struct PyMethodDef dictitervalue_methods[] = { {"__reduce__", (PyCFunction)dictitervalue_reduce, METH_NOARGS, "di.__reduce__() -- reduce dictionary-value-iterator for pickling"}, {NULL, NULL} /* Sentinel */ }; static int init_dictitervaluetype(void) { return init_type(&PyDictIterValue_Type, dictitervalue_methods, NULL); } static struct PyMethodDef dictiteritem_methods[] = { {"__reduce__", (PyCFunction)dictiteritem_reduce, METH_NOARGS, "di.__reduce__() -- reduce dictionary-item-iterator for pickling"}, {NULL, NULL} /* Sentinel */ }; static int init_dictiteritemtype(void) { return init_type(&PyDictIterItem_Type, dictiteritem_methods, NULL); } /****************************************************** pickling of enumerate ******************************************************/ static PyObject * enum_reduce(enumobject *en) { PyObject *tup; tup = Py_BuildValue("(O(Ol))", &PyEnumFactory_Type, en->en_sit, en->en_index ); return tup; } static struct PyMethodDef enum_methods[] = { {"__reduce__", (PyCFunction)enum_reduce, METH_NOARGS, "en.__reduce__() -- reduce enumerator for pickling"}, {NULL, NULL} /* Sentinel */ }; static int init_enumtype(void) { return init_type(&PyEnum_Type, enum_methods, NULL); } /****************************************************** pickling of listiter ******************************************************/ /* * unfortunately we have to copy here. * XXX automate checking such situations. */ typedef struct { PyObject_HEAD long it_index; PyListObject *it_seq; /* Set to NULL when iterator is exhausted */ } listiterobject; static PyObject * listiter_reduce(listiterobject *it) { PyObject *tup, *list; /* it's finished or exhausted */ if (it->it_seq == NULL || it->it_index >= PyList_GET_SIZE(it->it_seq)) { list = PyList_New(0); if (list == NULL) return PyErr_NoMemory(); } else { list = PyList_GetSlice( (PyObject *)it->it_seq, it->it_index, PyList_Size((PyObject *)it->it_seq)); } /* masquerade as a PySeqIter */ tup = Py_BuildValue("(O(lO))", &PySeqIter_Type, 0, list ); Py_DECREF(list); return tup; } static struct PyMethodDef listiter_methods[] = { {"__reduce__", (PyCFunction)listiter_reduce, METH_NOARGS, "it.__reduce__() -- reduce listiterator for pickling"}, {NULL, NULL} /* Sentinel */ }; static int init_listitertype(void) { return init_type(&PyListIter_Type, listiter_methods, NULL); } /****************************************************** pickling of rangeiter ******************************************************/ /* * unfortunately we have to copy here. * XXX automate checking such situations. */ typedef struct { PyObject_HEAD long index; long start; long step; long len; } rangeiterobject; static PyObject * rangeiter_reduce(rangeiterobject *it) { PyObject *tup, *typ; assert(it != NULL); typ = PyObject_Type((PyObject *)it); tup = Py_BuildValue("(O(llll))", typ, it->index, it->start, it->step, it->len ); Py_DECREF(typ); return tup; } static PyObject * rangeiter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { rangeiterobject *it; if (kwds != NULL) { PyErr_SetString(PyExc_ValueError, "Keyword parameters not supported for rangeiter_new"); return NULL; } it = PyObject_New(rangeiterobject, type); if (it == NULL) return NULL; if (!PyArg_ParseTuple(args, "iiii:rangeiterator", &it->index, &it->start, &it->step, &it->len)) return NULL; return (PyObject *)it; } static struct PyMethodDef rangeiter_methods[] = { {"__reduce__", (PyCFunction)rangeiter_reduce, METH_NOARGS, "it.__reduce__() -- reduce rangeiterator for pickling"}, {NULL, NULL} /* Sentinel */ }; static int init_rangeitertype(void) { return init_type(&Pyrangeiter_Type, rangeiter_methods, rangeiter_new); } /****************************************************** pickling of tupleiter ******************************************************/ /* * unfortunately we have to copy here. * XXX automate checking such situations. */ typedef struct { PyObject_HEAD long it_index; PyListObject *it_seq; /* Set to NULL when iterator is exhausted */ } tupleiterobject; static PyObject * tupleiter_reduce(tupleiterobject *it) { PyObject *tup, *tuple; /* it's finished or exhausted */ if (it->it_seq == NULL || it->it_index >= PyTuple_GET_SIZE(it->it_seq)) { tuple = PyTuple_New(0); if (tuple == NULL) return PyErr_NoMemory(); } else { tuple = PyTuple_GetSlice( (PyObject *)it->it_seq, it->it_index, PyTuple_Size((PyObject *)it->it_seq)); } /* masquerade as a PySeqIter */ tup = Py_BuildValue("(O(lO))", &PySeqIter_Type, 0, tuple ); Py_DECREF(tuple); return tup; } static struct PyMethodDef tupleiter_methods[] = { {"__reduce__", (PyCFunction)tupleiter_reduce, METH_NOARGS, "it.__reduce__() -- reduce tupleiterator for pickling"}, {NULL, NULL} /* Sentinel */ }; static int init_tupleitertype(void) { return init_type(&PyTupleIter_Type, tupleiter_methods, NULL); } /****************************************************** source module initialization ******************************************************/ int init_prickelpit(void) { if (0 || init_codetype() || init_functype() || init_celltype() || init_frametype() || init_tracebacktype() || init_moduletype() || init_moduledicttype() || init_itertype() || init_methodtype() || init_dictiterkeytype() || init_dictitervaluetype() || init_dictiteritemtype() || init_enumtype() || init_enumfactorytype() || init_listitertype() || init_rangeitertype() || init_tupleitertype() ) return -1; return 0; } #endif