Skip to content

Commit d63f73e

Browse files
Merge cell locals with var locals for args.
1 parent 507ed6f commit d63f73e

File tree

9 files changed

+4109
-4137
lines changed

9 files changed

+4109
-4137
lines changed

Include/cpython/code.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ struct PyCodeObject {
8787
// redundant values (derived from co_localsplusnames and co_localspluskinds)
8888
int co_nlocalsplus; /* number of local + cell + free variables */
8989
int co_nlocals; /* number of local variables */
90-
int co_ncellvars; /* number of cell variables */
90+
int co_nplaincellvars; /* number of non-arg cell variables */
91+
int co_ncellvars; /* total number of cell variables */
9192
int co_nfreevars; /* number of free variables */
9293
// lazily-computed values
9394
PyObject *co_varnames; /* tuple of strings (local variable names) */

Lib/test/test_dis.py

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -427,9 +427,9 @@ def foo(x):
427427
return foo
428428

429429
dis_nested_0 = """\
430-
0 MAKE_CELL 2 (y)
430+
0 MAKE_CELL 0 (y)
431431
432-
%3d 2 LOAD_CLOSURE 2 (y)
432+
%3d 2 LOAD_CLOSURE 0 (y)
433433
4 BUILD_TUPLE 1
434434
6 LOAD_CONST 1 (<code object foo at 0x..., file "%s", line %d>)
435435
8 LOAD_CONST 2 ('_h.<locals>.foo')
@@ -446,14 +446,14 @@ def foo(x):
446446

447447
dis_nested_1 = """%s
448448
Disassembly of <code object foo at 0x..., file "%s", line %d>:
449-
0 MAKE_CELL 1 (x)
449+
0 MAKE_CELL 0 (x)
450450
451-
%3d 2 LOAD_CLOSURE 1 (x)
451+
%3d 2 LOAD_CLOSURE 0 (x)
452452
4 BUILD_TUPLE 1
453453
6 LOAD_CONST 1 (<code object <listcomp> at 0x..., file "%s", line %d>)
454454
8 LOAD_CONST 2 ('_h.<locals>.foo.<locals>.<listcomp>')
455455
10 MAKE_FUNCTION 8 (closure)
456-
12 LOAD_DEREF 2 (y)
456+
12 LOAD_DEREF 1 (y)
457457
14 GET_ITER
458458
16 CALL_FUNCTION 1
459459
18 RETURN_VALUE
@@ -966,19 +966,19 @@ def jumpy():
966966

967967
Instruction = dis.Instruction
968968
expected_opinfo_outer = [
969-
Instruction(opname='MAKE_CELL', opcode=135, arg=3, argval='a', argrepr='a', offset=0, starts_line=None, is_jump_target=False),
970-
Instruction(opname='MAKE_CELL', opcode=135, arg=4, argval='b', argrepr='b', offset=2, starts_line=None, is_jump_target=False),
969+
Instruction(opname='MAKE_CELL', opcode=135, arg=0, argval='a', argrepr='a', offset=0, starts_line=None, is_jump_target=False),
970+
Instruction(opname='MAKE_CELL', opcode=135, arg=1, argval='b', argrepr='b', offset=2, starts_line=None, is_jump_target=False),
971971
Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval=(3, 4), argrepr='(3, 4)', offset=4, starts_line=2, is_jump_target=False),
972-
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=3, argval='a', argrepr='a', offset=6, starts_line=None, is_jump_target=False),
973-
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=4, argval='b', argrepr='b', offset=8, starts_line=None, is_jump_target=False),
972+
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=0, argval='a', argrepr='a', offset=6, starts_line=None, is_jump_target=False),
973+
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=1, argval='b', argrepr='b', offset=8, starts_line=None, is_jump_target=False),
974974
Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=10, starts_line=None, is_jump_target=False),
975975
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_f, argrepr=repr(code_object_f), offset=12, starts_line=None, is_jump_target=False),
976976
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f', argrepr="'outer.<locals>.f'", offset=14, starts_line=None, is_jump_target=False),
977977
Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=16, starts_line=None, is_jump_target=False),
978978
Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=18, starts_line=None, is_jump_target=False),
979979
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=20, starts_line=7, is_jump_target=False),
980-
Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='a', argrepr='a', offset=22, starts_line=None, is_jump_target=False),
981-
Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='b', argrepr='b', offset=24, starts_line=None, is_jump_target=False),
980+
Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='a', argrepr='a', offset=22, starts_line=None, is_jump_target=False),
981+
Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='b', argrepr='b', offset=24, starts_line=None, is_jump_target=False),
982982
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval='', argrepr="''", offset=26, starts_line=None, is_jump_target=False),
983983
Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval=1, argrepr='1', offset=28, starts_line=None, is_jump_target=False),
984984
Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=30, starts_line=None, is_jump_target=False),
@@ -991,23 +991,23 @@ def jumpy():
991991
]
992992

