gh-144145: Revert PR#144122 for performance and potential bugs. (GH-144391)

Revert "gh-144145: Track nullness of properties in the Tier 2 JIT optimizer (GH-144122)"

This reverts commit 1dc12b2883.
This commit is contained in:
Hai Zhu 2026-02-02 22:09:54 +08:00 committed by GitHub
parent c3b61ef73d
commit ebbb2ca81f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 902 additions and 1589 deletions

View file

@ -2671,23 +2671,6 @@ dummy_func(
Py_XDECREF(old_value);
}
op(_STORE_ATTR_INSTANCE_VALUE_NULL, (offset/1, value, owner -- o)) {
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
STAT_INC(STORE_ATTR, hit);
assert(_PyObject_GetManagedDict(owner_o) == NULL);
PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset);
PyObject *old_value = *value_ptr;
DEOPT_IF(old_value != NULL);
FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value));
PyDictValues *values = _PyObject_InlineValues(owner_o);
Py_ssize_t index = value_ptr - values->values;
_PyDictValues_AddToInsertionOrder(values, index);
UNLOCK_OBJECT(owner_o);
INPUTS_DEAD();
o = owner;
}
macro(STORE_ATTR_INSTANCE_VALUE) =
unused/1 +
_GUARD_TYPE_VERSION_AND_LOCK +
@ -2750,20 +2733,6 @@ dummy_func(
Py_XDECREF(old_value);
}
op(_STORE_ATTR_SLOT_NULL, (index/1, value, owner -- o)) {
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
DEOPT_IF(!LOCK_OBJECT(owner_o));
char *addr = (char *)owner_o + index;
STAT_INC(STORE_ATTR, hit);
PyObject *old_value = *(PyObject **)addr;
DEOPT_IF(old_value != NULL);
FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value));
UNLOCK_OBJECT(owner_o);
INPUTS_DEAD();
o = owner;
}
macro(STORE_ATTR_SLOT) =
unused/1 +
_GUARD_TYPE_VERSION +

View file

