Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-97933: inline list/dict/set comprehensions#101441

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
carljm merged 56 commits intopython:mainfromcarljm:inlinecomp2
May 9, 2023
Merged
Show file tree
Hide file tree
Changes from1 commit
Commits
Show all changes
56 commits
Select commitHold shift + click to select a range
72afa83
gh-97933: inline sync list/dict/set comprehensions
carljmJan 30, 2023
8988234
simplify cell handling code slightly
carljmJan 31, 2023
22c4a86
clarify comments
carljmJan 31, 2023
c1b54f0
enable inlining async comprehensions also
carljmJan 31, 2023
43db9b8
fix typo
carljmJan 31, 2023
ed3209b
Merge branch 'main' into inlinecomp2
carljmJan 31, 2023
aceb6c7
fix outer-cell, inner-local case
carljmJan 31, 2023
e57c354
fix restoring NULL (unbound outer name) followed by load
carljmJan 31, 2023
795d854
emit 1 x SWAP N+1 instead of N x SWAP 2
carljmJan 31, 2023
686221a
remove stray dis.dis() call
carljmJan 31, 2023
ac99697
fix compiler warning about Py_ssize_t -> int conversion
carljmJan 31, 2023
db208d5
Merge branch 'main' into inlinecomp2
carljmJan 31, 2023
8b76051
Merge branch 'main' into inlinecomp2
carljmFeb 1, 2023
4620856
add a couple more tests
carljmFeb 1, 2023
8773653
clear comp locals on entry, eval iter expr first
carljmFeb 1, 2023
be3becc
Merge branch 'main' into inlinecomp2
carljmFeb 9, 2023
f0c051e
fix double decref in error case
carljmFeb 9, 2023
142859a
adjust to RETURN_CONST
carljmFeb 9, 2023
568a470
fix up refcounting
carljmFeb 10, 2023
add772e
Merge branch 'main' into inlinecomp2
carljmFeb 10, 2023
17d5d84
improve importlib comment
carljmFeb 10, 2023
b87d209
mark STORE_FAST_MAYBE_NULL as possibly NULLing a local
carljmFeb 10, 2023
36b2917
Merge branch 'main' into inlinecomp2
carljmFeb 10, 2023
ae0bd02
Merge branch 'main' into inlinecomp2
carljmFeb 13, 2023
9f0fc5b
Merge branch 'main' into inlinecomp2
carljmFeb 20, 2023
463c740
add test for NameError/UnboundLocalError
carljmFeb 28, 2023
67f50ba
fix case where iter var is free in outer scope
carljmFeb 28, 2023
73dc0ed
Merge branch 'main' into inlinecomp2
carljmFeb 28, 2023
ecb313c
Merge branch 'main' into inlinecomp2
carljmMar 6, 2023
4109baa
add inlining of non-function-scope comprehensions
carljmMar 7, 2023
d8802a1
simplify scope handling
carljmMar 7, 2023
1c019a7
Merge branch 'main' into inlinecomp2
carljmMar 7, 2023
24a9d9f
Merge branch 'main' into inlinecomp2
carljmMar 8, 2023
b6a025b
add tests for comprehensions in class scope
carljmMar 8, 2023
90b34de
run all listcomp scope tests in module, class, and func scope
carljmMar 8, 2023
06db319
Merge branch 'main' into inlinecomp2
carljmMar 8, 2023
b52046b
handle frame locals materialization in class/module scope
carljmMar 14, 2023
6c5f269
Merge branch 'main' into inlinecomp2
carljmMar 14, 2023
1a8f4a0
Merge branch 'main' into inlinecomp2
carljmMar 17, 2023
1274e2b
Merge branch 'main' into inlinecomp2
carljmMay 1, 2023
0727d6f
Merge branch 'main' into inlinecomp2
carljmMay 2, 2023
51a1294
update comment
carljmMay 2, 2023
8a78a36
Merge branch 'main' into inlinecomp2
carljmMay 5, 2023
43722b4
review comments
carljmMay 5, 2023
bf9e1f1
fix single backticks
carljmMay 5, 2023
ca636a5
better nested test
carljmMay 5, 2023
46c7a4f
fix u_fasthidden in nested case
carljmMay 5, 2023
fb9f89e
fix refleak
carljmMay 5, 2023
baacf5f
Merge branch 'main' into inlinecomp2
carljmMay 5, 2023
5914d77
remove assumption that class scopes can't have cellvars
carljmMay 5, 2023
ffae4e6
Apply suggestions from code review
carljmMay 9, 2023
76077cd
Merge branch 'main' into inlinecomp2
carljmMay 9, 2023
a8425a6
review comments
carljmMay 9, 2023
656e46b
Apply suggestions from code review
carljmMay 9, 2023
1402e7a
Apply suggestions from code review
carljmMay 9, 2023
95401fe
Merge branch 'main' into inlinecomp2
carljmMay 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
PrevPrevious commit
NextNext commit
clear comp locals on entry, eval iter expr first
  • Loading branch information
