Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f6f575a

Browse files
committed
SF patch #707257: Improve code generation
Adds a single function to improve generated bytecode. Has a single line attachment point, so it is completely de-coupled from both the compiler and ceval.c. Makes three simple transforms that do not require a basic block analysis or re-ordering of code. Gives improved timings on pystone, pybench, and any code using either "while 1" or "x,y=y,x".
1 parent 590fe02 commit f6f575a

1 file changed

Lines changed: 94 additions & 2 deletions

File tree

Python/compile.c

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,99 @@ intern_strings(PyObject *tuple)
323323
return 0;
324324
}
325325

326+
#define GETARG(arr, i) ((int)((arr[i+2]<<8) + arr[i+1]))
327+
#define UNCONDITIONAL_JUMP(op) (op==JUMP_ABSOLUTE || op==JUMP_FORWARD)
328+
#define GETJUMPTGT(arr, i) (GETARG(arr,i) + (arr[i]==JUMP_ABSOLUTE ? 0 : i+3))
329+
#define SETARG(arr, i, val) arr[i+2] = val>>8; arr[i+1] = val & 255
330+
331+
static PyObject *
332+
optimize_code(PyObject *code, PyObject* consts)
333+
{
334+
int i, j, codelen;
335+
int tgt, tgttgt, opcode;
336+
unsigned char *codestr;
337+
338+
/* Make a modifiable copy of the code string */
339+
if (!PyString_Check(code))
340+
goto exitUnchanged;
341+
codelen = PyString_Size(code);
342+
codestr = PyMem_Malloc(codelen);
343+
if (codestr == NULL)
344+
goto exitUnchanged;
345+
codestr = memcpy(codestr, PyString_AS_STRING(code), codelen);
346+
assert(PyTuple_Check(consts));
347+
348+
for (i=0 ; i<codelen-7 ; i += HAS_ARG(codestr[i]) ? 3 : 1) {
349+
opcode = codestr[i];
350+
switch (opcode) {
351+
352+
/* Skip over LOAD_CONST trueconst JUMP_IF_FALSE xx POP_TOP.
353+
Note, only the first opcode is changed, the others still
354+
perform normally if they happen to be jump targets. */
355+
case LOAD_CONST:
356+
j = GETARG(codestr, i);
357+
if (codestr[i+3] != JUMP_IF_FALSE ||
358+
codestr[i+6] != POP_TOP ||
359+
!PyObject_IsTrue(PyTuple_GET_ITEM(consts, j)))
360+
continue;
361+
codestr[i] = JUMP_FORWARD;
362+
SETARG(codestr, i, 4);
363+
break;
364+
365+
/* Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2 JMP+2.
366+
Note, these opcodes occur together only in assignment
367+
statements. Accordingly, the unpack opcode is never
368+
a jump target. */
369+
case BUILD_TUPLE:
370+
case BUILD_LIST:
371+
if (codestr[i+3] != UNPACK_SEQUENCE ||
372+
GETARG(codestr, i) != 2 ||
373+
GETARG(codestr, i+3) != 2)
374+
continue;
375+
codestr[i] = ROT_TWO;
376+
codestr[i+1] = JUMP_FORWARD;
377+
SETARG(codestr, i+1, 2);
378+
codestr[i+4] = DUP_TOP; /* Filler codes used as NOPs */
379+
codestr[i+5] = POP_TOP;
380+
break;
381+
382+
/* Replace jumps to unconditional jumps */
383+
case JUMP_FORWARD:
384+
case JUMP_IF_FALSE:
385+
case JUMP_IF_TRUE:
386+
case JUMP_ABSOLUTE:
387+
case CONTINUE_LOOP:
388+
case SETUP_LOOP:
389+
case SETUP_EXCEPT:
390+
case SETUP_FINALLY:
391+
tgt = GETJUMPTGT(codestr, i);
392+
if (!UNCONDITIONAL_JUMP(codestr[tgt]))
393+
continue;
394+
tgttgt = GETJUMPTGT(codestr, tgt);
395+
if (opcode == JUMP_FORWARD) /* JMP_ABS can go backwards */
396+
opcode = JUMP_ABSOLUTE;
397+
if (opcode != JUMP_ABSOLUTE && opcode != CONTINUE_LOOP)
398+
tgttgt -= i + 3; /* Calc relative jump addr */
399+
if (tgttgt < 0) /* No backward relative jumps */
400+
continue;
401+
codestr[i] = opcode;
402+
SETARG(codestr, i, tgttgt);
403+
break;
404+
405+
case EXTENDED_ARG:
406+
PyMem_Free(codestr);
407+
goto exitUnchanged;
408+
}
409+
}
410+
code = PyString_FromStringAndSize(codestr, codelen);
411+
PyMem_Free(codestr);
412+
return code;
413+
414+
exitUnchanged:
415+
Py_INCREF(code);
416+
return code;
417+
}
418+
326419
PyCodeObject *
327420
PyCode_New(int argcount, int nlocals, int stacksize, int flags,
328421
PyObject *code, PyObject *consts, PyObject *names,
@@ -366,8 +459,7 @@ PyCode_New(int argcount, int nlocals, int stacksize, int flags,
366459
co->co_nlocals = nlocals;
367460
co->co_stacksize = stacksize;
368461
co->co_flags = flags;
369-
Py_INCREF(code);
370-
co->co_code = code;
462+
co->co_code = optimize_code(code, consts);
371463
Py_INCREF(consts);
372464
co->co_consts = consts;
373465
Py_INCREF(names);

0 commit comments

Comments
 (0)