-
-
Notifications
You must be signed in to change notification settings - Fork 34.2k
bpo-36551: Optimize list comprehensions with preallocate size and protect against overflow #12718
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
96258c6
64a6fdd
a7337a7
2063a2c
96e754c
5b3ce92
836616b
1710c84
f80b6a7
5f06333
0bcfa4d
22debe6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| Change the compiled bytecode for list comprehensions where there is no if statement. Allocates the size of the list to the length of the iterator in order to avoid having to continuously resize the list. | ||
| Also fixes a bug for a list comprehension containing an iterator with a potential size > PY_SSIZE_MAX, e.g. range(2**256). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -215,6 +215,12 @@ list_new_prealloc(Py_ssize_t size) | |
| return (PyObject *) op; | ||
| } | ||
|
|
||
| PyObject * | ||
| _PyList_NewPrealloc(Py_ssize_t size) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of adding a new function |
||
| { | ||
| return list_new_prealloc(size); | ||
| } | ||
|
|
||
| Py_ssize_t | ||
| PyList_Size(PyObject *op) | ||
| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1168,6 +1168,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) | |
| } | ||
|
|
||
| case TARGET(LOAD_FAST): { | ||
| PREDICTED(LOAD_FAST); | ||
| PyObject *value = GETLOCAL(oparg); | ||
| if (value == NULL) { | ||
| format_exc_check_arg(PyExc_UnboundLocalError, | ||
|
|
@@ -2484,6 +2485,20 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) | |
| DISPATCH(); | ||
| } | ||
|
|
||
| case TARGET(BUILD_LIST_PREALLOC): { | ||
| PyObject *list, *target = GETLOCAL(oparg); | ||
| Py_INCREF(target); | ||
| Py_ssize_t size = PyObject_LengthHint(target, 0); | ||
| Py_DECREF(target); | ||
| if (size < 0) | ||
| goto error; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMHO this should raise a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Have raised that separately in #12720 as it's out-of-scope for this change and impact other things |
||
|
|
||
| list = _PyList_NewPrealloc(size); | ||
| PUSH(list); | ||
| PREDICT(LOAD_FAST); | ||
| DISPATCH(); | ||
| } | ||
|
|
||
| case TARGET(BUILD_LIST): { | ||
| PyObject *list = PyList_New(oparg); | ||
| if (list == NULL) | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's really weird to me that this module is tested entirely with doctests (though I know that's not part of this PR).