@@ -326,16 +326,21 @@ _Py_uop_sym_set_type(JitOptContext *ctx, JitOptRef ref, PyTypeObject *typ)
326326 case JIT_SYM_RECORDED_VALUE_TAG :
327327 if (Py_TYPE (sym -> recorded_value .value ) == typ ) {
328328 sym -> recorded_value .known_type = true;
329- return ;
330329 }
331- sym -> tag = JIT_SYM_KNOWN_CLASS_TAG ;
332- sym -> cls . version = 0 ;
333- sym -> cls . type = typ ;
330+ else {
331+ sym_set_bottom ( ctx , sym ) ;
332+ }
334333 return ;
335334 case JIT_SYM_RECORDED_TYPE_TAG :
336- /* The given value might contradict the recorded one,
337- * in which case we could return bottom.
338- * Just discard the recorded value for now */
335+ if (sym -> recorded_type .type == typ ) {
336+ sym -> tag = JIT_SYM_KNOWN_CLASS_TAG ;
337+ sym -> cls .version = 0 ;
338+ sym -> cls .type = typ ;
339+ }
340+ else {
341+ sym_set_bottom (ctx , sym );
342+ }
343+ return ;
339344 case JIT_SYM_NON_NULL_TAG :
340345 case JIT_SYM_UNKNOWN_TAG :
341346 sym -> tag = JIT_SYM_KNOWN_CLASS_TAG ;
@@ -429,23 +434,23 @@ _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptRef ref, unsigned int ver
429434 sym -> tag = JIT_SYM_KNOWN_CLASS_TAG ;
430435 sym -> cls .type = Py_TYPE (sym -> recorded_value .value );
431436 sym -> cls .version = version ;
437+ return true;
432438 }
433439 else {
434- sym -> tag = JIT_SYM_TYPE_VERSION_TAG ;
435- sym -> version . version = version ;
440+ sym_set_bottom ( ctx , sym ) ;
441+ return false ;
436442 }
437- return true;
438443 case JIT_SYM_RECORDED_TYPE_TAG :
439444 if (sym -> recorded_type .type -> tp_version_tag == version ) {
440445 sym -> tag = JIT_SYM_KNOWN_CLASS_TAG ;
441446 sym -> cls .type = sym -> recorded_type .type ;
442447 sym -> cls .version = version ;
448+ return true;
443449 }
444450 else {
445- sym -> tag = JIT_SYM_TYPE_VERSION_TAG ;
446- sym -> version . version = version ;
451+ sym_set_bottom ( ctx , sym ) ;
452+ return false ;
447453 }
448- return true;
449454 }
450455 Py_UNREACHABLE ();
451456}
@@ -658,7 +663,6 @@ _Py_uop_sym_get_type(JitOptRef ref)
658663 case JIT_SYM_NON_NULL_TAG :
659664 case JIT_SYM_UNKNOWN_TAG :
660665 case JIT_SYM_RECORDED_TYPE_TAG :
661- case JIT_SYM_RECORDED_GEN_FUNC_TAG :
662666 return NULL ;
663667 case JIT_SYM_RECORDED_VALUE_TAG :
664668 if (sym -> recorded_value .known_type ) {
@@ -678,6 +682,8 @@ _Py_uop_sym_get_type(JitOptRef ref)
678682 return & PyBool_Type ;
679683 case JIT_SYM_COMPACT_INT :
680684 return & PyLong_Type ;
685+ case JIT_SYM_RECORDED_GEN_FUNC_TAG :
686+ return & PyGen_Type ;
681687 }
682688 Py_UNREACHABLE ();
683689}
@@ -1127,6 +1133,9 @@ _Py_uop_sym_set_recorded_value(JitOptContext *ctx, JitOptRef ref, PyObject *valu
11271133 sym -> recorded_value .known_type = true;
11281134 sym -> recorded_value .value = value ;
11291135 }
1136+ else {
1137+ sym_set_bottom (ctx , sym );
1138+ }
11301139 return ;
11311140 case JIT_SYM_KNOWN_VALUE_TAG :
11321141 return ;
@@ -1136,6 +1145,9 @@ _Py_uop_sym_set_recorded_value(JitOptContext *ctx, JitOptRef ref, PyObject *valu
11361145 sym -> recorded_value .known_type = true;
11371146 sym -> recorded_value .value = value ;
11381147 }
1148+ else {
1149+ sym_set_bottom (ctx , sym );
1150+ }
11391151 return ;
11401152 // In these cases the original information is more valuable
11411153 case JIT_SYM_RECORDED_GEN_FUNC_TAG :
@@ -1189,6 +1201,9 @@ _Py_uop_sym_set_recorded_gen_func(JitOptContext *ctx, JitOptRef ref, PyFunctionO
11891201 sym -> tag = JIT_SYM_RECORDED_GEN_FUNC_TAG ;
11901202 sym -> recorded_gen_func .func = value ;
11911203 }
1204+ else {
1205+ sym_set_bottom (ctx , sym );
1206+ }
11921207 return ;
11931208 case JIT_SYM_TYPE_VERSION_TAG :
11941209 if (sym -> version .version == PyGen_Type .tp_version_tag ) {
@@ -1249,6 +1264,9 @@ _Py_uop_sym_set_recorded_type(JitOptContext *ctx, JitOptRef ref, PyTypeObject *t
12491264 sym -> tag = JIT_SYM_KNOWN_CLASS_TAG ;
12501265 sym -> cls .type = type ;
12511266 }
1267+ else {
1268+ sym_set_bottom (ctx , sym );
1269+ }
12521270 return ;
12531271 // In these cases the original information is more valuable
12541272 case JIT_SYM_TUPLE_TAG :
@@ -1461,6 +1479,7 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
14611479 PyObject * val_43 = NULL ;
14621480 PyObject * val_big = NULL ;
14631481 PyObject * tuple = NULL ;
1482+ PyFunctionObject * func = NULL ;
14641483
14651484 // Use a single 'sym' variable so copy-pasting tests is easier.
14661485 JitOptRef ref = _Py_uop_sym_new_unknown (ctx );
@@ -1871,19 +1890,127 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
18711890 TEST_PREDICATE (_Py_uop_sym_matches_type (ref_int , & PyLong_Type ), "43 is not an int" );
18721891 TEST_PREDICATE (_Py_uop_sym_get_const (ctx , ref_int ) == val_43 , "43 isn't 43" );
18731892
1893+ // Test recorded values
1894+
1895+ /* Test that recorded values aren't treated as known values*/
1896+ JitOptRef rv1 = _Py_uop_sym_new_unknown (ctx );
1897+ _Py_uop_sym_set_recorded_value (ctx , rv1 , val_42 );
1898+ TEST_PREDICATE (!_Py_uop_sym_matches_type (rv1 , & PyLong_Type ), "recorded value is treated as known" );
1899+ TEST_PREDICATE (_Py_uop_sym_get_const (ctx , rv1 ) == NULL , "recorded value is treated as known" );
1900+ TEST_PREDICATE (!_Py_uop_sym_is_compact_int (rv1 ), "recorded value is treated as known" );
1901+
1902+ /* Test that setting type or value narrows correctly */
1903+ JitOptRef rv2 = _Py_uop_sym_new_unknown (ctx );
1904+ _Py_uop_sym_set_recorded_value (ctx , rv2 , val_42 );
1905+ _Py_uop_sym_set_const (ctx , rv2 , val_42 );
1906+ TEST_PREDICATE (_Py_uop_sym_matches_type (rv2 , & PyLong_Type ), "recorded value doesn't narrow" );
1907+ TEST_PREDICATE (_Py_uop_sym_get_const (ctx , rv2 ) == val_42 , "recorded value doesn't narrow" );
1908+
1909+ JitOptRef rv3 = _Py_uop_sym_new_unknown (ctx );
1910+ _Py_uop_sym_set_recorded_value (ctx , rv3 , val_42 );
1911+ _Py_uop_sym_set_type (ctx , rv3 , & PyLong_Type );
1912+ TEST_PREDICATE (_Py_uop_sym_matches_type (rv3 , & PyLong_Type ), "recorded value doesn't narrow" );
1913+ TEST_PREDICATE (_Py_uop_sym_get_const (ctx , rv3 ) == NULL , "recorded value with type is treated as known" );
1914+
1915+ JitOptRef rv4 = _Py_uop_sym_new_unknown (ctx );
1916+ _Py_uop_sym_set_recorded_value (ctx , rv4 , val_42 );
1917+ _Py_uop_sym_set_type_version (ctx , rv4 , PyLong_Type .tp_version_tag );
1918+ TEST_PREDICATE (_Py_uop_sym_matches_type (rv4 , & PyLong_Type ), "recorded value doesn't narrow" );
1919+ TEST_PREDICATE (_Py_uop_sym_get_const (ctx , rv4 ) == NULL , "recorded value with type is treated as known" );
1920+
1921+ // test recorded types
1922+
1923+ /* Test that recorded type aren't treated as known values*/
1924+ JitOptRef rt1 = _Py_uop_sym_new_unknown (ctx );
1925+ _Py_uop_sym_set_recorded_type (ctx , rt1 , & PyLong_Type );
1926+ TEST_PREDICATE (!_Py_uop_sym_matches_type (rt1 , & PyLong_Type ), "recorded type is treated as known" );
1927+ TEST_PREDICATE (_Py_uop_sym_get_const (ctx , rt1 ) == NULL , "recorded type is treated as known value" );
1928+
1929+ /* Test that setting type or value narrows correctly */
1930+ JitOptRef rt2 = _Py_uop_sym_new_unknown (ctx );
1931+ _Py_uop_sym_set_recorded_type (ctx , rt2 , & PyLong_Type );
1932+ _Py_uop_sym_set_const (ctx , rt2 , val_42 );
1933+ TEST_PREDICATE (_Py_uop_sym_matches_type (rt2 , & PyLong_Type ), "recorded value doesn't narrow" );
1934+ TEST_PREDICATE (_Py_uop_sym_get_const (ctx , rt2 ) == val_42 , "recorded value doesn't narrow" );
1935+
1936+ JitOptRef rt3 = _Py_uop_sym_new_unknown (ctx );
1937+ _Py_uop_sym_set_recorded_type (ctx , rt3 , & PyLong_Type );
1938+ _Py_uop_sym_set_type (ctx , rt3 , & PyLong_Type );
1939+ TEST_PREDICATE (_Py_uop_sym_matches_type (rt3 , & PyLong_Type ), "recorded value doesn't narrow" );
1940+ TEST_PREDICATE (_Py_uop_sym_get_const (ctx , rt3 ) == NULL , "known type is treated as known value" );
1941+
1942+ JitOptRef rt4 = _Py_uop_sym_new_unknown (ctx );
1943+ _Py_uop_sym_set_recorded_type (ctx , rt4 , & PyLong_Type );
1944+ _Py_uop_sym_set_type_version (ctx , rt4 , PyLong_Type .tp_version_tag );
1945+ TEST_PREDICATE (_Py_uop_sym_matches_type (rt4 , & PyLong_Type ), "recorded value doesn't narrow" );
1946+ TEST_PREDICATE (_Py_uop_sym_get_const (ctx , rt4 ) == NULL , "recorded value with type is treated as known" );
1947+
1948+ // test recorded gen function
1949+
1950+ PyObject * dict = PyDict_New ();
1951+ if (dict == NULL ) {
1952+ goto fail ;
1953+ }
1954+ PyCodeObject * code = PyCode_NewEmpty (__FILE__ , "uop_symbols_test" , __LINE__ );
1955+ if (code == NULL ) {
1956+ goto fail ;
1957+ }
1958+ func = (PyFunctionObject * )PyFunction_New ((PyObject * )code , dict );
1959+ if (func == NULL ) {
1960+ goto fail ;
1961+ }
1962+
1963+ /* Test that recorded type aren't treated as known values*/
1964+ JitOptRef rg1 = _Py_uop_sym_new_unknown (ctx );
1965+ _Py_uop_sym_set_recorded_gen_func (ctx , rg1 , func );
1966+ TEST_PREDICATE (_Py_uop_sym_matches_type (rg1 , & PyGen_Type ), "recorded gen func not treated as generator" );
1967+ TEST_PREDICATE (_Py_uop_sym_get_const (ctx , rg1 ) == NULL , "recorded gen func is treated as known value" );
1968+
1969+ /* Test that setting type narrows correctly */
1970+
1971+ JitOptRef rg2 = _Py_uop_sym_new_unknown (ctx );
1972+ _Py_uop_sym_set_recorded_gen_func (ctx , rg2 , func );
1973+ _Py_uop_sym_set_type (ctx , rg2 , & PyGen_Type );
1974+ TEST_PREDICATE (_Py_uop_sym_matches_type (rg1 , & PyGen_Type ), "recorded gen func not treated as generator" );
1975+ TEST_PREDICATE (_Py_uop_sym_get_const (ctx , rg2 ) == NULL , "known type is treated as known value" );
1976+
1977+ JitOptRef rg3 = _Py_uop_sym_new_unknown (ctx );
1978+ _Py_uop_sym_set_recorded_gen_func (ctx , rg3 , func );
1979+ _Py_uop_sym_set_type_version (ctx , rg3 , PyGen_Type .tp_version_tag );
1980+ TEST_PREDICATE (_Py_uop_sym_matches_type (rg1 , & PyGen_Type ), "recorded gen func not treated as generator" );
1981+ TEST_PREDICATE (_Py_uop_sym_get_const (ctx , rg3 ) == NULL , "recorded value with type is treated as known" );
1982+
1983+ /* Test contradictions */
1984+ _Py_uop_sym_set_type (ctx , rv1 , & PyFloat_Type );
1985+ TEST_PREDICATE (_Py_uop_sym_is_bottom (rv1 ), "recorded value cast to other type isn't bottom" );
1986+ _Py_uop_sym_set_type_version (ctx , rv2 , PyFloat_Type .tp_version_tag );
1987+ TEST_PREDICATE (_Py_uop_sym_is_bottom (rv2 ), "recorded value cast to other type version isn't bottom" );
1988+
1989+ _Py_uop_sym_set_type (ctx , rt1 , & PyFloat_Type );
1990+ TEST_PREDICATE (_Py_uop_sym_is_bottom (rv1 ), "recorded type cast to other type isn't bottom" );
1991+ _Py_uop_sym_set_type_version (ctx , rt2 , PyFloat_Type .tp_version_tag );
1992+ TEST_PREDICATE (_Py_uop_sym_is_bottom (rv2 ), "recorded type cast to other type version isn't bottom" );
1993+
1994+ _Py_uop_sym_set_type (ctx , rg1 , & PyFloat_Type );
1995+ TEST_PREDICATE (_Py_uop_sym_is_bottom (rg1 ), "recorded gen func cast to other type isn't bottom" );
1996+ _Py_uop_sym_set_type_version (ctx , rg2 , PyFloat_Type .tp_version_tag );
1997+ TEST_PREDICATE (_Py_uop_sym_is_bottom (rg2 ), "recorded gen func cast to other type version isn't bottom" );
1998+
18741999 _Py_uop_abstractcontext_fini (ctx );
18752000 Py_DECREF (val_42 );
18762001 Py_DECREF (val_43 );
18772002 Py_DECREF (val_big );
18782003 Py_DECREF (tuple );
2004+ Py_DECREF (func );
18792005 Py_RETURN_NONE ;
18802006
18812007fail :
18822008 _Py_uop_abstractcontext_fini (ctx );
18832009 Py_XDECREF (val_42 );
18842010 Py_XDECREF (val_43 );
18852011 Py_XDECREF (val_big );
1886- Py_DECREF (tuple );
2012+ Py_XDECREF (tuple );
2013+ Py_XDECREF (func );
18872014 return NULL ;
18882015}
18892016
0 commit comments