@ -9782,147 +9782,6 @@
break;
}
case _STORE_ATTR_INSTANCE_VALUE_NULL_r01: {
CHECK_CURRENT_CACHED_VALUES(0);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef owner;
_PyStackRef value;
_PyStackRef o;
owner = stack_pointer[-1];
value = stack_pointer[-2];
uint16_t offset = (uint16_t)CURRENT_OPERAND0_16();
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
STAT_INC(STORE_ATTR, hit);
assert(_PyObject_GetManagedDict(owner_o) == NULL);
PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset);
PyObject *old_value = *value_ptr;
if (old_value != NULL) {
UOP_STAT_INC(uopcode, miss);
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_JUMP_TARGET();
}
FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value));
PyDictValues *values = _PyObject_InlineValues(owner_o);
Py_ssize_t index = value_ptr - values->values;
_PyDictValues_AddToInsertionOrder(values, index);
UNLOCK_OBJECT(owner_o);
o = owner;
_tos_cache0 = o;
SET_CURRENT_CACHED_VALUES(1);
stack_pointer += -2;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _STORE_ATTR_INSTANCE_VALUE_NULL_r11: {
CHECK_CURRENT_CACHED_VALUES(1);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef owner;
_PyStackRef value;
_PyStackRef o;
_PyStackRef _stack_item_0 = _tos_cache0;
owner = _stack_item_0;
value = stack_pointer[-1];
uint16_t offset = (uint16_t)CURRENT_OPERAND0_16();
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
STAT_INC(STORE_ATTR, hit);
assert(_PyObject_GetManagedDict(owner_o) == NULL);
PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset);
PyObject *old_value = *value_ptr;
if (old_value != NULL) {
UOP_STAT_INC(uopcode, miss);
_tos_cache0 = owner;
SET_CURRENT_CACHED_VALUES(1);
JUMP_TO_JUMP_TARGET();
}
FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value));
PyDictValues *values = _PyObject_InlineValues(owner_o);
Py_ssize_t index = value_ptr - values->values;
_PyDictValues_AddToInsertionOrder(values, index);
UNLOCK_OBJECT(owner_o);
o = owner;
_tos_cache0 = o;
SET_CURRENT_CACHED_VALUES(1);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _STORE_ATTR_INSTANCE_VALUE_NULL_r21: {
CHECK_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef owner;
_PyStackRef value;
_PyStackRef o;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
owner = _stack_item_1;
value = _stack_item_0;
uint16_t offset = (uint16_t)CURRENT_OPERAND0_16();
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
STAT_INC(STORE_ATTR, hit);
assert(_PyObject_GetManagedDict(owner_o) == NULL);
PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset);
PyObject *old_value = *value_ptr;
if (old_value != NULL) {
UOP_STAT_INC(uopcode, miss);
_tos_cache1 = owner;
_tos_cache0 = value;
SET_CURRENT_CACHED_VALUES(2);
JUMP_TO_JUMP_TARGET();
}
FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value));
PyDictValues *values = _PyObject_InlineValues(owner_o);
Py_ssize_t index = value_ptr - values->values;
_PyDictValues_AddToInsertionOrder(values, index);
UNLOCK_OBJECT(owner_o);
o = owner;
_tos_cache0 = o;
SET_CURRENT_CACHED_VALUES(1);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _STORE_ATTR_INSTANCE_VALUE_NULL_r32: {
CHECK_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef owner;
_PyStackRef value;
_PyStackRef o;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
_PyStackRef _stack_item_2 = _tos_cache2;
owner = _stack_item_2;
value = _stack_item_1;
uint16_t offset = (uint16_t)CURRENT_OPERAND0_16();
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
STAT_INC(STORE_ATTR, hit);
assert(_PyObject_GetManagedDict(owner_o) == NULL);
PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset);
PyObject *old_value = *value_ptr;
if (old_value != NULL) {
UOP_STAT_INC(uopcode, miss);
_tos_cache2 = owner;
_tos_cache1 = value;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(3);
JUMP_TO_JUMP_TARGET();
}
FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value));
PyDictValues *values = _PyObject_InlineValues(owner_o);
Py_ssize_t index = value_ptr - values->values;
_PyDictValues_AddToInsertionOrder(values, index);
UNLOCK_OBJECT(owner_o);
o = owner;
_tos_cache1 = o;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _STORE_ATTR_WITH_HINT_r21: {
CHECK_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
@ -10055,157 +9914,6 @@
break;
}
case _STORE_ATTR_SLOT_NULL_r01: {
CHECK_CURRENT_CACHED_VALUES(0);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef owner;
_PyStackRef value;
_PyStackRef o;
owner = stack_pointer[-1];
value = stack_pointer[-2];
uint16_t index = (uint16_t)CURRENT_OPERAND0_16();
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
if (!LOCK_OBJECT(owner_o)) {
UOP_STAT_INC(uopcode, miss);
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_JUMP_TARGET();
}
char *addr = (char *)owner_o + index;
STAT_INC(STORE_ATTR, hit);
PyObject *old_value = *(PyObject **)addr;
if (old_value != NULL) {
UOP_STAT_INC(uopcode, miss);
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_JUMP_TARGET();
}
FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value));
UNLOCK_OBJECT(owner_o);
o = owner;
_tos_cache0 = o;
SET_CURRENT_CACHED_VALUES(1);
stack_pointer += -2;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _STORE_ATTR_SLOT_NULL_r11: {
CHECK_CURRENT_CACHED_VALUES(1);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef owner;
_PyStackRef value;
_PyStackRef o;
_PyStackRef _stack_item_0 = _tos_cache0;
owner = _stack_item_0;
value = stack_pointer[-1];
uint16_t index = (uint16_t)CURRENT_OPERAND0_16();
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
if (!LOCK_OBJECT(owner_o)) {
UOP_STAT_INC(uopcode, miss);
_tos_cache0 = owner;
SET_CURRENT_CACHED_VALUES(1);
JUMP_TO_JUMP_TARGET();
}
char *addr = (char *)owner_o + index;
STAT_INC(STORE_ATTR, hit);
PyObject *old_value = *(PyObject **)addr;
if (old_value != NULL) {
UOP_STAT_INC(uopcode, miss);
_tos_cache0 = owner;
SET_CURRENT_CACHED_VALUES(1);
JUMP_TO_JUMP_TARGET();
}
FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value));
UNLOCK_OBJECT(owner_o);
o = owner;
_tos_cache0 = o;
SET_CURRENT_CACHED_VALUES(1);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _STORE_ATTR_SLOT_NULL_r21: {
CHECK_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef owner;
_PyStackRef value;
_PyStackRef o;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
owner = _stack_item_1;
value = _stack_item_0;
uint16_t index = (uint16_t)CURRENT_OPERAND0_16();
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
if (!LOCK_OBJECT(owner_o)) {
UOP_STAT_INC(uopcode, miss);
_tos_cache1 = owner;
_tos_cache0 = value;
SET_CURRENT_CACHED_VALUES(2);
JUMP_TO_JUMP_TARGET();
}
char *addr = (char *)owner_o + index;
STAT_INC(STORE_ATTR, hit);
PyObject *old_value = *(PyObject **)addr;
if (old_value != NULL) {
UOP_STAT_INC(uopcode, miss);
_tos_cache1 = owner;
_tos_cache0 = value;
SET_CURRENT_CACHED_VALUES(2);
JUMP_TO_JUMP_TARGET();
}
FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value));
UNLOCK_OBJECT(owner_o);
o = owner;
_tos_cache0 = o;
SET_CURRENT_CACHED_VALUES(1);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _STORE_ATTR_SLOT_NULL_r32: {
CHECK_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef owner;
_PyStackRef value;
_PyStackRef o;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
_PyStackRef _stack_item_2 = _tos_cache2;
owner = _stack_item_2;
value = _stack_item_1;
uint16_t index = (uint16_t)CURRENT_OPERAND0_16();
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
if (!LOCK_OBJECT(owner_o)) {
UOP_STAT_INC(uopcode, miss);
_tos_cache2 = owner;
_tos_cache1 = value;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(3);
JUMP_TO_JUMP_TARGET();
}
char *addr = (char *)owner_o + index;
STAT_INC(STORE_ATTR, hit);
PyObject *old_value = *(PyObject **)addr;
if (old_value != NULL) {
UOP_STAT_INC(uopcode, miss);
_tos_cache2 = owner;
_tos_cache1 = value;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(3);
JUMP_TO_JUMP_TARGET();
}
FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value));
UNLOCK_OBJECT(owner_o);
o = owner;
_tos_cache1 = o;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _COMPARE_OP_r21: {
CHECK_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());

