Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(260413)

Delta Between Two Patch Sets: Objects/genobject.c

Issue 11682: PEP 380 reference implementation for 3.3
Left Patch Set: Created 8 years, 1 month ago
Right Patch Set: Created 7 years, 7 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
1 /* Generator object implementation */ 1 /* Generator object implementation */
2 2
3 #include "Python.h" 3 #include "Python.h"
4 #include "frameobject.h" 4 #include "frameobject.h"
5 #include "structmember.h" 5 #include "structmember.h"
6 #include "opcode.h" 6 #include "opcode.h"
7 7
8 static PyObject *gen_close(PyGenObject *gen, PyObject *args); 8 static PyObject *gen_close(PyGenObject *gen, PyObject *args);
Benjamin Peterson 2011/07/09 18:41:14 Why argument names in prototypes for this line but
Nick Coghlan 2011/09/20 13:21:02 Done.
9 static void gen_undelegate(PyGenObject *); 9 static void gen_undelegate(PyGenObject *gen);
10 10
11 static int 11 static int
12 gen_traverse(PyGenObject *gen, visitproc visit, void *arg) 12 gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
13 { 13 {
14 Py_VISIT((PyObject *)gen->gi_frame); 14 Py_VISIT((PyObject *)gen->gi_frame);
15 Py_VISIT(gen->gi_code); 15 Py_VISIT(gen->gi_code);
16 return 0; 16 return 0;
17 } 17 }
18 18
19 static void 19 static void
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
87 87
88 /* Don't keep the reference to f_back any longer than necessary. It 88 /* Don't keep the reference to f_back any longer than necessary. It
89 * may keep a chain of frames alive or it could create a reference 89 * may keep a chain of frames alive or it could create a reference
90 * cycle. */ 90 * cycle. */
91 assert(f->f_back == tstate->frame); 91 assert(f->f_back == tstate->frame);
92 Py_CLEAR(f->f_back); 92 Py_CLEAR(f->f_back);
93 93
94 /* If the generator just returned (as opposed to yielding), signal 94 /* If the generator just returned (as opposed to yielding), signal
95 * that the generator is exhausted. */ 95 * that the generator is exhausted. */
96 if (result && f->f_stacktop == NULL) { 96 if (result && f->f_stacktop == NULL) {
97 if (result == Py_None) 97 if (result == Py_None) {
Benjamin Peterson 2011/07/09 18:41:14 What's the purpose of this special casing? The res
Nick Coghlan 2011/09/20 13:21:02 The special case avoids instantiating the exceptio
98 /* Delay exception instantiation if we can */
98 PyErr_SetNone(PyExc_StopIteration); 99 PyErr_SetNone(PyExc_StopIteration);
99 else { 100 } else {
100 PyObject *e = PyStopIteration_New(result); 101 PyObject *e = PyStopIteration_Create(result);
Benjamin Peterson 2011/07/09 18:41:14 What if e is NULL? You don't want to override the
Nick Coghlan 2011/09/20 13:21:02 Done.
101 PyErr_SetObject(PyExc_StopIteration, e); 102 if (e != NULL) {
102 } 103 PyErr_SetObject(PyExc_StopIteration, e);
103 Py_DECREF(result); 104 Py_DECREF(e);
104 result = NULL; 105 }
106 }
107 Py_CLEAR(result);
105 } 108 }
106 109
107 if (!result || f->f_stacktop == NULL) { 110 if (!result || f->f_stacktop == NULL) {
108 /* generator can't be rerun, so release the frame */ 111 /* generator can't be rerun, so release the frame */
112 /* first clean reference cycle through stored exception traceback */
113 PyObject *t, *v, *tb;
114 t = f->f_exc_type;
115 v = f->f_exc_value;
116 tb = f->f_exc_traceback;
117 f->f_exc_type = NULL;
118 f->f_exc_value = NULL;
119 f->f_exc_traceback = NULL;
120 Py_XDECREF(t);
121 Py_XDECREF(v);
122 Py_XDECREF(tb);
123 gen->gi_frame = NULL;
109 Py_DECREF(f); 124 Py_DECREF(f);
110 gen->gi_frame = NULL;
111 } 125 }
112 126
113 return result; 127 return result;
114 } 128 }
115 129
116 PyDoc_STRVAR(send_doc, 130 PyDoc_STRVAR(send_doc,
117 "send(arg) -> send 'arg' into generator,\n\ 131 "send(arg) -> send 'arg' into generator,\n\
118 return next yielded value or raise StopIteration."); 132 return next yielded value or raise StopIteration.");
119 133
120 static PyObject * 134 static PyObject *
121 gen_send(PyGenObject *gen, PyObject *arg) 135 gen_send(PyGenObject *gen, PyObject *arg)
122 { 136 {
123 int exc = 0; 137 int exc = 0;
124 PyObject *ret; 138 PyObject *ret;
125 PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL; 139 PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL;
140 /* XXX (ncoghlan): Are the incref/decref on arg and yf strictly needed?
141 * Or would it be valid to rely on borrowed references?
142 */
126 Py_INCREF(arg); 143 Py_INCREF(arg);
127 if (yf) { 144 if (yf) {
128 Py_INCREF(yf); 145 Py_INCREF(yf);
Benjamin Peterson 2011/07/09 18:41:14 Somewhere there should be a comment about why you
Nick Coghlan 2011/09/20 13:21:02 Hmm, I'm not sure about that one. I've added a com
129 if (PyGen_CheckExact(yf)) 146 if (PyGen_CheckExact(yf)) {
130 ret = gen_send((PyGenObject *)yf, arg); 147 ret = gen_send((PyGenObject *)yf, arg);
131 else { 148 } else {
132 if (arg == Py_None) 149 if (arg == Py_None)
133 ret = PyIter_Next(yf); 150 ret = PyIter_Next(yf);
134 else 151 else
135 ret = PyObject_CallMethod(yf, "send", "O", arg); 152 ret = PyObject_CallMethod(yf, "send", "O", arg);
136 } 153 }
137 if (ret) { 154 if (ret) {
138 Py_DECREF(yf); 155 Py_DECREF(yf);
139 goto done; 156 goto done;
140 } 157 }
141 gen_undelegate(gen); 158 gen_undelegate(gen);
142 Py_DECREF(arg); 159 Py_CLEAR(arg);
143 arg = NULL; 160 if (PyGen_FetchStopIterationValue(&arg) < 0) {
144 if (PyGen_FetchStopIterationValue(&arg) < 0)
145 exc = 1; 161 exc = 1;
162 }
146 Py_DECREF(yf); 163 Py_DECREF(yf);
147 } 164 }
148 ret = gen_send_ex(gen, arg, exc); 165 ret = gen_send_ex(gen, arg, exc);
149 done: 166 done:
150 Py_XDECREF(arg); 167 Py_XDECREF(arg);
151 return ret; 168 return ret;
152 } 169 }
153 170
154 PyDoc_STRVAR(close_doc, 171 PyDoc_STRVAR(close_doc,
155 "close(arg) -> raise GeneratorExit inside generator."); 172 "close(arg) -> raise GeneratorExit inside generator.");
156 173
157 /* 174 /*
158 * This helper function is used by gen_close and gen_throw to 175 * This helper function is used by gen_close and gen_throw to
159 * close a subiterator being delegated to by yield-from. 176 * close a subiterator being delegated to by yield-from.
160 */ 177 */
161 178
162 static int 179 static int
163 gen_close_iter(PyObject *yf) { 180 gen_close_iter(PyObject *yf)
Benjamin Peterson 2011/07/09 18:41:14 The brace should be on the next line.
181 {
164 PyObject *retval = NULL; 182 PyObject *retval = NULL;
165 183
166 if (PyGen_CheckExact(yf)) { 184 if (PyGen_CheckExact(yf)) {
167 retval = gen_close((PyGenObject *)yf, NULL); 185 retval = gen_close((PyGenObject *)yf, NULL);
168 if (!retval) 186 if (retval == NULL) {
169 return -1; 187 return -1;
170 } 188 }
171 else { 189 } else {
172 PyObject *meth = PyObject_GetAttrString(yf, "close"); 190 PyObject *meth = PyObject_GetAttrString(yf, "close");
Benjamin Peterson 2011/07/09 18:41:14 How about just using PyObject_CallMethodObjArgs(yf
Nick Coghlan 2011/09/20 13:21:02 Done.
173 if (meth) { 191 if (meth == NULL) {
192 if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
193 PyErr_WriteUnraisable(yf);
194 }
195 PyErr_Clear();
196 } else {
174 retval = PyObject_CallFunction(meth, ""); 197 retval = PyObject_CallFunction(meth, "");
175 Py_DECREF(meth); 198 Py_DECREF(meth);
176 if (!retval) 199 if (!retval)
177 return -1; 200 return -1;
178 } 201 }
179 } 202 }
180 Py_XDECREF(retval); 203 Py_XDECREF(retval);
181 return 0; 204 return 0;
182 } 205 }
183 206
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
249 return; /* this is the normal path out */ 272 return; /* this is the normal path out */
250 273
251 /* close() resurrected it! Make it look like the original Py_DECREF 274 /* close() resurrected it! Make it look like the original Py_DECREF
252 * never happened. 275 * never happened.
253 */ 276 */
254 { 277 {
255 Py_ssize_t refcnt = self->ob_refcnt; 278 Py_ssize_t refcnt = self->ob_refcnt;
256 _Py_NewReference(self); 279 _Py_NewReference(self);
257 self->ob_refcnt = refcnt; 280 self->ob_refcnt = refcnt;
258 } 281 }
259 assert(PyType_IS_GC(self->ob_type) && 282 assert(PyType_IS_GC(Py_TYPE(self)) &&
260 _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED); 283 _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED);
261 284
262 /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so 285 /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so
263 * we need to undo that. */ 286 * we need to undo that. */
264 _Py_DEC_REFTOTAL; 287 _Py_DEC_REFTOTAL;
265 /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object 288 /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object
266 * chain, so no more to do there. 289 * chain, so no more to do there.
267 * If COUNT_ALLOCS, the original decref bumped tp_frees, and 290 * If COUNT_ALLOCS, the original decref bumped tp_frees, and
268 * _Py_NewReference bumped tp_allocs: both of those need to be 291 * _Py_NewReference bumped tp_allocs: both of those need to be
269 * undone. 292 * undone.
270 */ 293 */
271 #ifdef COUNT_ALLOCS 294 #ifdef COUNT_ALLOCS
272 --self->ob_type->tp_frees; 295 --(Py_TYPE(self)->tp_frees);
273 --self->ob_type->tp_allocs; 296 --(Py_TYPE(self)->tp_allocs);
274 #endif 297 #endif
275 } 298 }
276 299
277 300
278 301
279 PyDoc_STRVAR(throw_doc, 302 PyDoc_STRVAR(throw_doc,
280 "throw(typ[,val[,tb]]) -> raise exception in generator,\n\ 303 "throw(typ[,val[,tb]]) -> raise exception in generator,\n\
281 return next yielded value or raise StopIteration."); 304 return next yielded value or raise StopIteration.");
282 305
283 static PyObject * 306 static PyObject *
(...skipping 12 matching lines...) Expand all
296 int err; 319 int err;
297 Py_INCREF(yf); 320 Py_INCREF(yf);
298 if (PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit)) { 321 if (PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit)) {
299 err = gen_close_iter(yf); 322 err = gen_close_iter(yf);
300 Py_DECREF(yf); 323 Py_DECREF(yf);
301 gen_undelegate(gen); 324 gen_undelegate(gen);
302 if (err < 0) 325 if (err < 0)
303 return gen_send_ex(gen, Py_None, 1); 326 return gen_send_ex(gen, Py_None, 1);
304 goto throw_here; 327 goto throw_here;
305 } 328 }
306 if (PyGen_CheckExact(yf)) 329 if (PyGen_CheckExact(yf)) {
307 ret = gen_throw((PyGenObject *)yf, args); 330 ret = gen_throw((PyGenObject *)yf, args);
308 else { 331 } else {
309 PyObject *meth = PyObject_GetAttrString(yf, "throw"); 332 PyObject *meth = PyObject_GetAttrString(yf, "throw");
310 if (!meth) { 333 if (meth == NULL) {
Benjamin Peterson 2011/07/09 18:41:14 We're not going to check if it's an AttributeError
Nick Coghlan 2011/09/20 13:21:02 Done.
334 if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
335 Py_DECREF(yf);
336 return NULL;
337 }
311 PyErr_Clear(); 338 PyErr_Clear();
312 Py_DECREF(yf); 339 Py_DECREF(yf);
313 gen_undelegate(gen); 340 gen_undelegate(gen);
314 goto throw_here; 341 goto throw_here;
315 } 342 }
316 ret = PyObject_CallObject(meth, args); 343 ret = PyObject_CallObject(meth, args);
317 Py_DECREF(meth); 344 Py_DECREF(meth);
318 } 345 }
319 Py_DECREF(yf); 346 Py_DECREF(yf);
320 if (!ret) { 347 if (!ret) {
321 PyObject *val; 348 PyObject *val;
322 gen_undelegate(gen); 349 gen_undelegate(gen);
323 if (PyGen_FetchStopIterationValue(&val) == 0) { 350 if (PyGen_FetchStopIterationValue(&val) == 0) {
324 ret = gen_send_ex(gen, val, 0); 351 ret = gen_send_ex(gen, val, 0);
325 Py_DECREF(val); 352 Py_DECREF(val);
353 } else {
354 ret = gen_send_ex(gen, Py_None, 1);
326 } 355 }
327 else
Benjamin Peterson 2011/07/09 18:41:14 Need braces here.
Nick Coghlan 2011/09/20 13:21:02 Done.
328 ret = gen_send_ex(gen, Py_None, 1);
329 } 356 }
330 return ret; 357 return ret;
331 } 358 }
332 359
333 throw_here: 360 throw_here:
334 /* First, check the traceback argument, replacing None with 361 /* First, check the traceback argument, replacing None with
335 NULL. */ 362 NULL. */
336 if (tb == Py_None) 363 if (tb == Py_None) {
337 tb = NULL; 364 tb = NULL;
365 }
338 else if (tb != NULL && !PyTraceBack_Check(tb)) { 366 else if (tb != NULL && !PyTraceBack_Check(tb)) {
339 PyErr_SetString(PyExc_TypeError, 367 PyErr_SetString(PyExc_TypeError,
340 "throw() third argument must be a traceback object"); 368 "throw() third argument must be a traceback object");
341 return NULL; 369 return NULL;
342 } 370 }
343 371
344 Py_INCREF(typ); 372 Py_INCREF(typ);
345 Py_XINCREF(val); 373 Py_XINCREF(val);
346 Py_XINCREF(tb); 374 Py_XINCREF(tb);
347 375
348 if (PyExceptionClass_Check(typ)) { 376 if (PyExceptionClass_Check(typ))
349 PyErr_NormalizeException(&typ, &val, &tb); 377 PyErr_NormalizeException(&typ, &val, &tb);
350 }
351 378
352 else if (PyExceptionInstance_Check(typ)) { 379 else if (PyExceptionInstance_Check(typ)) {
353 /* Raising an instance. The value should be a dummy. */ 380 /* Raising an instance. The value should be a dummy. */
354 if (val && val != Py_None) { 381 if (val && val != Py_None) {
355 PyErr_SetString(PyExc_TypeError, 382 PyErr_SetString(PyExc_TypeError,
356 "instance exception may not have a separate value"); 383 "instance exception may not have a separate value");
357 goto failed_throw; 384 goto failed_throw;
358 } 385 }
359 else { 386 else {
360 /* Normalize to raise <class>, <instance> */ 387 /* Normalize to raise <class>, <instance> */
361 Py_XDECREF(val); 388 Py_XDECREF(val);
362 val = typ; 389 val = typ;
363 typ = PyExceptionInstance_Class(typ); 390 typ = PyExceptionInstance_Class(typ);
364 Py_INCREF(typ); 391 Py_INCREF(typ);
392
393 if (tb == NULL)
394 /* Returns NULL if there's no traceback */
395 tb = PyException_GetTraceback(val);
365 } 396 }
366 } 397 }
367 else { 398 else {
368 /* Not something you can raise. throw() fails. */ 399 /* Not something you can raise. throw() fails. */
369 PyErr_Format(PyExc_TypeError, 400 PyErr_Format(PyExc_TypeError,
370 "exceptions must be classes or instances " 401 "exceptions must be classes or instances "
371 "deriving from BaseException, not %s", 402 "deriving from BaseException, not %s",
372 typ->ob_type->tp_name); 403 Py_TYPE(typ)->tp_name);
373 goto failed_throw; 404 goto failed_throw;
374 } 405 }
375 406
376 PyErr_Restore(typ, val, tb); 407 PyErr_Restore(typ, val, tb);
377 return gen_send_ex(gen, Py_None, 1); 408 return gen_send_ex(gen, Py_None, 1);
378 409
379 failed_throw: 410 failed_throw:
380 /* Didn't use our arguments, so restore their original refcounts */ 411 /* Didn't use our arguments, so restore their original refcounts */
381 Py_DECREF(typ); 412 Py_DECREF(typ);
382 Py_XDECREF(val); 413 Py_XDECREF(val);
383 Py_XDECREF(tb); 414 Py_XDECREF(tb);
384 return NULL; 415 return NULL;
385 } 416 }
386 417
387 418
388 static PyObject * 419 static PyObject *
389 gen_iternext(PyGenObject *gen) 420 gen_iternext(PyGenObject *gen)
390 { 421 {
391 PyObject *val = NULL; 422 PyObject *val = NULL;
392 PyObject *ret; 423 PyObject *ret;
393 int exc = 0; 424 int exc = 0;
394 PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL; 425 PyObject *yf = gen->gi_frame ? gen->gi_frame->f_yieldfrom : NULL;
395 if (yf) { 426 if (yf) {
396 Py_INCREF(yf); 427 Py_INCREF(yf);
397 /* ceval.c ensures that yf is an iterator */ 428 /* ceval.c ensures that yf is an iterator */
398 ret = yf->ob_type->tp_iternext(yf); 429 ret = Py_TYPE(yf)->tp_iternext(yf);
Benjamin Peterson 2011/07/09 18:41:14 Py_TYPE please.
Nick Coghlan 2011/09/20 13:21:02 Done.
399 if (ret) { 430 if (ret) {
400 Py_DECREF(yf); 431 Py_DECREF(yf);
401 return ret; 432 return ret;
402 } 433 }
403 gen_undelegate(gen); 434 gen_undelegate(gen);
404 if (PyGen_FetchStopIterationValue(&val) < 0) 435 if (PyGen_FetchStopIterationValue(&val) < 0)
405 exc = 1; 436 exc = 1;
406 Py_DECREF(yf); 437 Py_DECREF(yf);
407 } 438 }
408 ret = gen_send_ex(gen, val, exc); 439 ret = gen_send_ex(gen, val, exc);
(...skipping 24 matching lines...) Expand all
433 * pvalue unchanged. 464 * pvalue unchanged.
434 */ 465 */
435 466
436 int 467 int
437 PyGen_FetchStopIterationValue(PyObject **pvalue) { 468 PyGen_FetchStopIterationValue(PyObject **pvalue) {
438 PyObject *et, *ev, *tb; 469 PyObject *et, *ev, *tb;
439 PyObject *value = NULL; 470 PyObject *value = NULL;
440 471
441 if (PyErr_ExceptionMatches(PyExc_StopIteration)) { 472 if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
442 PyErr_Fetch(&et, &ev, &tb); 473 PyErr_Fetch(&et, &ev, &tb);
443 Py_XDECREF(et); Py_XDECREF(tb); 474 Py_XDECREF(et);
Benjamin Peterson 2011/07/09 18:41:14 Put on separate lines.
Nick Coghlan 2011/09/20 13:21:02 Done.
475 Py_XDECREF(tb);
444 if (ev) { 476 if (ev) {
445 value = ((PyStopIterationObject *)ev)->value; 477 value = ((PyStopIterationObject *)ev)->value;
446 Py_XINCREF(value);
447 Py_DECREF(ev); 478 Py_DECREF(ev);
448 } 479 }
449 } 480 } else if (PyErr_Occurred()) {
450 else if (PyErr_Occurred())
451 return -1; 481 return -1;
452 if (!value) { 482 }
483 if (value == NULL) {
453 value = Py_None; 484 value = Py_None;
454 Py_INCREF(value); 485 }
Benjamin Peterson 2011/07/09 18:41:14 You could move this out after the if condition and
Nick Coghlan 2011/09/20 13:21:02 Done.
455 } 486 Py_INCREF(value);
456 *pvalue = value; 487 *pvalue = value;
457 return 0; 488 return 0;
458 } 489 }
459 490
460 static PyObject * 491 static PyObject *
461 gen_repr(PyGenObject *gen) 492 gen_repr(PyGenObject *gen)
462 { 493 {
463 return PyUnicode_FromFormat("<generator object %S at %p>", 494 return PyUnicode_FromFormat("<generator object %S at %p>",
464 ((PyCodeObject *)gen->gi_code)->co_name, 495 ((PyCodeObject *)gen->gi_code)->co_name,
465 gen); 496 gen);
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
576 return 0; /* no frame or empty blockstack == no finalization */ 607 return 0; /* no frame or empty blockstack == no finalization */
577 608
578 /* Any block type besides a loop requires cleanup. */ 609 /* Any block type besides a loop requires cleanup. */
579 for (i = 0; i < f->f_iblock; i++) 610 for (i = 0; i < f->f_iblock; i++)
580 if (f->f_blockstack[i].b_type != SETUP_LOOP) 611 if (f->f_blockstack[i].b_type != SETUP_LOOP)
581 return 1; 612 return 1;
582 613
583 /* No blocks except loops, it's safe to skip finalization. */ 614 /* No blocks except loops, it's safe to skip finalization. */
584 return 0; 615 return 0;
585 } 616 }
LEFTRIGHT

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+