@carljm
carljm committedFeb 1, 2023
commit8773653b4c078591d6c1ea28c1285b0922a775f6
8 changes: 3 additions & 5 deletionsDoc/library/dis.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1213,13 +1213,11 @@ iterations of the loop.

.. versionadded:: 3.12

.. opcode::LOAD_FAST_OR_NULL (var_num)
.. opcode::LOAD_FAST_AND_CLEAR (var_num)

Pushes a reference to the local ``co_varnames[var_num]`` onto the stack,or
Pushes a reference to the local ``co_varnames[var_num]`` onto the stack (or
pushes ``NULL`` onto the stack if the local variable has not been
initialized. This opcode has the same runtime effect as ``LOAD_FAST``; it
exists to maintain the invariant that ``LOAD_FAST`` will never load ``NULL``
and may appear only where the variable is guaranteed to be initialized.
initialized) and sets ``co_varnames[var_num]`` to ``NULL``.

.. versionadded:: 3.12

Expand Down
4 changes: 2 additions & 2 deletionsInclude/internal/pycore_opcode.h
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

2 changes: 1 addition & 1 deletionInclude/opcode.h
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

2 changes: 1 addition & 1 deletionLib/opcode.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -196,7 +196,7 @@ def pseudo_op(name, op, real_ops):
hascompare.append(141)

def_op('CALL_FUNCTION_EX', 142) # Flags
def_op('LOAD_FAST_OR_NULL', 143) # Local variable number, may load NULL if undefined
def_op('LOAD_FAST_AND_CLEAR', 143) # Local variable number
haslocal.append(143)

def_op('EXTENDED_ARG', 144)
Expand Down
5 changes: 3 additions & 2 deletionsPython/bytecodes.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -114,9 +114,10 @@ dummy_func(
Py_INCREF(value);
}

inst(LOAD_FAST_OR_NULL, (-- value)) {
inst(LOAD_FAST_AND_CLEAR, (-- value)) {
value = GETLOCAL(oparg);
Py_XINCREF(value);
// do not use SETLOCAL here, it decrefs the old value
GETLOCAL(oparg) = NULL;
}

inst(LOAD_CONST, (-- value)) {
Expand Down
148 changes: 89 additions & 59 deletionsPython/compile.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -550,14 +550,14 @@ static int compiler_sync_comprehension_generator(
asdl_comprehension_seq *generators, int gen_index,
int depth,
expr_ty elt, expr_ty val, int type,
intoutermost_iter_is_param);
intiter_on_stack);

static int compiler_async_comprehension_generator(
struct compiler *c, location loc,
asdl_comprehension_seq *generators, int gen_index,
int depth,
expr_ty elt, expr_ty val, int type,
intoutermost_iter_is_param);
intiter_on_stack);

static int compiler_pattern(struct compiler *, pattern_ty, pattern_context *);
static int compiler_match(struct compiler *, stmt_ty);
Expand DownExpand Up@@ -1229,7 +1229,7 @@ stack_effect(int opcode, int oparg, int jump)

case LOAD_FAST:
case LOAD_FAST_CHECK:
caseLOAD_FAST_OR_NULL:
caseLOAD_FAST_AND_CLEAR:
return 1;
case STORE_FAST:
case STORE_FAST_MAYBE_NULL:
Expand DownExpand Up@@ -5150,18 +5150,18 @@ compiler_comprehension_generator(struct compiler *c, location loc,
asdl_comprehension_seq *generators, int gen_index,
int depth,
expr_ty elt, expr_ty val, int type,
intoutermost_iter_is_param)
intiter_on_stack)
{
comprehension_ty gen;
gen = (comprehension_ty)asdl_seq_GET(generators, gen_index);
if (gen->is_async) {
return compiler_async_comprehension_generator(
c, loc, generators, gen_index, depth, elt, val, type,
outermost_iter_is_param);
iter_on_stack);
} else {
return compiler_sync_comprehension_generator(
c, loc, generators, gen_index, depth, elt, val, type,
outermost_iter_is_param);
iter_on_stack);
}
}