View file

@ -269,9 +269,6 @@ add_op(JitOptContext *ctx, _PyUOpInstruction *this_instr,
#define sym_is_compact_int _Py_uop_sym_is_compact_int
#define sym_new_compact_int _Py_uop_sym_new_compact_int
#define sym_new_truthiness _Py_uop_sym_new_truthiness
#define sym_new_descr_object _Py_uop_sym_new_descr_object
#define sym_get_attr _Py_uop_sym_get_attr
#define sym_set_attr _Py_uop_sym_set_attr
#define sym_new_predicate _Py_uop_sym_new_predicate
#define sym_apply_predicate_narrowing _Py_uop_sym_apply_predicate_narrowing
@ -506,6 +503,7 @@ optimize_uops(
int oparg = this_instr->oparg;
opcode = this_instr->opcode;
if (!CURRENT_FRAME_IS_INIT_SHIM()) {
stack_pointer = ctx->frame->stack_pointer;
}
@ -526,15 +524,9 @@ optimize_uops(
if (ctx->out_buffer.next == out_ptr) {
*(ctx->out_buffer.next++) = *this_instr;
}
// Track escapes - but skip when from init shim frame, since self hasn't escaped yet
bool is_init_shim = CURRENT_FRAME_IS_INIT_SHIM();
if ((_PyUop_Flags[out_ptr->opcode] & HAS_ESCAPES_FLAG) && !is_init_shim)
{
ctx->last_escape_index = uop_buffer_length(&ctx->out_buffer) - 1;
}
assert(ctx->frame != NULL);
DUMP_UOP(ctx, "out", uop_buffer_length(&ctx->out_buffer) - 1, out_ptr, stack_pointer);
if (!is_init_shim && !ctx->done) {
if (!CURRENT_FRAME_IS_INIT_SHIM() && !ctx->done) {
DPRINTF(3, " stack_level %d\n", STACK_LEVEL());
ctx->frame->stack_pointer = stack_pointer;
assert(STACK_LEVEL() >= 0);

View file

@ -38,9 +38,6 @@ typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame;
#define sym_new_compact_int _Py_uop_sym_new_compact_int
#define sym_is_compact_int _Py_uop_sym_is_compact_int
#define sym_new_truthiness _Py_uop_sym_new_truthiness
#define sym_new_descr_object _Py_uop_sym_new_descr_object
#define sym_get_attr _Py_uop_sym_get_attr
#define sym_set_attr _Py_uop_sym_set_attr
#define sym_new_predicate _Py_uop_sym_new_predicate
#define sym_apply_predicate_narrowing _Py_uop_sym_apply_predicate_narrowing
@ -106,14 +103,6 @@ dummy_func(void) {
}
op(_STORE_ATTR_INSTANCE_VALUE, (offset/1, value, owner -- o)) {
JitOptRef old_value = sym_set_attr(ctx, owner, (uint16_t)offset, value);
if (sym_is_null(old_value)) {
ADD_OP(_STORE_ATTR_INSTANCE_VALUE_NULL, 0, offset);
}
o = owner;
}
op(_STORE_ATTR_INSTANCE_VALUE_NULL, (offset/1, value, owner -- o)) {
(void)value;
o = owner;
}
@ -136,14 +125,7 @@ dummy_func(void) {
}
op(_STORE_ATTR_SLOT, (index/1, value, owner -- o)) {
JitOptRef old_value = sym_set_attr(ctx, owner, (uint16_t)index, value);
if (sym_is_null(old_value)) {
ADD_OP(_STORE_ATTR_SLOT_NULL, 0, index);
}
o = owner;
}
op(_STORE_ATTR_SLOT_NULL, (index/1, value, owner -- o)) {
(void)index;
(void)value;
o = owner;
}
@ -767,7 +749,8 @@ dummy_func(void) {
}
op(_LOAD_ATTR_SLOT, (index/1, owner -- attr, o)) {
attr = sym_get_attr(ctx, owner, (uint16_t)index);
attr = sym_new_not_null(ctx);
(void)index;
o = owner;
}
@ -951,14 +934,10 @@ dummy_func(void) {
}
op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable, self_or_null, args[oparg] -- callable, self_or_null, args[oparg])) {
(void)type_version;
(void)args;
callable = sym_new_not_null(ctx);
PyTypeObject *tp = _PyType_LookupByVersion(type_version);
if (tp != NULL) {
self_or_null = sym_new_descr_object(ctx, type_version);
} else {
self_or_null = sym_new_not_null(ctx);
}
self_or_null = sym_new_not_null(ctx);
}
op(_CREATE_INIT_FRAME, (init, self, args[oparg] -- init_frame)) {

View file

@ -1936,7 +1936,8 @@
JitOptRef o;
owner = stack_pointer[-1];
uint16_t index = (uint16_t)this_instr->operand0;
attr = sym_get_attr(ctx, owner, (uint16_t)index);
attr = sym_new_not_null(ctx);
(void)index;
o = owner;
CHECK_STACK_BOUNDS(1);
stack_pointer[-1] = attr;
@ -2005,25 +2006,6 @@
}
case _STORE_ATTR_INSTANCE_VALUE: {
JitOptRef owner;
JitOptRef value;
JitOptRef o;
owner = stack_pointer[-1];
value = stack_pointer[-2];
uint16_t offset = (uint16_t)this_instr->operand0;
JitOptRef old_value = sym_set_attr(ctx, owner, (uint16_t)offset, value);
if (sym_is_null(old_value)) {
ADD_OP(_STORE_ATTR_INSTANCE_VALUE_NULL, 0, offset);
}
o = owner;
CHECK_STACK_BOUNDS(-1);
stack_pointer[-2] = o;
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
break;
}
case _STORE_ATTR_INSTANCE_VALUE_NULL: {
JitOptRef owner;
JitOptRef value;
JitOptRef o;
@ -2062,25 +2044,7 @@
owner = stack_pointer[-1];
value = stack_pointer[-2];
uint16_t index = (uint16_t)this_instr->operand0;
JitOptRef old_value = sym_set_attr(ctx, owner, (uint16_t)index, value);
if (sym_is_null(old_value)) {
ADD_OP(_STORE_ATTR_SLOT_NULL, 0, index);
}
o = owner;
CHECK_STACK_BOUNDS(-1);
stack_pointer[-2] = o;
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
break;
}
case _STORE_ATTR_SLOT_NULL: {
JitOptRef owner;
JitOptRef value;
JitOptRef o;
owner = stack_pointer[-1];
value = stack_pointer[-2];
uint16_t index = (uint16_t)this_instr->operand0;
(void)index;
(void)value;
o = owner;
CHECK_STACK_BOUNDS(-1);
@ -3228,15 +3192,11 @@
self_or_null = stack_pointer[-1 - oparg];
callable = stack_pointer[-2 - oparg];
uint32_t type_version = (uint32_t)this_instr->operand0;
(void)type_version;
(void)args;
callable = sym_new_not_null(ctx);
self_or_null = sym_new_not_null(ctx);
stack_pointer[-2 - oparg] = callable;
PyTypeObject *tp = _PyType_LookupByVersion(type_version);
if (tp != NULL) {
self_or_null = sym_new_descr_object(ctx, type_version);
} else {
self_or_null = sym_new_not_null(ctx);
}
stack_pointer[-1 - oparg] = self_or_null;
break;
}

View file

@ -116,15 +116,6 @@ _PyUOpSymPrint(JitOptRef ref)
case JIT_SYM_PREDICATE_TAG:
printf("<predicate at %p>", (void *)sym);
break;
case JIT_SYM_DESCR_TAG: {
PyTypeObject *descr_type = _PyType_LookupByVersion(sym->descr.type_version);
if (descr_type) {
printf("<%s descr[%d] v%u at %p>", descr_type->tp_name, sym->descr.num_descrs, sym->descr.type_version, (void *)sym);
} else {
printf("<descr[%d] v%u at %p>", sym->descr.num_descrs, sym->descr.type_version, (void *)sym);
}
break;
}
default:
printf("<tag=%d at %p>", sym->tag, (void *)sym);
break;
@ -332,11 +323,6 @@ _Py_uop_sym_set_type(JitOptContext *ctx, JitOptRef ref, PyTypeObject *typ)
sym_set_bottom(ctx, sym);
}
return;
case JIT_SYM_DESCR_TAG:
if (typ->tp_version_tag != sym->descr.type_version) {
sym_set_bottom(ctx, sym);
}
return;
}
}
@ -401,12 +387,6 @@ _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptRef ref, unsigned int ver
return false;
}
return true;
case JIT_SYM_DESCR_TAG:
if (version != sym->descr.type_version) {
sym_set_bottom(ctx, sym);
return false;
}
return true;
}
Py_UNREACHABLE();
}
@ -506,9 +486,6 @@ _Py_uop_sym_set_const(JitOptContext *ctx, JitOptRef ref, PyObject *const_val)
sym_set_bottom(ctx, sym);
}
return;
case JIT_SYM_DESCR_TAG:
sym_set_bottom(ctx, sym);
return;
}
}
@ -629,8 +606,7 @@ _Py_uop_sym_get_type(JitOptRef ref)
return &PyBool_Type;
case JIT_SYM_COMPACT_INT:
return &PyLong_Type;
case JIT_SYM_DESCR_TAG:
return _PyType_LookupByVersion(sym->descr.type_version);
}
Py_UNREACHABLE();
}
@ -659,8 +635,6 @@ _Py_uop_sym_get_type_version(JitOptRef ref)
return PyBool_Type.tp_version_tag;
case JIT_SYM_COMPACT_INT:
return PyLong_Type.tp_version_tag;
case JIT_SYM_DESCR_TAG:
return sym->descr.type_version;
}
Py_UNREACHABLE();
}
@ -696,7 +670,6 @@ _Py_uop_sym_truthiness(JitOptContext *ctx, JitOptRef ref)
case JIT_SYM_UNKNOWN_TAG:
case JIT_SYM_COMPACT_INT:
case JIT_SYM_PREDICATE_TAG:
case JIT_SYM_DESCR_TAG:
return -1;
case JIT_SYM_KNOWN_CLASS_TAG:
/* TODO :
@ -854,7 +827,6 @@ _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef ref)
case JIT_SYM_TUPLE_TAG:
case JIT_SYM_PREDICATE_TAG:
case JIT_SYM_TRUTHINESS_TAG:
case JIT_SYM_DESCR_TAG:
sym_set_bottom(ctx, sym);
return;
case JIT_SYM_BOTTOM_TAG:
@ -969,116 +941,6 @@ _Py_uop_sym_new_compact_int(JitOptContext *ctx)
return PyJitRef_Wrap(sym);
}
JitOptRef
_Py_uop_sym_new_descr_object(JitOptContext *ctx, unsigned int type_version)
{
JitOptSymbol *res = sym_new(ctx);
if (res == NULL) {
return out_of_space_ref(ctx);
}
res->tag = JIT_SYM_DESCR_TAG;
res->descr.num_descrs = 0;
res->descr.descrs = NULL;
res->descr.type_version = type_version;
res->descr.last_modified_index = uop_buffer_length(&ctx->out_buffer);
return PyJitRef_Wrap(res);
}
JitOptRef
_Py_uop_sym_get_attr(JitOptContext *ctx, JitOptRef ref, uint16_t slot_index)
{
JitOptSymbol *sym = PyJitRef_Unwrap(ref);
switch (sym->tag) {
case JIT_SYM_DESCR_TAG:
// Only return tracked slot values if:
// 1. Symbol has mappings allocated
// 2. No escape has occurred since last modification (state is fresh)
if (sym->descr.descrs != NULL &&
sym->descr.last_modified_index >= ctx->last_escape_index)
{
for (int i = 0; i < sym->descr.num_descrs; i++) {
if (sym->descr.descrs[i].slot_index == slot_index) {
return PyJitRef_Wrap(allocation_base(ctx) + sym->descr.descrs[i].symbol);
}
}
}
break;
default:
break;
}
return _Py_uop_sym_new_not_null(ctx);
}
static JitOptDescrMapping *
descr_arena_alloc(JitOptContext *ctx)
{
if (ctx->d_arena.descr_curr_number + MAX_SYMBOLIC_DESCR_SIZE > ctx->d_arena.descr_max_number) {
return NULL;
}
JitOptDescrMapping *descrs = &ctx->d_arena.arena[ctx->d_arena.descr_curr_number];
ctx->d_arena.descr_curr_number += MAX_SYMBOLIC_DESCR_SIZE;
return descrs;
}
JitOptRef
_Py_uop_sym_set_attr(JitOptContext *ctx, JitOptRef ref, uint16_t slot_index, JitOptRef value)
{
JitOptSymbol *sym = PyJitRef_Unwrap(ref);
int curr_index = uop_buffer_length(&ctx->out_buffer);
switch (sym->tag) {
case JIT_SYM_DESCR_TAG:
break;
default:
return _Py_uop_sym_new_not_null(ctx);
}
// Check escape
if (sym->descr.last_modified_index < ctx->last_escape_index) {
sym->descr.num_descrs = 0;
}
// Get old value before updating
JitOptRef old_value = PyJitRef_NULL;
if (sym->descr.descrs != NULL) {
for (int i = 0; i < sym->descr.num_descrs; i++) {
if (sym->descr.descrs[i].slot_index == slot_index) {
old_value = PyJitRef_Wrap(allocation_base(ctx) + sym->descr.descrs[i].symbol);
break;
}
}
}
// Update the last modified timestamp
sym->descr.last_modified_index = curr_index;
// Check if have arena space allocated
if (sym->descr.descrs == NULL) {
sym->descr.descrs = descr_arena_alloc(ctx);
if (sym->descr.descrs == NULL) {
return PyJitRef_IsNull(old_value) ? _Py_uop_sym_new_not_null(ctx) : old_value;
}
}
// Check if the slot already exists
for (int i = 0; i < sym->descr.num_descrs; i++) {
if (sym->descr.descrs[i].slot_index == slot_index) {
sym->descr.descrs[i].symbol = (uint16_t)(PyJitRef_Unwrap(value) - allocation_base(ctx));
assert(!PyJitRef_IsNull(old_value));
return old_value;
}
}
// Add new mapping if there's space
if (sym->descr.num_descrs < MAX_SYMBOLIC_DESCR_SIZE) {
int idx = sym->descr.num_descrs++;
sym->descr.descrs[idx].slot_index = slot_index;
sym->descr.descrs[idx].symbol = (uint16_t)(PyJitRef_Unwrap(value) - allocation_base(ctx));
}
return PyJitRef_IsNull(old_value) ? PyJitRef_Borrow(_Py_uop_sym_new_null(ctx)) : old_value;
}
// 0 on success, -1 on error.
_Py_UOpsAbstractFrame *
_Py_uop_frame_new(
@ -1168,10 +1030,6 @@ _Py_uop_abstractcontext_init(JitOptContext *ctx)
ctx->t_arena.ty_curr_number = 0;
ctx->t_arena.ty_max_number = TY_ARENA_SIZE;
// Setup the arena for descriptor mappings.
ctx->d_arena.descr_curr_number = 0;
ctx->d_arena.descr_max_number = DESCR_ARENA_SIZE;
// Frame setup
ctx->curr_frame_depth = 0;
@ -1182,7 +1040,6 @@ _Py_uop_abstractcontext_init(JitOptContext *ctx)
ctx->out_of_space = false;
ctx->contradiction = false;
ctx->builtins_watched = false;
ctx->last_escape_index = 0;
}
int
@ -1664,61 +1521,6 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
TEST_PREDICATE(_Py_uop_sym_matches_type(ref_int, &PyLong_Type), "43 is not an int");
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, ref_int) == val_43, "43 isn't 43");
JitOptRef descr_obj = _Py_uop_sym_new_descr_object(ctx, 42);
TEST_PREDICATE(!_Py_uop_sym_is_null(descr_obj), "descr object is NULL");
TEST_PREDICATE(_Py_uop_sym_is_not_null(descr_obj), "descr object is not not-null");
TEST_PREDICATE(_Py_uop_sym_get_type_version(descr_obj) == 42,
"descr object has wrong type version");
JitOptRef slot_val = _Py_uop_sym_new_const(ctx, val_42);
JitOptRef old_val = _Py_uop_sym_set_attr(ctx, descr_obj, 0, slot_val);
TEST_PREDICATE(_Py_uop_sym_is_null(old_val), "set_attr on new slot should return NULL");
JitOptRef retrieved = _Py_uop_sym_get_attr(ctx, descr_obj, 0);
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, retrieved) == val_42,
"descr getattr(0) didn't return val_42");
JitOptRef missing = _Py_uop_sym_get_attr(ctx, descr_obj, 99);
TEST_PREDICATE(_Py_uop_sym_is_not_null(missing), "missing slot is not not-null");
TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, missing), "missing slot is const");
JitOptRef slot_val2 = _Py_uop_sym_new_const(ctx, val_43);
old_val = _Py_uop_sym_set_attr(ctx, descr_obj, 0, slot_val2);
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, old_val) == val_42,
"set_attr should return old value (val_42)");
retrieved = _Py_uop_sym_get_attr(ctx, descr_obj, 0);
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, retrieved) == val_43,
"descr getattr(0) didn't return val_43 after update");
// Test multiple slots
JitOptRef slot_val3 = _Py_uop_sym_new_const(ctx, val_42);
_Py_uop_sym_set_attr(ctx, descr_obj, 1, slot_val3);
retrieved = _Py_uop_sym_get_attr(ctx, descr_obj, 1);
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, retrieved) == val_42,
"descr getattr(1) didn't return val_42");
retrieved = _Py_uop_sym_get_attr(ctx, descr_obj, 0);
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, retrieved) == val_43,
"descr getattr(0) changed unexpectedly");
// Test escape invalidation
JitOptRef descr_obj3 = _Py_uop_sym_new_descr_object(ctx, 100);
JitOptRef escape_val = _Py_uop_sym_new_const(ctx, val_42);
_Py_uop_sym_set_attr(ctx, descr_obj3, 0, escape_val);
retrieved = _Py_uop_sym_get_attr(ctx, descr_obj3, 0);
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, retrieved) == val_42,
"descr getattr before escape didn't return val_42");
// Simulate escape by setting last_escape_index higher
ctx->last_escape_index = INT_MAX;
retrieved = _Py_uop_sym_get_attr(ctx, descr_obj3, 0);
TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, retrieved),
"descr getattr after escape should not return const");
TEST_PREDICATE(_Py_uop_sym_is_not_null(retrieved),
"descr getattr after escape should return not-null");
ctx->last_escape_index = 0;
JitOptRef descr_obj2 = _Py_uop_sym_new_descr_object(ctx, 42);
_Py_uop_sym_set_type_version(ctx, descr_obj2, 43);
TEST_PREDICATE(_Py_uop_sym_is_bottom(descr_obj2),
"descr object with wrong type version isn't bottom");
_Py_uop_abstractcontext_fini(ctx);
Py_DECREF(val_42);
Py_DECREF(val_43);