Skip to content

Commit d2f617f

Browse files
markshannonericsnowcurrently
authored andcommitted
Compute index of cellvars in compiler to avoid additional pointer in interpreter.
1 parent 2c1e258 commit d2f617f

File tree

7 files changed

+73
-68
lines changed

7 files changed

+73
-68
lines changed

Lib/dis.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -378,14 +378,11 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
378378
elif op in hasjrel:
379379
argval = offset + 2 + arg*2
380380
argrepr = "to " + repr(argval)
381-
elif op in haslocal:
381+
elif op in haslocal or op in hasfree:
382382
argval, argrepr = _get_name_info(arg, varname_from_oparg)
383383
elif op in hascompare:
384384
argval = cmp_op[arg]
385385
argrepr = argval
386-
elif op in hasfree:
387-
argval, argrepr = _get_name_info(arg, varname_from_oparg,
388-
cell=True)
389386
elif op == FORMAT_VALUE:
390387
argval, argrepr = FORMAT_VALUE_CONVERTERS[arg & 0x3]
391388
argval = (argval, bool(arg & 0x4))

Lib/test/test_dis.py

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

429429
dis_nested_0 = """\
430-
%3d 0 LOAD_CLOSURE 0 (y)
430+
%3d 0 LOAD_CLOSURE 2 (y)
431431
2 BUILD_TUPLE 1
432432
4 LOAD_CONST 1 (<code object foo at 0x..., file "%s", line %d>)
433433
6 LOAD_CONST 2 ('_h.<locals>.foo')
@@ -444,12 +444,12 @@ def foo(x):
444444

445445
dis_nested_1 = """%s
446446
Disassembly of <code object foo at 0x..., file "%s", line %d>:
447-
%3d 0 LOAD_CLOSURE 0 (x)
447+
%3d 0 LOAD_CLOSURE 1 (x)
448448
2 BUILD_TUPLE 1
449449
4 LOAD_CONST 1 (<code object <listcomp> at 0x..., file "%s", line %d>)
450450
6 LOAD_CONST 2 ('_h.<locals>.foo.<locals>.<listcomp>')
451451
8 MAKE_FUNCTION 8 (closure)
452-
10 LOAD_DEREF 1 (y)
452+
10 LOAD_DEREF 2 (y)
453453
12 GET_ITER
454454
14 CALL_FUNCTION 1
455455
16 RETURN_VALUE
@@ -467,7 +467,7 @@ def foo(x):
467467
2 LOAD_FAST 0 (.0)
468468
>> 4 FOR_ITER 6 (to 18)
469469
6 STORE_FAST 1 (z)
470-
8 LOAD_DEREF 0 (x)
470+
8 LOAD_DEREF 2 (x)
471471
10 LOAD_FAST 1 (z)
472472
12 BINARY_ADD
473473
14 LIST_APPEND 2
@@ -962,16 +962,16 @@ def jumpy():
962962
Instruction = dis.Instruction
963963
expected_opinfo_outer = [
964964
Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval=(3, 4), argrepr='(3, 4)', offset=0, starts_line=2, is_jump_target=False),
965-
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False),
966-
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False),
965+
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=3, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False),
966+
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=4, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False),
967967
Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=6, starts_line=None, is_jump_target=False),
968968
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_f, argrepr=repr(code_object_f), offset=8, starts_line=None, is_jump_target=False),
969969
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f', argrepr="'outer.<locals>.f'", offset=10, starts_line=None, is_jump_target=False),
970970
Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=12, starts_line=None, is_jump_target=False),
971971
Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=14, starts_line=None, is_jump_target=False),
972972
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=16, starts_line=7, is_jump_target=False),
973-
Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='a', argrepr='a', offset=18, starts_line=None, is_jump_target=False),
974-
Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='b', argrepr='b', offset=20, starts_line=None, is_jump_target=False),
973+
Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='a', argrepr='a', offset=18, starts_line=None, is_jump_target=False),
974+
Instruction(opname='LOAD_DEREF', opcode=136, arg=4, argval='b', argrepr='b', offset=20, starts_line=None, is_jump_target=False),
975975
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval='', argrepr="''", offset=22, starts_line=None, is_jump_target=False),
976976
Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval=1, argrepr='1', offset=24, starts_line=None, is_jump_target=False),
977977
Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=26, starts_line=None, is_jump_target=False),
@@ -985,20 +985,20 @@ def jumpy():
985985

