@@ -113,6 +113,9 @@ _PyUOpSymPrint(JitOptRef ref)
113113 case JIT_SYM_COMPACT_INT :
114114 printf ("<compact_int at %p>" , (void * )sym );
115115 break ;
116+ case JIT_SYM_SLOTS_TAG :
117+ printf ("<slots[%d] v%u at %p>" , sym -> slots .num_slots , sym -> slots .type_version , (void * )sym );
118+ break ;
116119 default :
117120 printf ("<tag=%d at %p>" , sym -> tag , (void * )sym );
118121 break ;
@@ -319,6 +322,11 @@ _Py_uop_sym_set_type(JitOptContext *ctx, JitOptRef ref, PyTypeObject *typ)
319322 sym_set_bottom (ctx , sym );
320323 }
321324 return ;
325+ case JIT_SYM_SLOTS_TAG :
326+ if (typ -> tp_version_tag != sym -> slots .type_version ) {
327+ sym_set_bottom (ctx , sym );
328+ }
329+ return ;
322330 }
323331}
324332
@@ -382,6 +390,12 @@ _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptRef ref, unsigned int ver
382390 return false;
383391 }
384392 return true;
393+ case JIT_SYM_SLOTS_TAG :
394+ if (version != sym -> slots .type_version ) {
395+ sym_set_bottom (ctx , sym );
396+ return false;
397+ }
398+ return true;
385399 }
386400 Py_UNREACHABLE ();
387401}
@@ -474,6 +488,9 @@ _Py_uop_sym_set_const(JitOptContext *ctx, JitOptRef ref, PyObject *const_val)
474488 sym_set_bottom (ctx , sym );
475489 }
476490 return ;
491+ case JIT_SYM_SLOTS_TAG :
492+ sym_set_bottom (ctx , sym );
493+ return ;
477494 }
478495}
479496
@@ -593,7 +610,8 @@ _Py_uop_sym_get_type(JitOptRef ref)
593610 return & PyBool_Type ;
594611 case JIT_SYM_COMPACT_INT :
595612 return & PyLong_Type ;
596-
613+ case JIT_SYM_SLOTS_TAG :
614+ return _PyType_LookupByVersion (sym -> slots .type_version );
597615 }
598616 Py_UNREACHABLE ();
599617}
@@ -621,6 +639,8 @@ _Py_uop_sym_get_type_version(JitOptRef ref)
621639 return PyBool_Type .tp_version_tag ;
622640 case JIT_SYM_COMPACT_INT :
623641 return PyLong_Type .tp_version_tag ;
642+ case JIT_SYM_SLOTS_TAG :
643+ return sym -> slots .type_version ;
624644 }
625645 Py_UNREACHABLE ();
626646}
@@ -655,6 +675,7 @@ _Py_uop_sym_truthiness(JitOptContext *ctx, JitOptRef ref)
655675 case JIT_SYM_NON_NULL_TAG :
656676 case JIT_SYM_UNKNOWN_TAG :
657677 case JIT_SYM_COMPACT_INT :
678+ case JIT_SYM_SLOTS_TAG :
658679 return -1 ;
659680 case JIT_SYM_KNOWN_CLASS_TAG :
660681 /* TODO :
@@ -811,6 +832,7 @@ _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef ref)
811832 return ;
812833 case JIT_SYM_TUPLE_TAG :
813834 case JIT_SYM_TRUTHINESS_TAG :
835+ case JIT_SYM_SLOTS_TAG :
814836 sym_set_bottom (ctx , sym );
815837 return ;
816838 case JIT_SYM_BOTTOM_TAG :
@@ -859,6 +881,74 @@ _Py_uop_sym_new_compact_int(JitOptContext *ctx)
859881 return PyJitRef_Wrap (sym );
860882}
861883
884+ JitOptRef
885+ _Py_uop_sym_new_slots_object (JitOptContext * ctx , unsigned int type_version )
886+ {
887+ JitOptSymbol * res = sym_new (ctx );
888+ if (res == NULL ) {
889+ return out_of_space_ref (ctx );
890+ }
891+ res -> tag = JIT_SYM_SLOTS_TAG ;
892+ res -> slots .num_slots = 0 ;
893+ res -> slots .type_version = type_version ;
894+ return PyJitRef_Wrap (res );
895+ }
896+
897+ JitOptRef
898+ _Py_uop_sym_slots_getattr (JitOptContext * ctx , JitOptRef ref , uint16_t slot_index )
899+ {
900+ JitOptSymbol * sym = PyJitRef_Unwrap (ref );
901+
902+ if (sym -> tag == JIT_SYM_SLOTS_TAG ) {
903+ // Linear search through the mapping array
904+ for (int i = 0 ; i < sym -> slots .num_slots ; i ++ ) {
905+ if (sym -> slots .slots [i ].slot_index == slot_index ) {
906+ return PyJitRef_Wrap (allocation_base (ctx ) + sym -> slots .slots [i ].symbol );
907+ }
908+ }
909+ }
910+
911+ // Not found, return not_null
912+ return _Py_uop_sym_new_not_null (ctx );
913+ }
914+
915+ void
916+ _Py_uop_sym_slots_setattr (JitOptContext * ctx , JitOptRef ref , uint16_t slot_index , JitOptRef value )
917+ {
918+ JitOptSymbol * sym = PyJitRef_Unwrap (ref );
919+
920+ if (sym -> tag == JIT_SYM_TYPE_VERSION_TAG ) {
921+ uint32_t version = sym -> version .version ;
922+ sym -> tag = JIT_SYM_SLOTS_TAG ;
923+ sym -> slots .type_version = version ;
924+ sym -> slots .num_slots = 0 ;
925+ }
926+ else if (sym -> tag == JIT_SYM_KNOWN_CLASS_TAG ) {
927+ uint32_t version = sym -> cls .version ;
928+ sym -> tag = JIT_SYM_SLOTS_TAG ;
929+ sym -> slots .type_version = version ;
930+ sym -> slots .num_slots = 0 ;
931+ }
932+ else if (sym -> tag != JIT_SYM_SLOTS_TAG ) {
933+ return ;
934+ }
935+
936+ if (sym -> slots .num_slots >= MAX_SYMBOLIC_SLOTS_SIZE ) {
937+ return ;
938+ }
939+
940+ for (int i = 0 ; i < sym -> slots .num_slots ; i ++ ) {
941+ if (sym -> slots .slots [i ].slot_index == slot_index ) {
942+ sym -> slots .slots [i ].symbol = (uint16_t )(PyJitRef_Unwrap (value ) - allocation_base (ctx ));
943+ return ;
944+ }
945+ }
946+
947+ int idx = sym -> slots .num_slots ++ ;
948+ sym -> slots .slots [idx ].slot_index = slot_index ;
949+ sym -> slots .slots [idx ].symbol = (uint16_t )(PyJitRef_Unwrap (value ) - allocation_base (ctx ));
950+ }
951+
862952// 0 on success, -1 on error.
863953_Py_UOpsAbstractFrame *
864954_Py_uop_frame_new (
@@ -1186,6 +1276,33 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
11861276 TEST_PREDICATE (_Py_uop_sym_matches_type (ref_int , & PyLong_Type ), "43 is not an int" );
11871277 TEST_PREDICATE (_Py_uop_sym_get_const (ctx , ref_int ) == val_43 , "43 isn't 43" );
11881278
1279+ JitOptRef slots_obj = _Py_uop_sym_new_slots_object (ctx , 42 );
1280+ TEST_PREDICATE (!_Py_uop_sym_is_null (slots_obj ), "slots object is NULL" );
1281+ TEST_PREDICATE (_Py_uop_sym_is_not_null (slots_obj ), "slots object is not not-null" );
1282+ TEST_PREDICATE (_Py_uop_sym_get_type_version (slots_obj ) == 42 ,
1283+ "slots object has wrong type version" );
1284+
1285+ JitOptRef slot_val = _Py_uop_sym_new_const (ctx , val_42 );
1286+ _Py_uop_sym_slots_setattr (ctx , slots_obj , 0 , slot_val );
1287+ JitOptRef retrieved = _Py_uop_sym_slots_getattr (ctx , slots_obj , 0 );
1288+ TEST_PREDICATE (_Py_uop_sym_get_const (ctx , retrieved ) == val_42 ,
1289+ "slots getattr(0) didn't return val_42" );
1290+
1291+ JitOptRef missing = _Py_uop_sym_slots_getattr (ctx , slots_obj , 99 );
1292+ TEST_PREDICATE (_Py_uop_sym_is_not_null (missing ), "missing slot is not not-null" );
1293+ TEST_PREDICATE (!_Py_uop_sym_is_const (ctx , missing ), "missing slot is const" );
1294+
1295+ JitOptRef slot_val2 = _Py_uop_sym_new_const (ctx , val_43 );
1296+ _Py_uop_sym_slots_setattr (ctx , slots_obj , 0 , slot_val2 );
1297+ retrieved = _Py_uop_sym_slots_getattr (ctx , slots_obj , 0 );
1298+ TEST_PREDICATE (_Py_uop_sym_get_const (ctx , retrieved ) == val_43 ,
1299+ "slots getattr(0) didn't return val_43 after update" );
1300+
1301+ JitOptRef slots_obj2 = _Py_uop_sym_new_slots_object (ctx , 42 );
1302+ _Py_uop_sym_set_type_version (ctx , slots_obj2 , 43 );
1303+ TEST_PREDICATE (_Py_uop_sym_is_bottom (slots_obj2 ),
1304+ "slots object with wrong type version isn't bottom" );
1305+
11891306 _Py_uop_abstractcontext_fini (ctx );
11901307 Py_DECREF (val_42 );
11911308 Py_DECREF (val_43 );
0 commit comments