993993
expected_opinfo_f = [
994-
Instruction(opname='MAKE_CELL', opcode=135, arg=3, argval='c', argrepr='c', offset=0, starts_line=None, is_jump_target=False),
995-
Instruction(opname='MAKE_CELL', opcode=135, arg=4, argval='d', argrepr='d', offset=2, starts_line=None, is_jump_target=False),
994+
Instruction(opname='MAKE_CELL', opcode=135, arg=0, argval='c', argrepr='c', offset=0, starts_line=None, is_jump_target=False),
995+
Instruction(opname='MAKE_CELL', opcode=135, arg=1, argval='d', argrepr='d', offset=2, starts_line=None, is_jump_target=False),
996996
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=(5, 6), argrepr='(5, 6)', offset=4, starts_line=3, is_jump_target=False),
997-
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=5, argval='a', argrepr='a', offset=6, starts_line=None, is_jump_target=False),
998-
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=6, argval='b', argrepr='b', offset=8, starts_line=None, is_jump_target=False),
999-
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=3, argval='c', argrepr='c', offset=10, starts_line=None, is_jump_target=False),
1000-
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=4, argval='d', argrepr='d', offset=12, starts_line=None, is_jump_target=False),
997+
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=3, argval='a', argrepr='a', offset=6, starts_line=None, is_jump_target=False),
998+
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=4, argval='b', argrepr='b', offset=8, starts_line=None, is_jump_target=False),
999+
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=0, argval='c', argrepr='c', offset=10, starts_line=None, is_jump_target=False),
1000+
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=1, argval='d', argrepr='d', offset=12, starts_line=None, is_jump_target=False),
10011001
Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=14, starts_line=None, is_jump_target=False),
10021002
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_inner, argrepr=repr(code_object_inner), offset=16, starts_line=None, is_jump_target=False),
10031003
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f.<locals>.inner', argrepr="'outer.<locals>.f.<locals>.inner'", offset=18, starts_line=None, is_jump_target=False),
10041004
Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=20, starts_line=None, is_jump_target=False),
10051005
Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=22, starts_line=None, is_jump_target=False),
10061006
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=24, starts_line=5, is_jump_target=False),
1007-
Instruction(opname='LOAD_DEREF', opcode=137, arg=5, argval='a', argrepr='a', offset=26, starts_line=None, is_jump_target=False),
1008-
Instruction(opname='LOAD_DEREF', opcode=137, arg=6, argval='b', argrepr='b', offset=28, starts_line=None, is_jump_target=False),
1009-
Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='c', argrepr='c', offset=30, starts_line=None, is_jump_target=False),
1010-
Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='d', argrepr='d', offset=32, starts_line=None, is_jump_target=False),
1007+
Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='a', argrepr='a', offset=26, starts_line=None, is_jump_target=False),
1008+
Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='b', argrepr='b', offset=28, starts_line=None, is_jump_target=False),
1009+
Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=30, starts_line=None, is_jump_target=False),
1010+
Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=32, starts_line=None, is_jump_target=False),
10111011
Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='', offset=34, starts_line=None, is_jump_target=False),
10121012
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=36, starts_line=None, is_jump_target=False),
10131013
Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=38, starts_line=6, is_jump_target=False),

Objects/codeobject.c

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -162,43 +162,28 @@ _Py_set_localsplus_info(int offset, PyObject *name, _PyLocalsPlusKind kind,
162162
Py_INCREF(name);
163163
PyTuple_SET_ITEM(names, offset, name);
164164
kinds[offset] = kind;
165-
166-
if (kind == CO_FAST_CELL) {
167-
// Cells can overlap with args, so mark those cases.
168-
int nlocalsplus = (int)PyTuple_GET_SIZE(names);
169-
for (int i = 0; i < nlocalsplus; i++) {
170-
_PyLocalsPlusKind kind = kinds[i];
171-
if (kind && !(kind & CO_FAST_LOCAL)) {
172-
// We've moved past the locals.
173-
break;
174-
}
175-
PyObject *varname = PyTuple_GET_ITEM(names, i);
176-
int cmp = PyUnicode_Compare(name, varname);
177-
if (cmp == 0) {
178-
kinds[i] |= CO_FAST_CELL;
179-
break;
180-
}
181-
assert(cmp > 0 || !PyErr_Occurred());
182-
}
183-
}
184165
}
185166

