diff -r f82399cc67d6 -r 0badacc78470 Lib/test/test_dis.py --- a/Lib/test/test_dis.py Sun Nov 27 11:39:35 2016 +0100 +++ b/Lib/test/test_dis.py Sun Nov 27 11:39:57 2016 +0100 @@ -679,9 +679,9 @@ # End fodder for opinfo generation tests expected_outer_line = 1 _line_offset = outer.__code__.co_firstlineno - 1 -code_object_f = outer.__code__.co_consts[3] +code_object_f = outer.__code__.co_consts[1] expected_f_line = code_object_f.co_firstlineno - _line_offset -code_object_inner = code_object_f.co_consts[3] +code_object_inner = code_object_f.co_consts[1] expected_inner_line = code_object_inner.co_firstlineno - _line_offset expected_jumpy_line = 1 @@ -706,22 +706,22 @@ Instruction = dis.Instruction expected_opinfo_outer = [ - Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval=(3, 4), argrepr='(3, 4)', offset=0, starts_line=2, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval=(3, 4), argrepr='(3, 4)', offset=0, starts_line=2, is_jump_target=False), Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False), Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=6, starts_line=None, is_jump_target=False), - 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), - Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer..f', argrepr="'outer..f'", offset=10, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=code_object_f, argrepr=repr(code_object_f), offset=8, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval='outer..f', argrepr="'outer..f'", offset=10, starts_line=None, is_jump_target=False), Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='', offset=12, starts_line=None, is_jump_target=False), Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=14, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=16, starts_line=7, is_jump_target=False), Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='a', argrepr='a', offset=18, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='b', argrepr='b', offset=20, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval='', argrepr="''", offset=22, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval=1, argrepr='1', offset=24, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval='', argrepr="''", offset=22, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval=1, argrepr='1', offset=24, starts_line=None, is_jump_target=False), Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=26, starts_line=None, is_jump_target=False), Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=28, starts_line=None, is_jump_target=False), - Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval='Hello world!', argrepr="'Hello world!'", offset=30, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval='Hello world!', argrepr="'Hello world!'", offset=30, starts_line=None, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=7, argval=7, argrepr='', offset=32, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=34, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=36, starts_line=8, is_jump_target=False), @@ -729,14 +729,14 @@ ] expected_opinfo_f = [ - Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=(5, 6), argrepr='(5, 6)', offset=0, starts_line=3, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=(5, 6), argrepr='(5, 6)', offset=0, starts_line=3, is_jump_target=False), Instruction(opname='LOAD_CLOSURE', opcode=135, arg=2, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CLOSURE', opcode=135, arg=3, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='c', argrepr='c', offset=6, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='d', argrepr='d', offset=8, starts_line=None, is_jump_target=False), Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=10, starts_line=None, is_jump_target=False), - 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), - Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer..f..inner', argrepr="'outer..f..inner'", offset=14, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=code_object_inner, argrepr=repr(code_object_inner), offset=12, starts_line=None, is_jump_target=False), + Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval='outer..f..inner', argrepr="'outer..f..inner'", offset=14, starts_line=None, is_jump_target=False), Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='', offset=16, starts_line=None, is_jump_target=False), Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=18, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=20, starts_line=5, is_jump_target=False), diff -r f82399cc67d6 -r 0badacc78470 Python/peephole.c --- a/Python/peephole.c Sun Nov 27 11:39:35 2016 +0100 +++ b/Python/peephole.c Sun Nov 27 11:39:57 2016 +0100 @@ -22,6 +22,10 @@ #define ISBASICBLOCK(blocks, start, end) \ (blocks[start]==blocks[end]) +struct const_uses_entry { + unsigned int uses; + unsigned int relocation; +}; #define CONST_STACK_CREATE() { \ const_stack_size = 256; \ @@ -30,11 +34,19 @@ PyErr_NoMemory(); \ goto exitError; \ } \ + const_uses_curr_size = const_uses_size = PyList_GET_SIZE(consts); \ + const_uses = PyMem_New(struct const_uses_entry, const_uses_size); \ + if (!const_uses) { \ + PyErr_NoMemory(); \ + goto exitError; \ + } \ + memset(const_uses, 0, const_uses_size * sizeof(struct const_uses_entry)); \ } #define CONST_STACK_DELETE() do { \ if (const_stack) \ PyMem_Free(const_stack); \ + PyMem_Free(const_uses); \ } while(0) #define CONST_STACK_LEN() ((unsigned)(const_stack_top + 1)) @@ -50,7 +62,21 @@ goto exitError; \ } \ } \ - const_stack[const_stack_top] = get_arg(codestr, i); \ + int arg = get_arg(codestr, i); \ + const_stack[const_stack_top] = arg; \ + if (arg >= const_uses_curr_size) {\ + const_uses_curr_size = arg + 1; \ + if (const_uses_curr_size > const_uses_size) {\ + const_uses_size *= 2; \ + PyMem_Resize(const_uses, struct const_uses_entry, const_uses_size); \ + if (!const_uses) { \ + PyErr_NoMemory(); \ + goto exitError; \ + } \ + for (int z = arg; z < const_uses_size; ++z) const_uses[z].uses = 0; \ + } \ + }\ + const_uses[arg].uses += 1; \ in_consts = 1; \ } while(0) @@ -64,6 +90,8 @@ #define CONST_STACK_POP(i) do { \ assert(CONST_STACK_LEN() >= i); \ const_stack_top -= i; \ + for (unsigned int z = 0; z < i; ++z) \ + const_uses[const_stack[const_stack_top+z+1]].uses -= 1; \ } while(0) #define CONST_GET(i) (PyList_GET_ITEM((consts), (i))) @@ -436,6 +464,9 @@ unsigned int *const_stack = NULL; Py_ssize_t const_stack_top = -1; Py_ssize_t const_stack_size = 0; + struct const_uses_entry *const_uses = NULL; + Py_ssize_t const_uses_curr_size = 0; + Py_ssize_t const_uses_size = 0; int in_consts = 0; /* whether we are in a LOAD_CONST sequence */ unsigned int *blocks = NULL; @@ -738,7 +769,34 @@ last_offset = new_offset; } - /* Remove NOPs and fixup jump targets */ + assert(PyList_GET_SIZE(consts) == const_uses_curr_size); + + /* move used consts to the front of the list; remove unused + we skip the first const since it's either + - a string which will later become a docstring + - something else - unfortunately we can't remove it, since it could + move a string to the first cell and thus make it a docstring + */ + const_uses[0].relocation = 0; + unsigned int relocation = 1; + for (int i = 1; i < const_uses_curr_size; ++i) { + PyObject *item = PyList_GET_ITEM(consts, i); + if (const_uses[i].uses == 0) { + Py_DECREF(item); + continue; + } + const_uses[i].relocation = relocation; + PyList_SET_ITEM(consts, relocation, item); + relocation++; + } + for (int i = relocation; i < const_uses_curr_size; ++i) + PyList_SET_ITEM(consts, i, NULL); + + /* shrink consts as needed */ + if (PyList_SetSlice(consts, relocation, const_uses_curr_size, NULL) < 0) + goto exitError; + + /* Remove NOPs, fixup jump targets and LOAD_CONST args */ for (op_start = i = h = 0; i < codelen; i++, op_start = i) { j = _Py_OPARG(codestr[i]); while (_Py_OPCODE(codestr[i]) == EXTENDED_ARG) { @@ -749,6 +807,10 @@ switch (opcode) { case NOP:continue; + case LOAD_CONST: + j = const_uses[j].relocation; + break; + case JUMP_ABSOLUTE: case CONTINUE_LOOP: case POP_JUMP_IF_FALSE: