@@ -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+
326419PyCodeObject *
327420PyCode_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