986986
expected_opinfo_f = [
987987
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=(5, 6), argrepr='(5, 6)', offset=0, starts_line=3, is_jump_target=False),
988-
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=2, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False),
989-
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=3, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False),
990-
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='c', argrepr='c', offset=6, starts_line=None, is_jump_target=False),
991-
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='d', argrepr='d', offset=8, starts_line=None, is_jump_target=False),
988+
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=5, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False),
989+
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=6, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False),
990+
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=3, argval='c', argrepr='c', offset=6, starts_line=None, is_jump_target=False),
991+
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=4, argval='d', argrepr='d', offset=8, starts_line=None, is_jump_target=False),
992992
Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=10, starts_line=None, is_jump_target=False),
993993
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_inner, argrepr=repr(code_object_inner), offset=12, starts_line=None, is_jump_target=False),
994994
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f.<locals>.inner', argrepr="'outer.<locals>.f.<locals>.inner'", offset=14, starts_line=None, is_jump_target=False),
995995
Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=16, starts_line=None, is_jump_target=False),
996996
Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=18, starts_line=None, is_jump_target=False),
997997
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=20, starts_line=5, is_jump_target=False),
998-
Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='a', argrepr='a', offset=22, starts_line=None, is_jump_target=False),
999-
Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='b', argrepr='b', offset=24, starts_line=None, is_jump_target=False),
1000-
Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='c', argrepr='c', offset=26, starts_line=None, is_jump_target=False),
1001-
Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='d', argrepr='d', offset=28, starts_line=None, is_jump_target=False),
998+
Instruction(opname='LOAD_DEREF', opcode=136, arg=5, argval='a', argrepr='a', offset=22, starts_line=None, is_jump_target=False),
999+
Instruction(opname='LOAD_DEREF', opcode=136, arg=6, argval='b', argrepr='b', offset=24, starts_line=None, is_jump_target=False),
1000+
Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='c', argrepr='c', offset=26, starts_line=None, is_jump_target=False),
1001+
Instruction(opname='LOAD_DEREF', opcode=136, arg=4, argval='d', argrepr='d', offset=28, starts_line=None, is_jump_target=False),
10021002
Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='', offset=30, starts_line=None, is_jump_target=False),
10031003
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=32, starts_line=None, is_jump_target=False),
10041004
Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=34, starts_line=6, is_jump_target=False),
@@ -1007,10 +1007,10 @@ def jumpy():
10071007

10081008
expected_opinfo_inner = [
10091009
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=0, starts_line=4, is_jump_target=False),
1010-
Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False),
1011-
Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False),
1012-
Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='c', argrepr='c', offset=6, starts_line=None, is_jump_target=False),
1013-
Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='d', argrepr='d', offset=8, starts_line=None, is_jump_target=False),
1010+
Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False),
1011+
Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False),
1012+
Instruction(opname='LOAD_DEREF', opcode=136, arg=4, argval='c', argrepr='c', offset=6, starts_line=None, is_jump_target=False),
1013+
Instruction(opname='LOAD_DEREF', opcode=136, arg=5, argval='d', argrepr='d', offset=8, starts_line=None, is_jump_target=False),
10141014
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=10, starts_line=None, is_jump_target=False),
10151015
Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=12, starts_line=None, is_jump_target=False),
10161016
Instruction(opname='CALL_FUNCTION', opcode=131, arg=6, argval=6, argrepr='', offset=14, starts_line=None, is_jump_target=False),