186167
static void
187168
get_localsplus_counts(PyObject *names, _PyLocalsPlusKinds kinds,
188-
int *pnlocals, int *pncellvars,
169+
int *pnlocals, int *pnplaincellvars, int *pncellvars,
189170
int *pnfreevars)
190171
{
191172
int nlocals = 0;
173+
int nplaincellvars = 0;
192174
int ncellvars = 0;
193175
int nfreevars = 0;
194-
int nlocalsplus = Py_SAFE_DOWNCAST(PyTuple_GET_SIZE(names),
195-
Py_ssize_t, int);
176+
Py_ssize_t nlocalsplus = PyTuple_GET_SIZE(names);
196177
for (int i = 0; i < nlocalsplus; i++) {
197178
if (kinds[i] & CO_FAST_LOCAL) {
198179
nlocals += 1;
180+
if (kinds[i] & CO_FAST_CELL) {
181+
ncellvars += 1;
182+
}
199183
}
200184
else if (kinds[i] & CO_FAST_CELL) {
201185
ncellvars += 1;
186+
nplaincellvars += 1;
202187
}
203188
else if (kinds[i] & CO_FAST_FREE) {
204189
nfreevars += 1;
@@ -207,6 +192,9 @@ get_localsplus_counts(PyObject *names, _PyLocalsPlusKinds kinds,
207192
if (pnlocals != NULL) {
208193
*pnlocals = nlocals;
209194
}
195+
if (pnplaincellvars != NULL) {
196+
*pnplaincellvars = nplaincellvars;
197+
}
210198
if (pncellvars != NULL) {
211199
*pncellvars = ncellvars;
212200
}
@@ -227,10 +215,6 @@ get_localsplus_names(PyCodeObject *co, _PyLocalsPlusKind kind, int num)
227215
if ((co->co_localspluskinds[offset] & kind) == 0) {
228216
continue;
229217
}
230-
// For now there may be duplicates, which we ignore.
231-
if (kind == CO_FAST_CELL && co->co_localspluskinds[offset] != kind) {
232-
continue;
233-
}
234218
assert(index < num);
235219
PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, offset);
236220
Py_INCREF(name);
@@ -283,7 +267,7 @@ _PyCode_Validate(struct _PyCodeConstructor *con)
283267
* here to avoid the possibility of overflow (however remote). */
284268
int nlocals;
285269
get_localsplus_counts(con->localsplusnames, con->localspluskinds,
286-
&nlocals, NULL, NULL);
270+
&nlocals, NULL, NULL, NULL);
287271
int nplainlocals = nlocals -
288272
con->argcount -
289273
con->kwonlyargcount -
@@ -301,9 +285,9 @@ static void
301285
init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
302286
{
303287
int nlocalsplus = (int)PyTuple_GET_SIZE(con->localsplusnames);
304-
int nlocals, ncellvars, nfreevars;
288+
int nlocals, nplaincellvars, ncellvars, nfreevars;
305289
get_localsplus_counts(con->localsplusnames, con->localspluskinds,
306-
&nlocals, &ncellvars, &nfreevars);
290+
&nlocals, &nplaincellvars, &ncellvars, &nfreevars);
307291

308292
Py_INCREF(con->filename);
309293
co->co_filename = con->filename;
@@ -341,6 +325,7 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
341325
co->co_cell2arg = NULL; // This will be set soon.
342326
co->co_nlocalsplus = nlocalsplus;
343327
co->co_nlocals = nlocals;
328+
co->co_nplaincellvars = nplaincellvars;
344329
co->co_ncellvars = ncellvars;
345330
co->co_nfreevars = nfreevars;
346331
co->co_varnames = NULL;
@@ -401,6 +386,7 @@ _PyCode_New(struct _PyCodeConstructor *con)
401386
assert(totalargs <= co->co_nlocals);
402387
/* Find cells which are also arguments. */
403388
for (int i = 0; i < co->co_ncellvars; i++) {
389+
continue;
404390
PyObject *cellname = PyTuple_GET_ITEM(co->co_localsplusnames,
405391
i + co->co_nlocals);
406392
for (int j = 0; j < totalargs; j++) {
@@ -478,6 +464,23 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
478464
}
479465
for (int i = 0; i < ncellvars; i++, offset++) {
480466
PyObject *name = PyTuple_GET_ITEM(cellvars, i);
467+
int argoffset = -1;
468+
for (int j = 0; j < nvarnames; j++) {
469+
int cmp = PyUnicode_Compare(PyTuple_GET_ITEM(varnames, j),
470+
name);
471+
assert(!PyErr_Occurred());
472+
if (cmp == 0) {
473+
argoffset = j;
474+
break;
475+
}
476+
}
477+
if (argoffset >= 0) {
478+
// Merge the localsplus indices.
479+
nlocalsplus -= 1;
480+
offset -= 1;
481+
localspluskinds[argoffset] |= CO_FAST_CELL;
482+
continue;
483+
}
481484
_Py_set_localsplus_info(offset, name, CO_FAST_CELL,
482485
localsplusnames, localspluskinds);
483486
}
@@ -486,6 +489,11 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
486489
_Py_set_localsplus_info(offset, name, CO_FAST_FREE,
487490
localsplusnames, localspluskinds);
488491
}
492+
// If any cells were args then nlocalsplus will have shrunk.
493+
// We don't bother resizing localspluskinds.
494+
if (_PyTuple_Resize(&localsplusnames, nlocalsplus) < 0) {
495+
goto error;
496+
}
489497

490498
struct _PyCodeConstructor con = {
491499
.filename = filename,

0 commit comments

Comments
 (0)