Skip to content

Commit ca584d5

Browse files
author
Anselm Kruis
committed
merge 3.3-slp (Stackless python#111)
2 parents dec0d83 + 380bd7a commit ca584d5

File tree

6 files changed

+75
-63
lines changed

6 files changed

+75
-63
lines changed

Include/genobject.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@ PyAPI_DATA(PyTypeObject) PyGen_Type;
3333
#define PyGen_CheckExact(op) (Py_TYPE(op) == &PyGen_Type)
3434

3535
PyAPI_FUNC(PyObject *) PyGen_New(struct _frame *);
36-
#ifdef STACKLESS
37-
#define PyGen_New PyGenerator_New
38-
#endif
3936
PyAPI_FUNC(int) PyGen_NeedsFinalizing(PyGenObject *);
4037
PyAPI_FUNC(int) _PyGen_FetchStopIterationValue(PyObject **);
4138
PyObject *_PyGen_Send(PyGenObject *, PyObject *);

Objects/genobject.c

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -518,13 +518,8 @@ PyTypeObject PyGen_Type = {
518518

519519
STACKLESS_DECLARE_METHOD(&PyGen_Type, tp_iternext);
520520

521-
#ifdef STACKLESS
522-
PyObject *
523-
PyGenerator_New(PyFrameObject *f)
524-
#else
525521
PyObject *
526522
PyGen_New(PyFrameObject *f)
527-
#endif
528523
{
529524
PyGenObject *gen = PyObject_GC_New(PyGenObject, &PyGen_Type);
530525
if (gen == NULL) {
@@ -533,19 +528,8 @@ PyGen_New(PyFrameObject *f)
533528
}
534529
gen->gi_frame = f;
535530
f->f_gen = (PyObject *) gen;
536-
#ifdef STACKLESS
537-
/* Support for unpickling generators. This will segmentation fault if
538-
called by pricklepit.c:gen_new as that passes Py_None as a placeholder. */
539-
if ((PyObject*)f == Py_None) {
540-
Py_INCREF(Py_None);
541-
gen->gi_code = Py_None;
542-
} else {
543-
#endif
544531
Py_INCREF(f->f_code);
545532
gen->gi_code = (PyObject *)(f->f_code);
546-
#ifdef STACKLESS
547-
}
548-
#endif
549533
gen->gi_running = 0;
550534
gen->gi_weakreflist = NULL;
551535
_PyObject_GC_TRACK(gen);

Stackless/changelog.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ What's New in Stackless 3.X.X?
99

1010
*Release date: 20XX-XX-XX*
1111

12+
- https://bitbucket.org/stackless-dev/stackless/issues/111
13+
Restore the Python ABI function PyGen_New(). Previously Stackless named this
14+
function PyGenerator_New() and used a macro the redefine PyGen_New as
15+
PyGenerator_New. Stackless is now again binary compatible with Python-
16+
extensions using PyGen_New().
17+
1218
- https://bitbucket.org/stackless-dev/stackless/issues/107
1319
Improve unpickling of traceback objects. Stackless now reconstructs the
1420
frame.f_back linkage in frames directly referenced by traceback objects.

Stackless/core/stackless_impl.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,7 @@ struct _frame * slp_clone_frame(struct _frame *f);
128128
struct _frame * slp_ensure_new_frame(struct _frame *f);
129129

130130
/* exposing some hidden types */
131-
132-
PyAPI_DATA(PyTypeObject) PyGen_Type;
133-
PyAPI_FUNC(PyObject *) PyGenerator_New(struct _frame *f);
134131
PyObject * slp_gen_send_ex(PyGenObject *gen, PyObject *arg, int exc);
135-
#define PyGenerator_Check(op) PyObject_TypeCheck(op, &PyGen_Type)
136132

137133
PyAPI_DATA(PyTypeObject) PyMethodDescr_Type;
138134
PyAPI_DATA(PyTypeObject) PyClassMethodDescr_Type;

Stackless/pickling/prickelpit.c

Lines changed: 51 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2232,29 +2232,12 @@ static int init_methodwrappertype(void)
22322232
22332233
******************************************************/
22342234

2235-
/* Note: this definition is not compatible to 2.2.3, since
2236-
the gi_weakreflist does not exist. Therefore, we don't
2237-
create the object ourselves, but use the provided function
2238-
with a fake frame. The gi_weakreflist is not touched.
2239-
*/
2240-
2241-
typedef struct {
2242-
PyObject_HEAD
2243-
/* The gi_ prefix is intended to remind of generator-iterator. */
2244-
2245-
PyFrameObject *gi_frame;
2246-
2247-
/* True if generator is being executed. */
2248-
char gi_running;
2249-
2250-
/* List of weak reference. */
2251-
PyObject *gi_weakreflist;
2252-
} genobject;
2253-
22542235
static PyTypeObject wrap_PyGen_Type;
2236+
/* Used to initialize a generator created by gen_new. */
2237+
static PyFrameObject *gen_exhausted_frame;
22552238

22562239
static PyObject *
2257-
gen_reduce(genobject *gen)
2240+
gen_reduce(PyGenObject *gen)
22582241
{
22592242
PyObject *tup;
22602243
tup = Py_BuildValue("(O()(Oi))",
@@ -2268,11 +2251,13 @@ gen_reduce(genobject *gen)
22682251
static PyObject *
22692252
gen_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
22702253
{
2271-
genobject *gen;
2272-
2254+
PyGenObject *gen;
22732255
if (is_wrong_type(type)) return NULL;
2274-
Py_INCREF(Py_None);
2275-
gen = (genobject *) PyGenerator_New((PyFrameObject *) Py_None);
2256+
2257+
/* A reference to frame is stolen by PyGen_New. */
2258+
assert(gen_exhausted_frame != NULL);
2259+
assert(PyFrame_Check(gen_exhausted_frame));
2260+
gen = (PyGenObject *) PyGen_New(slp_ensure_new_frame(gen_exhausted_frame));
22762261
if (gen == NULL)
22772262
return NULL;
22782263
Py_TYPE(gen) = type;
@@ -2282,7 +2267,7 @@ gen_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
22822267
static PyObject *
22832268
gen_setstate(PyObject *self, PyObject *args)
22842269
{
2285-
genobject *gen = (genobject *) self;
2270+
PyGenObject *gen = (PyGenObject *) self;
22862271
PyFrameObject *f;
22872272
int gi_running;
22882273

@@ -2294,16 +2279,17 @@ gen_setstate(PyObject *self, PyObject *args)
22942279
if (!gi_running) {
22952280
if ((f = slp_ensure_new_frame(f)) != NULL) {
22962281
/* use a second one for late initialization */
2297-
genobject *tmpgen;
2282+
PyGenObject *tmpgen;
22982283
/* PyGenerator_New eats an existing reference */
2299-
if ((tmpgen = (genobject *)
2300-
PyGenerator_New(f)) == NULL) {
2284+
if ((tmpgen = (PyGenObject *)
2285+
PyGen_New(f)) == NULL) {
23012286
Py_DECREF(f);
23022287
return NULL;
23032288
}
23042289
Py_INCREF(f);
2305-
Py_CLEAR(gen->gi_frame);
2306-
gen->gi_frame = f;
2290+
Py_SETREF(gen->gi_frame, f);
2291+
Py_INCREF(f->f_code);
2292+
Py_SETREF(gen->gi_code, (PyObject *)f->f_code);
23072293
/* The frame the temporary generator references
23082294
will have GeneratorExit raised on it, when the
23092295
temporary generator is torn down. So clearing
@@ -2327,8 +2313,9 @@ gen_setstate(PyObject *self, PyObject *args)
23272313
* generator without the corresponding tasklet.
23282314
*/
23292315
Py_INCREF(f);
2330-
Py_CLEAR(gen->gi_frame);
2331-
gen->gi_frame = f;
2316+
Py_SETREF(gen->gi_frame, f);
2317+
Py_INCREF(f->f_code);
2318+
Py_SETREF(gen->gi_code, (PyObject *)f->f_code);
23322319
gen->gi_running = gi_running;
23332320
Py_TYPE(gen) = Py_TYPE(gen)->tp_base;
23342321
Py_INCREF(gen);
@@ -2343,10 +2330,10 @@ DEF_INVALID_EXEC(gen_iternext_callback)
23432330
static int init_generatortype(void)
23442331
{
23452332
int res;
2346-
genobject *gen = (genobject *) run_script(
2347-
"def f(): yield 42\n" /* define a generator */
2348-
"g = f()\n" /* instanciate it */
2349-
"g.__next__()\n", "g"); /* force callback frame creation */
2333+
PyGenObject *gen = (PyGenObject *) run_script(
2334+
"def exhausted_generator(): yield 42\n" /* define a generator */
2335+
"g = exhausted_generator()\n" /* instanciate it */
2336+
"g.__next__()\n", "g"); /* force callback frame creation */
23502337
PyFrameObject *cbframe;
23512338

23522339
if (gen == NULL || gen->gi_frame->f_back == NULL)
@@ -2356,6 +2343,13 @@ static int init_generatortype(void)
23562343
gen->gi_frame->f_back->f_execute,
23572344
REF_INVALID_EXEC(gen_iternext_callback))
23582345
|| init_type(&wrap_PyGen_Type, initchain);
2346+
2347+
assert(gen_exhausted_frame == NULL);
2348+
gen_exhausted_frame = slp_ensure_new_frame(gen->gi_frame);
2349+
if (gen_exhausted_frame == NULL) {
2350+
return -1;
2351+
}
2352+
23592353
Py_DECREF(gen);
23602354
return res;
23612355
}
@@ -2458,23 +2452,36 @@ slp_pickle_moduledict(PyObject *self, PyObject *args)
24582452
source module initialization
24592453
24602454
******************************************************/
2455+
static int
2456+
_wrapmodule_traverse(PyObject *self, visitproc visit, void *arg)
2457+
{
2458+
Py_VISIT(gen_exhausted_frame);
2459+
return 0;
2460+
}
2461+
2462+
static int
2463+
_wrapmodule_clear(PyObject *self)
2464+
{
2465+
Py_CLEAR(gen_exhausted_frame);
2466+
return 0;
2467+
}
2468+
24612469
static struct PyModuleDef _wrapmodule = {
24622470
PyModuleDef_HEAD_INIT,
24632471
"_stackless._wrap",
24642472
NULL,
24652473
-1,
24662474
NULL,
24672475
NULL,
2468-
NULL,
2469-
NULL,
2476+
_wrapmodule_traverse,
2477+
_wrapmodule_clear,
24702478
NULL
24712479
};
24722480

24732481
PyObject*
24742482
init_prickelpit(void)
24752483
{
24762484
PyObject *copy_reg, *tmp;
2477-
int ret = 0;
24782485

24792486
types_mod = PyModule_Create(&_wrapmodule);
24802487
if (types_mod == NULL)
@@ -2491,7 +2498,11 @@ init_prickelpit(void)
24912498
Py_CLEAR(types_mod);
24922499
return NULL;
24932500
}
2494-
ret = initchain();
2501+
if (initchain()) {
2502+
Py_CLEAR(pickle_reg);
2503+
Py_CLEAR(types_mod);
2504+
return NULL;
2505+
}
24952506
Py_CLEAR(pickle_reg);
24962507
tmp = types_mod;
24972508
types_mod = NULL;

Stackless/unittests/test_generator.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import unittest
22
import gc
33
import stackless
4+
import types
45

56
from support import StacklessTestCase
67

@@ -31,5 +32,22 @@ def testSimpleLeakage(self):
3132
if len(leakage):
3233
self.failUnless(len(leakage) == 0, "Leaked %s" % repr(leakage))
3334

35+
36+
class TestGeneratorWrapper(StacklessTestCase):
37+
def test_run_wrap_generator(self):
38+
g = stackless._wrap.generator()
39+
self.assertIsInstance(g, types.GeneratorType)
40+
self.assertIsNot(type(g), types.GeneratorType)
41+
self.assertRaises(StopIteration, next, g)
42+
43+
def test_wrap_generator_frame_code(self):
44+
g0 = stackless._wrap.generator()
45+
g1 = stackless._wrap.generator()
46+
self.assertIsInstance(g0.gi_frame, types.FrameType)
47+
self.assertIsInstance(g0.gi_code, types.CodeType)
48+
self.assertIs(g0.gi_code, g1.gi_code)
49+
self.assertIsNot(g0.gi_frame, g1.gi_frame)
50+
self.assertEqual(g0.__name__, "exhausted_generator")
51+
3452
if __name__ == '__main__':
3553
unittest.main()

0 commit comments

Comments
 (0)