Objects/codeobject.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,8 +1547,6 @@ code_replace_impl(PyCodeObject *self, int co_argcount,
15471547
code._varname_from_oparg
15481548
15491549
oparg: int
1550-
*
1551-
cell: bool = False
15521550
15531551
(internal-only) Return the local variable name for the given oparg.
15541552
@@ -1559,9 +1557,6 @@ static PyObject *
15591557
code__varname_from_oparg_impl(PyCodeObject *self, int oparg, int cell)
15601558
/*[clinic end generated code: output=c7d39c9723692c8f input=2945bb291d3a3118]*/
15611559
{
1562-
if (cell) {
1563-
oparg += self->co_nlocals;
1564-
}
15651560
PyObject *name = PyTuple_GetItem(self->co_localsplusnames, oparg);
15661561
if (name == NULL) {
15671562
return NULL;

Python/ceval.c

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1569,7 +1569,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
15691569
const _Py_CODEUNIT *next_instr;
15701570
int opcode; /* Current opcode */
15711571
int oparg; /* Current opcode argument, if any */
1572-
PyObject **localsplus, **freevars, **specials;
1572+
PyObject **localsplus, **specials;
15731573
PyObject *retval = NULL; /* Return value */
15741574
_Py_atomic_int * const eval_breaker = &tstate->interp->ceval.eval_breaker;
15751575
PyCodeObject *co;
@@ -1647,7 +1647,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
16471647
names = co->co_names;
16481648
consts = co->co_consts;
16491649
localsplus = f->f_localsptr;
1650-
freevars = f->f_localsptr + co->co_nlocals;
16511650
assert(PyBytes_Check(co->co_code));
16521651
assert(PyBytes_GET_SIZE(co->co_code) <= INT_MAX);
16531652
assert(PyBytes_GET_SIZE(co->co_code) % sizeof(_Py_CODEUNIT) == 0);
@@ -3060,7 +3059,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
30603059
}
30613060

30623061
case TARGET(DELETE_DEREF): {
3063-
PyObject *cell = freevars[oparg];
3062+
PyObject *cell = GETLOCAL(oparg);
30643063
PyObject *oldobj = PyCell_GET(cell);
30653064
if (oldobj != NULL) {
30663065
PyCell_SET(cell, NULL);
@@ -3072,20 +3071,17 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
30723071
}
30733072

30743073
case TARGET(LOAD_CLOSURE): {
3075-
PyObject *cell = freevars[oparg];
3074+
PyObject *cell = GETLOCAL(oparg);
30763075
Py_INCREF(cell);
30773076
PUSH(cell);
30783077
DISPATCH();
30793078
}
30803079

30813080
case TARGET(LOAD_CLASSDEREF): {
30823081
PyObject *name, *value, *locals = LOCALS();
3083-
Py_ssize_t idx;
30843082
assert(locals);
3085-
assert(oparg >= co->co_ncellvars);
3086-
idx = oparg + co->co_nlocals;
3087-
assert(idx < co->co_nlocalsplus);
3088-
name = PyTuple_GET_ITEM(co->co_localsplusnames, idx);
3083+
assert(oparg >= 0 && oparg < co->co_nlocalsplus);
3084+
name = PyTuple_GET_ITEM(co->co_localsplusnames, oparg);
30893085
if (PyDict_CheckExact(locals)) {
30903086
value = PyDict_GetItemWithError(locals, name);
30913087
if (value != NULL) {
@@ -3105,7 +3101,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
31053101
}
31063102
}
31073103
if (!value) {
3108-
PyObject *cell = freevars[oparg];
3104+
PyObject *cell = GETLOCAL(oparg);
31093105
value = PyCell_GET(cell);
31103106
if (value == NULL) {
31113107
format_exc_unbound(tstate, co, oparg);
@@ -3118,7 +3114,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
31183114
}
31193115

31203116
case TARGET(LOAD_DEREF): {
3121-
PyObject *cell = freevars[oparg];
3117+
PyObject *cell = GETLOCAL(oparg);
31223118
PyObject *value = PyCell_GET(cell);
31233119
if (value == NULL) {
31243120
format_exc_unbound(tstate, co, oparg);
@@ -3131,7 +3127,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
31313127

31323128
case TARGET(STORE_DEREF): {
31333129
PyObject *v = POP();
3134-
PyObject *cell = freevars[oparg];
3130+
PyObject *cell = GETLOCAL(oparg);
31353131
PyObject *oldobj = PyCell_GET(cell);
31363132
PyCell_SET(cell, v);
31373133
Py_XDECREF(oldobj);
@@ -4882,7 +4878,6 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
48824878
{
48834879
PyCodeObject *co = (PyCodeObject*)con->fc_code;
48844880
const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount;
4885-
PyObject **freevars = localsplus + co->co_nlocals;
48864881

48874882
/* Create a dictionary for keyword parameters (**kwags) */
48884883
PyObject *kwdict;
@@ -5086,7 +5081,7 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
50865081
for (i = 0; i < co->co_nfreevars; ++i) {
50875082
PyObject *o = PyTuple_GET_ITEM(con->fc_closure, i);
50885083
Py_INCREF(o);
5089-
freevars[co->co_ncellvars + i] = o;
5084+
localsplus[co->co_nlocals + co->co_ncellvars + i] = o;
50905085
}
50915086

50925087
return 0;
@@ -6419,8 +6414,8 @@ format_exc_unbound(PyThreadState *tstate, PyCodeObject *co, int oparg)
64196414
/* Don't stomp existing exception */
64206415
if (_PyErr_Occurred(tstate))
64216416
return;
6422-
name = PyTuple_GET_ITEM(co->co_localsplusnames, oparg + co->co_nlocals);
6423-
if (oparg < co->co_ncellvars) {
6417+
name = PyTuple_GET_ITEM(co->co_localsplusnames, oparg);
6418+
if (oparg < co->co_ncellvars + co->co_nlocals) {
64246419
format_exc_check_arg(tstate, PyExc_UnboundLocalError,
64256420
UNBOUNDLOCAL_ERROR_MSG, name);
64266421
} else {
@@ -6472,9 +6467,7 @@ unicode_concatenate(PyThreadState *tstate, PyObject *v, PyObject *w,
64726467
}
64736468
case STORE_DEREF:
64746469
{
6475-
PyObject **freevars = (f->f_localsptr +
6476-
f->f_code->co_nlocals);
6477-
PyObject *c = freevars[oparg];
6470+
PyObject *c = f->f_localsptr[oparg];
64786471
if (PyCell_GET(c) == v) {
64796472
PyCell_SET(c, NULL);
64806473
Py_DECREF(v);

Python/compile.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7435,6 +7435,24 @@ guarantee_lineno_for_exits(struct assembler *a, int firstlineno) {
74357435
}
74367436
}
74377437

7438+
static void
7439+
offset_derefs(struct assembler *a, int nlocals)
7440+
{
7441+
for (basicblock *b = a->a_entry; b != NULL; b = b->b_next) {
7442+
for (int i = 0; i < b->b_iused; i++) {
7443+
struct instr *inst = &b->b_instr[i];
7444+
switch(inst->i_opcode) {
7445+
case LOAD_DEREF:
7446+
case STORE_DEREF:
7447+
case DELETE_DEREF:
7448+
case LOAD_CLASSDEREF:
7449+
case LOAD_CLOSURE:
7450+
inst->i_oparg += nlocals;
7451+
}
7452+
}
7453+
}
7454+
}
7455+
74387456
static PyCodeObject *
74397457
assemble(struct compiler *c, int addNone)
74407458
{
@@ -7499,6 +7517,8 @@ assemble(struct compiler *c, int addNone)
74997517
}
75007518
guarantee_lineno_for_exits(&a, c->u->u_firstlineno);
75017519

7520+
offset_derefs(&a, (int)PyDict_GET_SIZE(c->u->u_varnames));
7521+
75027522
int maxdepth = stackdepth(c);
75037523
if (maxdepth < 0) {
75047524
goto error;

Python/importlib.h

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)