@@ -1336,6 +1336,18 @@ add_const(PyObject *newconst, PyObject *consts, PyObject *const_cache)
13361336 return (int )index ;
13371337}
13381338
1339+ static int
1340+ is_sequence_constant (cfg_instr * inst , int n )
1341+ {
1342+ for (int i = 0 ; i < n ; i ++ ) {
1343+ if (!loads_const (inst [i ].i_opcode )) {
1344+ return 0 ;
1345+ }
1346+ }
1347+ return 1 ;
1348+ }
1349+
1350+
13391351/* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cn, BUILD_TUPLE n
13401352 with LOAD_CONST (c1, c2, ... cn).
13411353 The consts table must still be in list form so that the
@@ -1353,17 +1365,60 @@ fold_tuple_on_constants(PyObject *const_cache,
13531365 assert (inst [n ].i_opcode == BUILD_TUPLE );
13541366 assert (inst [n ].i_oparg == n );
13551367
1368+ if (!is_sequence_constant (inst , n )) {
1369+ return SUCCESS ;
1370+ }
1371+
1372+ /* Buildup new tuple of constants */
1373+ PyObject * newconst = PyTuple_New (n );
1374+ if (newconst == NULL ) {
1375+ return ERROR ;
1376+ }
13561377 for (int i = 0 ; i < n ; i ++ ) {
1357- if (!loads_const (inst [i ].i_opcode )) {
1358- return SUCCESS ;
1378+ int op = inst [i ].i_opcode ;
1379+ int arg = inst [i ].i_oparg ;
1380+ PyObject * constant = get_const_value (op , arg , consts );
1381+ if (constant == NULL ) {
1382+ return ERROR ;
13591383 }
1384+ PyTuple_SET_ITEM (newconst , i , constant );
1385+ }
1386+ int index = add_const (newconst , consts , const_cache );
1387+ if (index < 0 ) {
1388+ return ERROR ;
1389+ }
1390+ for (int i = 0 ; i < n ; i ++ ) {
1391+ INSTR_SET_OP0 (& inst [i ], NOP );
1392+ }
1393+ INSTR_SET_OP1 (& inst [n ], LOAD_CONST , index );
1394+ return SUCCESS ;
1395+ }
1396+
1397+
1398+ // Replaces const set with a frozenset.
1399+ // This should be used only in situations where we 100% sure that
1400+ // this set cannot be changed: where's constant set is a rhs in `for` loop
1401+ // or it's a rhs in `in` operation.
1402+ static int
1403+ fold_set_on_constants (PyObject * const_cache ,
1404+ cfg_instr * inst ,
1405+ int n , PyObject * consts )
1406+ {
1407+ /* Pre-conditions */
1408+ assert (PyDict_CheckExact (const_cache ));
1409+ assert (PyList_CheckExact (consts ));
1410+ assert (inst [n ].i_opcode == BUILD_SET );
1411+ assert (inst [n ].i_oparg == n );
1412+
1413+ if (!is_sequence_constant (inst , n )) {
1414+ return SUCCESS ;
13601415 }
13611416
1362- /* Buildup new tuple of constants */
13631417 PyObject * newconst = PyTuple_New (n );
13641418 if (newconst == NULL ) {
13651419 return ERROR ;
13661420 }
1421+
13671422 for (int i = 0 ; i < n ; i ++ ) {
13681423 int op = inst [i ].i_opcode ;
13691424 int arg = inst [i ].i_oparg ;
@@ -1373,6 +1428,13 @@ fold_tuple_on_constants(PyObject *const_cache,
13731428 }
13741429 PyTuple_SET_ITEM (newconst , i , constant );
13751430 }
1431+
1432+ PyObject * frozenset = PyFrozenSet_New (newconst );
1433+ if (frozenset == NULL ) {
1434+ return ERROR ;
1435+ }
1436+ Py_SETREF (newconst , frozenset );
1437+
13761438 int index = add_const (newconst , consts , const_cache );
13771439 if (index < 0 ) {
13781440 return ERROR ;
@@ -1751,6 +1813,13 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
17511813 }
17521814 }
17531815 break ;
1816+ case BUILD_SET :
1817+ if (nextop == CONTAINS_OP || nextop == GET_ITER ) {
1818+ if (fold_set_on_constants (const_cache , inst - oparg , oparg , consts )) {
1819+ goto error ;
1820+ }
1821+ }
1822+ break ;
17541823 case POP_JUMP_IF_NOT_NONE :
17551824 case POP_JUMP_IF_NONE :
17561825 switch (target -> i_opcode ) {
0 commit comments