@@ -328,25 +328,68 @@ intern_strings(PyObject *tuple)
328328#define ABSOLUTE_JUMP (op ) (op==JUMP_ABSOLUTE || op==CONTINUE_LOOP)
329329#define GETJUMPTGT (arr , i ) (GETARG(arr,i) + (ABSOLUTE_JUMP(arr[i]) ? 0 : i+3))
330330#define SETARG (arr , i , val ) arr[i+2] = val>>8; arr[i+1] = val & 255
331+ #define CODESIZE (op ) (HAS_ARG(op) ? 3 : 1)
332+ #define ISBASICBLOCK (blocks , start , bytes ) (blocks[start]==blocks[start+bytes-1])
333+
334+ static unsigned int *
335+ markblocks (unsigned char * code , int len )
336+ {
337+ unsigned int * blocks = PyMem_Malloc (len * sizeof (int ));
338+ int i ,j , opcode , oldblock , newblock , blockcnt = 0 ;
339+
340+ if (blocks == NULL )
341+ return NULL ;
342+ memset (blocks , 0 , len * sizeof (int ));
343+ for (i = 0 ; i < len ; i += CODESIZE (opcode )) {
344+ opcode = code [i ];
345+ switch (opcode ) {
346+ case FOR_ITER :
347+ case JUMP_FORWARD :
348+ case JUMP_IF_FALSE :
349+ case JUMP_IF_TRUE :
350+ case JUMP_ABSOLUTE :
351+ case CONTINUE_LOOP :
352+ case SETUP_LOOP :
353+ case SETUP_EXCEPT :
354+ case SETUP_FINALLY :
355+ j = GETJUMPTGT (code , i );
356+ oldblock = blocks [j ];
357+ newblock = ++ blockcnt ;
358+ for (; j < len ; j ++ ) {
359+ if (blocks [j ] != (unsigned )oldblock )
360+ break ;
361+ blocks [j ] = newblock ;
362+ }
363+ break ;
364+ }
365+ }
366+ return blocks ;
367+ }
331368
332369static PyObject *
333370optimize_code (PyObject * code , PyObject * consts )
334371{
335372 int i , j , codelen ;
336373 int tgt , tgttgt , opcode ;
337374 unsigned char * codestr ;
375+ unsigned int * blocks ;
338376
339377 /* Make a modifiable copy of the code string */
340378 if (!PyString_Check (code ))
341379 goto exitUnchanged ;
342380 codelen = PyString_Size (code );
343381 codestr = PyMem_Malloc (codelen );
344- if (codestr == NULL )
382+ if (codestr == NULL )
345383 goto exitUnchanged ;
346384 codestr = memcpy (codestr , PyString_AS_STRING (code ), codelen );
385+ blocks = markblocks (codestr , codelen );
386+ if (blocks == NULL ) {
387+ PyMem_Free (codestr );
388+ goto exitUnchanged ;
389+ }
347390 assert (PyTuple_Check (consts ));
348391
349- for (i = 0 ; i < codelen - 7 ; i += HAS_ARG (codestr [i ]) ? 3 : 1 ) {
392+ for (i = 0 ; i < codelen ; i += CODESIZE (codestr [i ])) {
350393 opcode = codestr [i ];
351394 switch (opcode ) {
352395
@@ -363,8 +406,8 @@ optimize_code(PyObject *code, PyObject* consts)
363406 SETARG (codestr , i , 4 );
364407 break ;
365408
366- /* Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2 JMP+2.
367- Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2 JMP+1.
409+ /* Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2 JMP+2 NOP NOP .
410+ Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2 JMP+1 NOP .
368411 Note, these opcodes occur together only in assignment
369412 statements. Accordingly, the unpack opcode is never
370413 a jump target. */
@@ -377,20 +420,50 @@ optimize_code(PyObject *code, PyObject* consts)
377420 codestr [i ] = ROT_TWO ;
378421 codestr [i + 1 ] = JUMP_FORWARD ;
379422 SETARG (codestr , i + 1 , 2 );
380- codestr [i + 4 ] = DUP_TOP ; /* Filler codes used as NOPs */
381- codestr [i + 5 ] = POP_TOP ;
423+ codestr [i + 4 ] = NOP ;
424+ codestr [i + 5 ] = NOP ;
382425 continue ;
383426 }
384427 if (GETARG (codestr , i ) == 3 && \
385428 GETARG (codestr , i + 3 ) == 3 ) {
386429 codestr [i ] = ROT_THREE ;
387430 codestr [i + 1 ] = ROT_TWO ;
388431 codestr [i + 2 ] = JUMP_FORWARD ;
389- SETARG (codestr , i + 2 , 1 );
390- codestr [i + 5 ] = DUP_TOP ;
432+ SETARG (codestr , i + 2 , 1 );
433+ codestr [i + 5 ] = NOP ;
391434 }
392435 break ;
393436
437+ /* Simplify inverted tests.
438+ Must verify that sequence is a basic block because the jump
439+ can itself be a jump target. Also, must verify that *both*
440+ jump alternatives go to a POP_TOP. Otherwise, the code will
441+ expect the stack value to have been inverted. */
442+ case UNARY_NOT :
443+ if (codestr [i + 1 ] != JUMP_IF_FALSE || \
444+ codestr [i + 4 ] != POP_TOP || \
445+ !ISBASICBLOCK (blocks ,i ,5 ))
446+ continue ;
447+ tgt = GETJUMPTGT (codestr , (i + 1 ));
448+ if (codestr [tgt ] != POP_TOP )
449+ continue ;
450+ codestr [i ] = NOP ;
451+ codestr [i + 1 ] = JUMP_IF_TRUE ;
452+ break ;
453+
454+ /* not a is b --> a is not b
455+ not a in b --> a not in b
456+ not a is not b --> a is b
457+ not a not in b --> a in b */
458+ case COMPARE_OP :
459+ j = GETARG (codestr , i );
460+ if (codestr [i + 3 ] != UNARY_NOT || j < 6 || \
461+ j > 9 || !ISBASICBLOCK (blocks ,i ,4 ))
462+ continue ;
463+ SETARG (codestr , i , (j ^1 ));
464+ codestr [i + 3 ] = NOP ;
465+ break ;
466+
394467 /* Replace jumps to unconditional jumps */
395468 case FOR_ITER :
396469 case JUMP_FORWARD :
@@ -402,7 +475,7 @@ optimize_code(PyObject *code, PyObject* consts)
402475 case SETUP_EXCEPT :
403476 case SETUP_FINALLY :
404477 tgt = GETJUMPTGT (codestr , i );
405- if (!UNCONDITIONAL_JUMP (codestr [tgt ]))
478+ if (!UNCONDITIONAL_JUMP (codestr [tgt ]))
406479 continue ;
407480 tgttgt = GETJUMPTGT (codestr , tgt );
408481 if (opcode == JUMP_FORWARD ) /* JMP_ABS can go backwards */
@@ -422,6 +495,7 @@ optimize_code(PyObject *code, PyObject* consts)
422495 }
423496 code = PyString_FromStringAndSize (codestr , codelen );
424497 PyMem_Free (codestr );
498+ PyMem_Free (blocks );
425499 return code ;
426500
427501exitUnchanged :
0 commit comments