Skip to content

Commit 5d997b5

Browse files
authored
[3.12] gh-119897: Revert buggy optimization which was removed in 3.13 (#120467)
1 parent 4b53ea8 commit 5d997b5

File tree

6 files changed

+18
-43
lines changed

6 files changed

+18
-43
lines changed

Include/internal/pycore_frame.h

-3
Original file line numberDiff line numberDiff line change
@@ -213,9 +213,6 @@ _PyFrame_GetFrameObject(_PyInterpreterFrame *frame)
213213
return _PyFrame_MakeAndSetFrameObject(frame);
214214
}
215215

216-
void
217-
_PyFrame_ClearLocals(_PyInterpreterFrame *frame);
218-
219216
/* Clears all references in the frame.
220217
* If take is non-zero, then the _PyInterpreterFrame frame
221218
* may be transferred to the frame object it references

Lib/test/test_cprofile.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ def test_throw(self):
8383

8484
for func, (cc, nc, _, _, _) in pr.stats.items():
8585
if func[2] == "<genexpr>":
86-
self.assertEqual(cc, 1)
87-
self.assertEqual(nc, 1)
86+
self.assertEqual(cc, 2)
87+
self.assertEqual(nc, 2)
8888

8989

9090
class TestCommandLine(unittest.TestCase):

Lib/test/test_generators.py

+5-21
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import unittest
77
import weakref
88
import inspect
9+
import types
910

1011
from test import support
1112

@@ -89,9 +90,12 @@ def gen():
8990
self.assertEqual(gc.garbage, old_garbage)
9091

9192
def test_lambda_generator(self):
92-
# Issue #23192: Test that a lambda returning a generator behaves
93+
# bpo-23192, gh-119897: Test that a lambda returning a generator behaves
9394
# like the equivalent function
9495
f = lambda: (yield 1)
96+
self.assertIsInstance(f(), types.GeneratorType)
97+
self.assertEqual(next(f()), 1)
98+
9599
def g(): return (yield 1)
96100

97101
# test 'yield from'
@@ -450,26 +454,6 @@ def g():
450454
self.assertIsInstance(cm.exception.value, StopIteration)
451455
self.assertEqual(cm.exception.value.value, 2)
452456

453-
def test_close_releases_frame_locals(self):
454-
# See gh-118272
455-
456-
class Foo:
457-
pass
458-
459-
f = Foo()
460-
f_wr = weakref.ref(f)
461-
462-
def genfn():
463-
a = f
464-
yield
465-
466-
g = genfn()
467-
next(g)
468-
del f
469-
g.close()
470-
support.gc_collect()
471-
self.assertIsNone(f_wr())
472-
473457

474458
class GeneratorThrowTest(unittest.TestCase):
475459

Lib/test/test_sys_setprofile.py

+4
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ def g(p):
265265
f_ident = ident(f)
266266
g_ident = ident(g)
267267
self.check_events(g, [(1, 'call', g_ident),
268+
(2, 'call', f_ident),
269+
(2, 'return', f_ident),
270+
# once more; the generator is being garbage collected
271+
# and it will do a PY_THROW
268272
(2, 'call', f_ident),
269273
(2, 'return', f_ident),
270274
(1, 'return', g_ident),

Objects/genobject.c

+2-4
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ static PyObject *
374374
gen_close(PyGenObject *gen, PyObject *args)
375375
{
376376
PyObject *retval;
377+
PyObject *yf = _PyGen_yf(gen);
377378
int err = 0;
378379

379380
if (gen->gi_frame_state == FRAME_CREATED) {
@@ -383,7 +384,6 @@ gen_close(PyGenObject *gen, PyObject *args)
383384
if (gen->gi_frame_state >= FRAME_COMPLETED) {
384385
Py_RETURN_NONE;
385386
}
386-
PyObject *yf = _PyGen_yf(gen);
387387
if (yf) {
388388
PyFrameState state = gen->gi_frame_state;
389389
gen->gi_frame_state = FRAME_EXECUTING;
@@ -396,14 +396,12 @@ gen_close(PyGenObject *gen, PyObject *args)
396396
* YIELD_VALUE if the debugger has changed the lineno. */
397397
if (err == 0 && is_yield(frame->prev_instr)) {
398398
assert(is_resume(frame->prev_instr + 1));
399-
int exception_handler_depth = frame->prev_instr[0].op.arg;
399+
int exception_handler_depth = frame->prev_instr[0].op.code;
400400
assert(exception_handler_depth > 0);
401401
/* We can safely ignore the outermost try block
402402
* as it automatically generated to handle
403403
* StopIteration. */
404404
if (exception_handler_depth == 1) {
405-
gen->gi_frame_state = FRAME_COMPLETED;
406-
_PyFrame_ClearLocals((_PyInterpreterFrame *)gen->gi_iframe);
407405
Py_RETURN_NONE;
408406
}
409407
}

Python/frame.c

+5-13
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,6 @@ take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame)
115115
}
116116
}
117117

118-
void
119-
_PyFrame_ClearLocals(_PyInterpreterFrame *frame)
120-
{
121-
assert(frame->stacktop >= 0);
122-
int stacktop = frame->stacktop;
123-
frame->stacktop = 0;
124-
for (int i = 0; i < stacktop; i++) {
125-
Py_XDECREF(frame->localsplus[i]);
126-
}
127-
Py_CLEAR(frame->f_locals);
128-
}
129-
130118
void
131119
_PyFrame_ClearExceptCode(_PyInterpreterFrame *frame)
132120
{
@@ -147,8 +135,12 @@ _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame)
147135
}
148136
Py_DECREF(f);
149137
}
150-
_PyFrame_ClearLocals(frame);
138+
assert(frame->stacktop >= 0);
139+
for (int i = 0; i < frame->stacktop; i++) {
140+
Py_XDECREF(frame->localsplus[i]);
141+
}
151142
Py_XDECREF(frame->frame_obj);
143+
Py_XDECREF(frame->f_locals);
152144
Py_DECREF(frame->f_funcobj);
153145
}
154146

0 commit comments

Comments
 (0)