Expand All@@ -5170,7 +5170,7 @@ compiler_sync_comprehension_generator(struct compiler *c, location loc,
asdl_comprehension_seq *generators,
int gen_index, int depth,
expr_ty elt, expr_ty val, int type,
intoutermost_iter_is_param)
intiter_on_stack)
{
/* generate code for the iterator, then each of the ifs,
and then write to the element */
Expand All@@ -5182,37 +5182,39 @@ compiler_sync_comprehension_generator(struct compiler *c, location loc,
comprehension_ty gen = (comprehension_ty)asdl_seq_GET(generators,
gen_index);

if (gen_index == 0 && outermost_iter_is_param) {
/* Receive outermost iter as an implicit argument */
c->u->u_argcount = 1;
ADDOP_I(c, loc, LOAD_FAST, 0);
}
else {
/* Sub-iter - calculate on the fly */
/* Fast path for the temporary variable assignment idiom:
for y in [f(x)]
*/
asdl_expr_seq *elts;
switch (gen->iter->kind) {
case List_kind:
elts = gen->iter->v.List.elts;
break;
case Tuple_kind:
elts = gen->iter->v.Tuple.elts;
break;
default:
elts = NULL;
if (!iter_on_stack) {
if (gen_index == 0) {
/* Receive outermost iter as an implicit argument */
c->u->u_argcount = 1;
ADDOP_I(c, loc, LOAD_FAST, 0);
}
if (asdl_seq_LEN(elts) == 1) {
expr_ty elt = asdl_seq_GET(elts, 0);
if (elt->kind != Starred_kind) {
VISIT(c, expr, elt);
start = NO_LABEL;
else {
/* Sub-iter - calculate on the fly */
/* Fast path for the temporary variable assignment idiom:
for y in [f(x)]
*/
asdl_expr_seq *elts;
switch (gen->iter->kind) {
case List_kind:
elts = gen->iter->v.List.elts;
break;
case Tuple_kind:
elts = gen->iter->v.Tuple.elts;
break;
default:
elts = NULL;
}
if (asdl_seq_LEN(elts) == 1) {
expr_ty elt = asdl_seq_GET(elts, 0);
if (elt->kind != Starred_kind) {
VISIT(c, expr, elt);
start = NO_LABEL;
}
}
if (IS_LABEL(start)) {
VISIT(c, expr, gen->iter);
ADDOP(c, loc, GET_ITER);
}
}
if (IS_LABEL(start)) {
VISIT(c, expr, gen->iter);
ADDOP(c, loc, GET_ITER);
}
}
if (IS_LABEL(start)) {
Expand DownExpand Up@@ -5287,7 +5289,7 @@ compiler_async_comprehension_generator(struct compiler *c, location loc,
asdl_comprehension_seq *generators,
int gen_index, int depth,
expr_ty elt, expr_ty val, int type,
intoutermost_iter_is_param)
intiter_on_stack)
{
NEW_JUMP_TARGET_LABEL(c, start);
NEW_JUMP_TARGET_LABEL(c, except);
Expand All@@ -5296,15 +5298,17 @@ compiler_async_comprehension_generator(struct compiler *c, location loc,
comprehension_ty gen = (comprehension_ty)asdl_seq_GET(generators,
gen_index);

if (gen_index == 0 && outermost_iter_is_param) {
/* Receive outermost iter as an implicit argument */
c->u->u_argcount = 1;
ADDOP_I(c, loc, LOAD_FAST, 0);
}
else {
/* Sub-iter - calculate on the fly */
VISIT(c, expr, gen->iter);
ADDOP(c, loc, GET_AITER);
if (!iter_on_stack) {
if (gen_index == 0) {
/* Receive outermost iter as an implicit argument */
c->u->u_argcount = 1;
ADDOP_I(c, loc, LOAD_FAST, 0);
}
else {
/* Sub-iter - calculate on the fly */
VISIT(c, expr, gen->iter);
ADDOP(c, loc, GET_AITER);
}
}

USE_LABEL(c, start);
Expand DownExpand Up@@ -5449,7 +5453,7 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
// in the case of a cell, this will actually push the cell
// itself to the stack, then we'll create a new one for the
// comprehension and restore the original one after
ADDOP_NAME(c, loc,LOAD_FAST_OR_NULL, k, varnames);
ADDOP_NAME(c, loc,LOAD_FAST_AND_CLEAR, k, varnames);
if (scope == CELL) {
ADDOP_NAME(c, loc, MAKE_CELL, k, cellvars);
}
Expand All@@ -5459,6 +5463,14 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
}
}
}
if (state->pushed_locals) {
// Outermost iterable expression was already evaluated and is on the
// stack, we need to swap it back to TOS. This also rotates the order of
// `pushed_locals` on the stack, but this will be reversed when we swap
// out the comprehension result in pop_inlined_comprehension_state
ADDOP_I(c, loc, SWAP, PyList_GET_SIZE(state->pushed_locals) + 1);
}

return SUCCESS;
}

Expand All@@ -5479,11 +5491,13 @@ pop_inlined_comprehension_state(struct compiler *c, location loc,
if (state.pushed_locals) {
// pop names we pushed to stack earlier
Py_ssize_t npops = PyList_GET_SIZE(state.pushed_locals);
// preserve the list/dict/set result of the comprehension as TOS
// Preserve the list/dict/set result of the comprehension as TOS. This
// reverses the SWAP we did in push_inlined_comprehension_state to get
// the outermost iterable to TOS, so we can still just iterate
// pushed_locals in simple reverse order
ADDOP_I(c, loc, SWAP, npops + 1);
for (Py_ssize_t i = npops; i > 0; --i) {
// i % npops: pop in order e.g. 0, 3, 2, 1: accounts for the swap
k = PyList_GetItem(state.pushed_locals, i % npops);
for (Py_ssize_t i = npops - 1; i >= 0; --i) {
k = PyList_GetItem(state.pushed_locals, i);
if (k == NULL) {
return ERROR;
}
Expand All@@ -5493,6 +5507,19 @@ pop_inlined_comprehension_state(struct compiler *c, location loc,
return SUCCESS;
}

static inline int
compiler_comprehension_iter(struct compiler *c, location loc,
comprehension_ty comp)
{
VISIT(c, expr, comp->iter);
if (comp->is_async) {
ADDOP(c, loc, GET_AITER);
} else {
ADDOP(c, loc, GET_ITER);
}
return SUCCESS;
}

static int
compiler_comprehension(struct compiler *c, expr_ty e, int type,
identifier name, asdl_comprehension_seq *generators, expr_ty elt,
Expand All@@ -5516,6 +5543,9 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,

outermost = (comprehension_ty) asdl_seq_GET(generators, 0);
if (is_inlined) {
if (compiler_comprehension_iter(c, loc, outermost)) {
goto error;
}
if (push_inlined_comprehension_state(c, loc, entry, &inline_state)) {
goto error;
}
Expand DownExpand Up@@ -5557,10 +5587,13 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
}

ADDOP_I(c, loc, op, 0);
if (is_inlined) {
ADDOP_I(c, loc, SWAP, 2);
}
}

if (compiler_comprehension_generator(c, loc, generators, 0, 0,
elt, val, type,!is_inlined) < 0) {
elt, val, type, is_inlined) < 0) {
goto error_in_scope;
}

Expand DownExpand Up@@ -5595,13 +5628,8 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
}
Py_DECREF(co);

VISIT(c, expr, outermost->iter);

loc = LOC(e);
if (outermost->is_async) {
ADDOP(c, loc, GET_AITER);
} else {
ADDOP(c, loc, GET_ITER);
if (compiler_comprehension_iter(c, loc, outermost)) {
goto error;
}

ADDOP_I(c, loc, CALL, 0);
Expand DownExpand Up@@ -8141,6 +8169,7 @@ scan_block_for_locals(basicblock *b, basicblock ***sp)
uint64_t bit = (uint64_t)1 << instr->i_oparg;
switch (instr->i_opcode) {
case DELETE_FAST:
case LOAD_FAST_AND_CLEAR:
unsafe_mask |= bit;
break;
case STORE_FAST:
Expand DownExpand Up@@ -8194,6 +8223,7 @@ fast_scan_many_locals(basicblock *entryblock, int nlocals)
assert(arg >= 0);
switch (instr->i_opcode) {
case DELETE_FAST:
case LOAD_FAST_AND_CLEAR:
states[arg - 64] = blocknum - 1;
break;
case STORE_FAST:
Expand Down
5 changes: 3 additions & 2 deletionsPython/generated_cases.c.h
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

6 changes: 3 additions & 3 deletionsPython/opcode_metadata.h
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -16,7 +16,7 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 0;
case LOAD_FAST:
return 0;
caseLOAD_FAST_OR_NULL:
caseLOAD_FAST_AND_CLEAR:
return 0;
case LOAD_CONST:
return 0;
Expand DownExpand Up@@ -364,7 +364,7 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 1;
case LOAD_FAST:
return 1;
caseLOAD_FAST_OR_NULL:
caseLOAD_FAST_AND_CLEAR:
return 1;
case LOAD_CONST:
return 1;
Expand DownExpand Up@@ -711,7 +711,7 @@ struct opcode_metadata {
[LOAD_CLOSURE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[LOAD_FAST_CHECK] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[LOAD_FAST_OR_NULL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[LOAD_FAST_AND_CLEAR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[LOAD_CONST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[STORE_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[LOAD_FAST__LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB },
Expand Down
2 changes: 1 addition & 1 deletionPython/opcode_targets.h
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.


[8]ページ先頭

©2009-2025 Movatter.jp