This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author anselm.kruis
Recipients anselm.kruis
Date 2017-10-21.11:14:04
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1508584444.52.0.213398074469.issue31835@psf.upfronthosting.co.za>
In-reply-to
Content
Just a minor performance issue.

The C functions _PyFunction_FastCallDict() and _PyFunction_FastCallKeywords() (branch 'master', Objects/call.c) and their predecessors fast_function() and _PyFunction_FastCallDict() in Python/ceval.c all contain the following sub-expression in the "if"-statement for the fast-path. For instance Objects/call.c:318

 co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)

Now, if co_flags has any of the CO_FUTURE_... bits set, the expression is always False and the fast path is not used.

Currently this affects only Python 3.6 and Python 2.7, because other Python versions do not use the __future__ mechanism.

The fix is simple. Replace the faulty sub-expression by

 (co->co_flags & (~PyCF_MASK)) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))

I discovered this issue while debugging reference leaks in Stackless Python a few month ago. It is hard to write a test case, but one can compare C call stacks using a debugger.

$ ulimit -c unlimited  # enable core dumps
$ python3.6 -c 'from __future__ import generator_stop; import os; (lambda: os.abort())()'
$ gdb -batch -ex bt  python3.6 core > trace_with_future
$ python3.6 -c 'import os; (lambda: os.abort())()'
$ gdb -batch -ex bt  python3.6 core > trace_without_future

If you compare the traces, the difference is in stack frame #9. Same for python2.7.
History
Date User Action Args
2017-10-21 11:14:04anselm.kruissetrecipients: + anselm.kruis
2017-10-21 11:14:04anselm.kruissetmessageid: <1508584444.52.0.213398074469.issue31835@psf.upfronthosting.co.za>
2017-10-21 11:14:04anselm.kruislinkissue31835 messages
2017-10-21 11:14:04anselm.kruiscreate