GH-144179: Use recorded values to make optimizer more robust (GH-144437)

* Add three new symbol kinds
* Do not smuggle code object in _PUSH_FRAME operand
* Fix small bug in predicate analysis
This commit is contained in:
Mark Shannon 2026-02-05 08:58:41 +00:00 committed by GitHub
parent b6d8aa436b
commit b53fc7caa6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 2062 additions and 1507 deletions

View file

@ -1179,7 +1179,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
[FORMAT_SIMPLE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[FORMAT_WITH_SPEC] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG },
[FOR_ITER_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
[FOR_ITER_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
[FOR_ITER_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG },
[FOR_ITER_RANGE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG },
[FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG },
@ -1280,10 +1280,10 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
[RESERVED] = { true, INSTR_FMT_IX, 0 },
[RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
[RESUME_CHECK] = { true, INSTR_FMT_IX, HAS_DEOPT_FLAG },
[RETURN_GENERATOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
[RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
[RETURN_GENERATOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[SEND] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[SEND_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[SEND_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
[SETUP_ANNOTATIONS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[SET_ADD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[SET_FUNCTION_ATTRIBUTE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
@ -1320,7 +1320,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
[UNPACK_SEQUENCE_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
[UNPACK_SEQUENCE_TWO_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
[WITH_EXCEPT_START] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
[YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[ANNOTATIONS_PLACEHOLDER] = { true, -1, HAS_PURE_FLAG },
[JUMP] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[JUMP_IF_FALSE] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
@ -1354,7 +1354,7 @@ _PyOpcode_macro_expansion[256] = {
[BINARY_OP_MULTIPLY_FLOAT] = { .nuops = 5, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_MULTIPLY_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_MULTIPLY_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_MULTIPLY_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBSCR_DICT] = { .nuops = 4, .uops = { { _GUARD_NOS_DICT, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_DICT, OPARG_SIMPLE, 5 }, { _POP_TOP, OPARG_SIMPLE, 5 }, { _POP_TOP, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBSCR_GETITEM] = { .nuops = 5, .uops = { { _RECORD_TOS, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_CHECK_FUNC, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_INIT_CALL, OPARG_SIMPLE, 5 }, { _PUSH_FRAME, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBSCR_GETITEM] = { .nuops = 5, .uops = { { _RECORD_NOS, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_CHECK_FUNC, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_INIT_CALL, OPARG_SIMPLE, 5 }, { _PUSH_FRAME, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBSCR_LIST_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_LIST_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBSCR_LIST_SLICE] = { .nuops = 3, .uops = { { _GUARD_TOS_SLICE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_LIST_SLICE, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBSCR_STR_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_COMPACT_ASCII, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_STR_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_UNICODE, OPARG_SIMPLE, 5 } } },
@ -1424,7 +1424,7 @@ _PyOpcode_macro_expansion[256] = {
[FORMAT_SIMPLE] = { .nuops = 1, .uops = { { _FORMAT_SIMPLE, OPARG_SIMPLE, 0 } } },
[FORMAT_WITH_SPEC] = { .nuops = 1, .uops = { { _FORMAT_WITH_SPEC, OPARG_SIMPLE, 0 } } },
[FOR_ITER] = { .nuops = 1, .uops = { { _FOR_ITER, OPARG_REPLACED, 0 } } },
[FOR_ITER_GEN] = { .nuops = 4, .uops = { { _RECORD_NOS, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _FOR_ITER_GEN_FRAME, OPARG_SIMPLE, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } },
[FOR_ITER_GEN] = { .nuops = 4, .uops = { { _RECORD_NOS_GEN_FUNC, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _FOR_ITER_GEN_FRAME, OPARG_SIMPLE, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } },
[FOR_ITER_LIST] = { .nuops = 3, .uops = { { _ITER_CHECK_LIST, OPARG_SIMPLE, 1 }, { _ITER_JUMP_LIST, OPARG_REPLACED, 1 }, { _ITER_NEXT_LIST, OPARG_REPLACED, 1 } } },
[FOR_ITER_RANGE] = { .nuops = 3, .uops = { { _ITER_CHECK_RANGE, OPARG_SIMPLE, 1 }, { _ITER_JUMP_RANGE, OPARG_REPLACED, 1 }, { _ITER_NEXT_RANGE, OPARG_SIMPLE, 1 } } },
[FOR_ITER_TUPLE] = { .nuops = 3, .uops = { { _ITER_CHECK_TUPLE, OPARG_SIMPLE, 1 }, { _ITER_JUMP_TUPLE, OPARG_REPLACED, 1 }, { _ITER_NEXT_TUPLE, OPARG_SIMPLE, 1 } } },
@ -1494,9 +1494,9 @@ _PyOpcode_macro_expansion[256] = {
[PUSH_EXC_INFO] = { .nuops = 1, .uops = { { _PUSH_EXC_INFO, OPARG_SIMPLE, 0 } } },
[PUSH_NULL] = { .nuops = 1, .uops = { { _PUSH_NULL, OPARG_SIMPLE, 0 } } },
[RESUME_CHECK] = { .nuops = 1, .uops = { { _RESUME_CHECK, OPARG_SIMPLE, 0 } } },
[RETURN_GENERATOR] = { .nuops = 2, .uops = { { _RECORD_CALLER_CODE, OPARG_SIMPLE, 0 }, { _RETURN_GENERATOR, OPARG_SIMPLE, 0 } } },
[RETURN_VALUE] = { .nuops = 2, .uops = { { _RECORD_CALLER_CODE, OPARG_SIMPLE, 0 }, { _RETURN_VALUE, OPARG_SIMPLE, 0 } } },
[SEND_GEN] = { .nuops = 3, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _SEND_GEN_FRAME, OPARG_SIMPLE, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } },
[RETURN_GENERATOR] = { .nuops = 1, .uops = { { _RETURN_GENERATOR, OPARG_SIMPLE, 0 } } },
[RETURN_VALUE] = { .nuops = 1, .uops = { { _RETURN_VALUE, OPARG_SIMPLE, 0 } } },
[SEND_GEN] = { .nuops = 4, .uops = { { _RECORD_NOS_GEN_FUNC, OPARG_SIMPLE, 1 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _SEND_GEN_FRAME, OPARG_SIMPLE, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } },
[SETUP_ANNOTATIONS] = { .nuops = 1, .uops = { { _SETUP_ANNOTATIONS, OPARG_SIMPLE, 0 } } },
[SET_ADD] = { .nuops = 1, .uops = { { _SET_ADD, OPARG_SIMPLE, 0 } } },
[SET_FUNCTION_ATTRIBUTE] = { .nuops = 1, .uops = { { _SET_FUNCTION_ATTRIBUTE, OPARG_SIMPLE, 0 } } },
@ -1532,7 +1532,7 @@ _PyOpcode_macro_expansion[256] = {
[UNPACK_SEQUENCE_TUPLE] = { .nuops = 2, .uops = { { _GUARD_TOS_TUPLE, OPARG_SIMPLE, 0 }, { _UNPACK_SEQUENCE_TUPLE, OPARG_SIMPLE, 1 } } },
[UNPACK_SEQUENCE_TWO_TUPLE] = { .nuops = 2, .uops = { { _GUARD_TOS_TUPLE, OPARG_SIMPLE, 0 }, { _UNPACK_SEQUENCE_TWO_TUPLE, OPARG_SIMPLE, 1 } } },
[WITH_EXCEPT_START] = { .nuops = 1, .uops = { { _WITH_EXCEPT_START, OPARG_SIMPLE, 0 } } },
[YIELD_VALUE] = { .nuops = 2, .uops = { { _RECORD_CALLER_CODE, OPARG_SIMPLE, 0 }, { _YIELD_VALUE, OPARG_SIMPLE, 0 } } },
[YIELD_VALUE] = { .nuops = 1, .uops = { { _YIELD_VALUE, OPARG_SIMPLE, 0 } } },
};
#endif // NEED_OPCODE_METADATA

View file

@ -298,6 +298,11 @@ extern JitOptRef _Py_uop_sym_new_compact_int(JitOptContext *ctx);
extern void _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef sym);
extern JitOptRef _Py_uop_sym_new_predicate(JitOptContext *ctx, JitOptRef lhs_ref, JitOptRef rhs_ref, JitOptPredicateKind kind);
extern void _Py_uop_sym_apply_predicate_narrowing(JitOptContext *ctx, JitOptRef sym, bool branch_is_true);
extern void _Py_uop_sym_set_recorded_value(JitOptContext *ctx, JitOptRef sym, PyObject *value);
extern void _Py_uop_sym_set_recorded_type(JitOptContext *ctx, JitOptRef sym, PyTypeObject *type);
extern void _Py_uop_sym_set_recorded_gen_func(JitOptContext *ctx, JitOptRef ref, PyFunctionObject *value);
extern PyCodeObject *_Py_uop_sym_get_probable_func_code(JitOptRef sym);
extern PyObject *_Py_uop_sym_get_probable_value(JitOptRef sym);
extern void _Py_uop_abstractcontext_init(JitOptContext *ctx);
extern void _Py_uop_abstractcontext_fini(JitOptContext *ctx);
@ -308,6 +313,14 @@ extern _Py_UOpsAbstractFrame *_Py_uop_frame_new(
int curr_stackentries,
JitOptRef *args,
int arg_len);
extern _Py_UOpsAbstractFrame *_Py_uop_frame_new_from_symbol(
JitOptContext *ctx,
JitOptRef callable,
int curr_stackentries,
JitOptRef *args,
int arg_len);
extern int _Py_uop_frame_pop(JitOptContext *ctx, PyCodeObject *co, int curr_stackentries);
PyAPI_FUNC(PyObject *) _Py_uop_symbols_test(PyObject *self, PyObject *ignored);
@ -341,6 +354,7 @@ _PyJit_TryInitializeTracing(PyThreadState *tstate, _PyInterpreterFrame *frame,
int oparg, _PyExecutorObject *current_executor);
PyAPI_FUNC(void) _PyJit_FinalizeTracing(PyThreadState *tstate, int err);
void _PyPrintExecutor(_PyExecutorObject *executor, const _PyUOpInstruction *marker);
void _PyJit_TracerFree(_PyThreadStateImpl *_tstate);
void _PyJit_Tracer_InvalidateDependency(PyThreadState *old_tstate, void *obj);

View file

@ -41,6 +41,9 @@ typedef enum _JitSymType {
JIT_SYM_TRUTHINESS_TAG = 9,
JIT_SYM_COMPACT_INT = 10,
JIT_SYM_PREDICATE_TAG = 11,
JIT_SYM_RECORDED_VALUE_TAG = 12,
JIT_SYM_RECORDED_TYPE_TAG = 13,
JIT_SYM_RECORDED_GEN_FUNC_TAG = 14,
} JitSymType;
typedef struct _jit_opt_known_class {
@ -87,6 +90,24 @@ typedef struct {
uint16_t rhs;
} JitOptPredicate;
typedef struct _jit_opt_recorded_value {
uint8_t tag;
bool known_type;
PyObject *value;
} JitOptRecordedValue;
typedef struct _jit_opt_recorded_type {
uint8_t tag;
PyTypeObject *type;
} JitOptRecordedType;
/* Represents a generator, but we record the
* function as the generator is emphemeral */
typedef struct _jit_opt_recorded_gen_func {
uint8_t tag;
PyFunctionObject *func;
} JitOptRecordedGenFunc;
typedef struct {
uint8_t tag;
} JitOptCompactInt;
@ -100,6 +121,9 @@ typedef union _jit_opt_symbol {
JitOptTruthiness truthiness;
JitOptCompactInt compact;
JitOptPredicate predicate;
JitOptRecordedValue recorded_value;
JitOptRecordedType recorded_type;
JitOptRecordedGenFunc recorded_gen_func;
} JitOptSymbol;
// This mimics the _PyStackRef API

File diff suppressed because it is too large Load diff

View file

@ -370,6 +370,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = {
[_TIER2_RESUME_CHECK] = HAS_PERIODIC_FLAG,
[_COLD_EXIT] = HAS_SYNC_SP_FLAG,
[_COLD_DYNAMIC_EXIT] = HAS_SYNC_SP_FLAG,
[_GUARD_CODE] = HAS_EXIT_FLAG,
[_GUARD_IP__PUSH_FRAME] = HAS_EXIT_FLAG,
[_GUARD_IP_YIELD_VALUE] = HAS_EXIT_FLAG,
[_GUARD_IP_RETURN_VALUE] = HAS_EXIT_FLAG,
@ -377,10 +378,11 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = {
[_RECORD_TOS] = HAS_RECORDS_VALUE_FLAG,
[_RECORD_TOS_TYPE] = HAS_RECORDS_VALUE_FLAG,
[_RECORD_NOS] = HAS_RECORDS_VALUE_FLAG,
[_RECORD_NOS_GEN_FUNC] = HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG,
[_RECORD_4OS] = HAS_RECORDS_VALUE_FLAG,
[_RECORD_CALLABLE] = HAS_ARG_FLAG | HAS_RECORDS_VALUE_FLAG,
[_RECORD_BOUND_METHOD] = HAS_ARG_FLAG | HAS_RECORDS_VALUE_FLAG,
[_RECORD_CALLER_CODE] = HAS_RECORDS_VALUE_FLAG,
[_RECORD_CODE] = HAS_RECORDS_VALUE_FLAG,
};
const ReplicationRange _PyUop_Replication[MAX_UOP_ID+1] = {
@ -3402,6 +3404,15 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = {
{ -1, -1, -1 },
},
},
[_GUARD_CODE] = {
.best = { 0, 1, 2, 3 },
.entries = {
{ 0, 0, _GUARD_CODE_r00 },
{ 1, 1, _GUARD_CODE_r11 },
{ 2, 2, _GUARD_CODE_r22 },
{ 3, 3, _GUARD_CODE_r33 },
},
},
[_GUARD_IP__PUSH_FRAME] = {
.best = { 0, 1, 2, 3 },
.entries = {
@ -4210,6 +4221,10 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = {
[_TIER2_RESUME_CHECK_r33] = _TIER2_RESUME_CHECK,
[_COLD_EXIT_r00] = _COLD_EXIT,
[_COLD_DYNAMIC_EXIT_r00] = _COLD_DYNAMIC_EXIT,
[_GUARD_CODE_r00] = _GUARD_CODE,
[_GUARD_CODE_r11] = _GUARD_CODE,
[_GUARD_CODE_r22] = _GUARD_CODE,
[_GUARD_CODE_r33] = _GUARD_CODE,
[_GUARD_IP__PUSH_FRAME_r00] = _GUARD_IP__PUSH_FRAME,
[_GUARD_IP__PUSH_FRAME_r11] = _GUARD_IP__PUSH_FRAME,
[_GUARD_IP__PUSH_FRAME_r22] = _GUARD_IP__PUSH_FRAME,
@ -4640,6 +4655,11 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = {
[_GUARD_CALLABLE_TYPE_1_r13] = "_GUARD_CALLABLE_TYPE_1_r13",
[_GUARD_CALLABLE_TYPE_1_r23] = "_GUARD_CALLABLE_TYPE_1_r23",
[_GUARD_CALLABLE_TYPE_1_r33] = "_GUARD_CALLABLE_TYPE_1_r33",
[_GUARD_CODE] = "_GUARD_CODE",
[_GUARD_CODE_r00] = "_GUARD_CODE_r00",
[_GUARD_CODE_r11] = "_GUARD_CODE_r11",
[_GUARD_CODE_r22] = "_GUARD_CODE_r22",
[_GUARD_CODE_r33] = "_GUARD_CODE_r33",
[_GUARD_DORV_NO_DICT] = "_GUARD_DORV_NO_DICT",
[_GUARD_DORV_NO_DICT_r01] = "_GUARD_DORV_NO_DICT_r01",
[_GUARD_DORV_NO_DICT_r11] = "_GUARD_DORV_NO_DICT_r11",
@ -5179,8 +5199,9 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = {
[_RECORD_4OS] = "_RECORD_4OS",
[_RECORD_BOUND_METHOD] = "_RECORD_BOUND_METHOD",
[_RECORD_CALLABLE] = "_RECORD_CALLABLE",
[_RECORD_CALLER_CODE] = "_RECORD_CALLER_CODE",
[_RECORD_CODE] = "_RECORD_CODE",
[_RECORD_NOS] = "_RECORD_NOS",
[_RECORD_NOS_GEN_FUNC] = "_RECORD_NOS_GEN_FUNC",
[_RECORD_TOS] = "_RECORD_TOS",
[_RECORD_TOS_TYPE] = "_RECORD_TOS_TYPE",
[_REPLACE_WITH_TRUE] = "_REPLACE_WITH_TRUE",
@ -6049,6 +6070,8 @@ int _PyUop_num_popped(int opcode, int oparg)
return 0;
case _COLD_DYNAMIC_EXIT:
return 0;
case _GUARD_CODE:
return 0;
case _GUARD_IP__PUSH_FRAME:
return 0;
case _GUARD_IP_YIELD_VALUE:
@ -6063,13 +6086,15 @@ int _PyUop_num_popped(int opcode, int oparg)
return 0;
case _RECORD_NOS:
return 0;
case _RECORD_NOS_GEN_FUNC:
return 0;
case _RECORD_4OS:
return 0;
case _RECORD_CALLABLE:
return 0;
case _RECORD_BOUND_METHOD:
return 0;
case _RECORD_CALLER_CODE:
case _RECORD_CODE:
return 0;
default:
return -1;

View file

@ -978,50 +978,6 @@ def return_tenth():
# Constant narrowing allows constant folding for second comparison
self.assertLessEqual(count_ops(ex, "_COMPARE_OP_FLOAT"), 1)
def test_compare_str_eq_narrows_to_constant(self):
def f(n):
def return_hello():
return "hello"
hits = 0
v = return_hello()
for _ in range(n):
if v == "hello":
if v == "hello":
hits += 1
return hits
res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
self.assertEqual(res, TIER2_THRESHOLD)
self.assertIsNotNone(ex)
uops = get_opnames(ex)
# Constant narrowing allows constant folding for second comparison
self.assertLessEqual(count_ops(ex, "_COMPARE_OP_STR"), 1)
def test_compare_str_ne_narrows_to_constant(self):
def f(n):
def return_hello():
return "hello"
hits = 0
v = return_hello()
for _ in range(n):
if v != "hello":
hits += 1000
else:
if v == "hello":
hits += 1
return hits
res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
self.assertEqual(res, TIER2_THRESHOLD)
self.assertIsNotNone(ex)
uops = get_opnames(ex)
# Constant narrowing allows constant folding for second comparison
self.assertLessEqual(count_ops(ex, "_COMPARE_OP_STR"), 1)
def test_combine_stack_space_checks_sequential(self):
def dummy12(x):
return x - 1

View file

@ -749,11 +749,11 @@
JUMP_TO_PREDICTED(BINARY_OP);
}
getitem = PyStackRef_FromPyObjectNew(getitem_o);
STAT_INC(BINARY_OP, hit);
}
// _BINARY_OP_SUBSCR_INIT_CALL
{
sub = stack_pointer[-1];
STAT_INC(BINARY_OP, hit);
_PyInterpreterFrame* pushed_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame);
pushed_frame->localsplus[0] = container;
pushed_frame->localsplus[1] = sub;
@ -10449,33 +10449,30 @@
next_instr += 1;
INSTRUCTION_STATS(RETURN_GENERATOR);
_PyStackRef res;
// _RETURN_GENERATOR
{
assert(PyStackRef_FunctionCheck(frame->f_funcobj));
PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (gen == NULL) {
JUMP_TO_LABEL(error);
}
assert(STACK_LEVEL() <= 2);
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyInterpreterFrame *gen_frame = &gen->gi_iframe;
frame->instr_ptr++;
_PyFrame_Copy(frame, gen_frame);
assert(frame->frame_obj == NULL);
gen->gi_frame_state = FRAME_CREATED;
gen_frame->owner = FRAME_OWNED_BY_GENERATOR;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *prev = frame->previous;
_PyThreadState_PopFrame(tstate, frame);
frame = tstate->current_frame = prev;
LOAD_IP(frame->return_offset);
stack_pointer = _PyFrame_GetStackPointer(frame);
res = PyStackRef_FromPyObjectStealMortal((PyObject *)gen);
LLTRACE_RESUME_FRAME();
assert(PyStackRef_FunctionCheck(frame->f_funcobj));
PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (gen == NULL) {
JUMP_TO_LABEL(error);
}
assert(STACK_LEVEL() <= 2);
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyInterpreterFrame *gen_frame = &gen->gi_iframe;
frame->instr_ptr++;
_PyFrame_Copy(frame, gen_frame);
assert(frame->frame_obj == NULL);
gen->gi_frame_state = FRAME_CREATED;
gen_frame->owner = FRAME_OWNED_BY_GENERATOR;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *prev = frame->previous;
_PyThreadState_PopFrame(tstate, frame);
frame = tstate->current_frame = prev;
LOAD_IP(frame->return_offset);
stack_pointer = _PyFrame_GetStackPointer(frame);
res = PyStackRef_FromPyObjectStealMortal((PyObject *)gen);
LLTRACE_RESUME_FRAME();
stack_pointer[0] = res;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
@ -10492,24 +10489,21 @@
INSTRUCTION_STATS(RETURN_VALUE);
_PyStackRef retval;
_PyStackRef res;
// _RETURN_VALUE
{
retval = stack_pointer[-1];
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
_PyStackRef temp = PyStackRef_MakeHeapSafe(retval);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
assert(STACK_LEVEL() == 0);
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *dying = frame;
frame = tstate->current_frame = dying->previous;
_PyEval_FrameClearAndPop(tstate, dying);
stack_pointer = _PyFrame_GetStackPointer(frame);
LOAD_IP(frame->return_offset);
res = temp;
LLTRACE_RESUME_FRAME();
}
retval = stack_pointer[-1];
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
_PyStackRef temp = PyStackRef_MakeHeapSafe(retval);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
assert(STACK_LEVEL() == 0);
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *dying = frame;
frame = tstate->current_frame = dying->previous;
_PyEval_FrameClearAndPop(tstate, dying);
stack_pointer = _PyFrame_GetStackPointer(frame);
LOAD_IP(frame->return_offset);
res = temp;
LLTRACE_RESUME_FRAME();
stack_pointer[0] = res;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
@ -12326,40 +12320,37 @@
INSTRUCTION_STATS(YIELD_VALUE);
_PyStackRef retval;
_PyStackRef value;
// _YIELD_VALUE
{
retval = stack_pointer[-1];
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
frame->instr_ptr++;
PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame);
assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1);
assert(oparg == 0 || oparg == 1);
_PyStackRef temp = retval;
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
tstate->exc_info = gen->gi_exc_state.previous_item;
gen->gi_exc_state.previous_item = NULL;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *gen_frame = frame;
frame = tstate->current_frame = frame->previous;
gen_frame->previous = NULL;
((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD;
FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_SUSPENDED + oparg);
assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER);
#if TIER_ONE
assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE ||
retval = stack_pointer[-1];
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
frame->instr_ptr++;
PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame);
assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1);
assert(oparg == 0 || oparg == 1);
_PyStackRef temp = retval;
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
tstate->exc_info = gen->gi_exc_state.previous_item;
gen->gi_exc_state.previous_item = NULL;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *gen_frame = frame;
frame = tstate->current_frame = frame->previous;
gen_frame->previous = NULL;
((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD;
FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_SUSPENDED + oparg);
assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER);
#if TIER_ONE
assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE ||
frame->instr_ptr->op.code == INSTRUMENTED_INSTRUCTION ||
_PyOpcode_Deopt[frame->instr_ptr->op.code] == SEND ||
_PyOpcode_Deopt[frame->instr_ptr->op.code] == FOR_ITER ||
_PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT ||
_PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR);
#endif
stack_pointer = _PyFrame_GetStackPointer(frame);
LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND);
value = PyStackRef_MakeHeapSafe(temp);
LLTRACE_RESUME_FRAME();
}
#endif
stack_pointer = _PyFrame_GetStackPointer(frame);
LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND);
value = PyStackRef_MakeHeapSafe(temp);
LLTRACE_RESUME_FRAME();
stack_pointer[0] = value;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);

View file

@ -1095,10 +1095,10 @@ dummy_func(
assert(code->co_argcount == 2);
DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize));
getitem = PyStackRef_FromPyObjectNew(getitem_o);
STAT_INC(BINARY_OP, hit);
}
op(_BINARY_OP_SUBSCR_INIT_CALL, (container, sub, getitem -- new_frame)) {
STAT_INC(BINARY_OP, hit);
_PyInterpreterFrame* pushed_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame);
pushed_frame->localsplus[0] = container;
pushed_frame->localsplus[1] = sub;
@ -1108,7 +1108,7 @@ dummy_func(
}
macro(BINARY_OP_SUBSCR_GETITEM) =
_RECORD_TOS +
_RECORD_NOS +
unused/5 + // Skip over the counter and cache
_CHECK_PEP_523 +
_BINARY_OP_SUBSCR_CHECK_FUNC +
@ -1269,7 +1269,7 @@ dummy_func(
// The stack effect here is a bit misleading.
// retval is popped from the stack, but res
// is pushed to a different frame, the callers' frame.
op(_RETURN_VALUE, (retval -- res)) {
inst(RETURN_VALUE, (retval -- res)) {
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
_PyStackRef temp = PyStackRef_MakeHeapSafe(retval);
DEAD(retval);
@ -1293,13 +1293,9 @@ dummy_func(
ERROR_IF(err);
}
macro(RETURN_VALUE) =
_RECORD_CALLER_CODE +
_RETURN_VALUE;
macro(INSTRUMENTED_RETURN_VALUE) =
_RETURN_VALUE_EVENT +
_RETURN_VALUE;
RETURN_VALUE;
inst(GET_AITER, (obj -- iter)) {
unaryfunc getter = NULL;
@ -1436,11 +1432,12 @@ dummy_func(
macro(SEND_GEN) =
unused/1 +
_RECORD_NOS_GEN_FUNC +
_CHECK_PEP_523 +
_SEND_GEN_FRAME +
_PUSH_FRAME;
op(_YIELD_VALUE, (retval -- value)) {
inst(YIELD_VALUE, (retval -- value)) {
// NOTE: It's important that YIELD_VALUE never raises an exception!
// The compiler treats any exception raised here as a failed close()
// or throw() call.
@ -1476,10 +1473,6 @@ dummy_func(
LLTRACE_RESUME_FRAME();
}
macro(YIELD_VALUE) =
_RECORD_CALLER_CODE +
_YIELD_VALUE;
tier1 op(_YIELD_VALUE_EVENT, (val -- val)) {
int err = _Py_call_instrumentation_arg(
tstate, PY_MONITORING_EVENT_PY_YIELD,
@ -1495,7 +1488,7 @@ dummy_func(
macro(INSTRUMENTED_YIELD_VALUE) =
_YIELD_VALUE_EVENT +
_YIELD_VALUE;
YIELD_VALUE;
inst(POP_EXCEPT, (exc_value -- )) {
_PyErr_StackItem *exc_info = tstate->exc_info;
@ -3523,7 +3516,7 @@ dummy_func(
}
macro(FOR_ITER_GEN) =
_RECORD_NOS +
_RECORD_NOS_GEN_FUNC +
unused/1 +
_CHECK_PEP_523 +
_FOR_ITER_GEN_FRAME +
@ -5074,7 +5067,7 @@ dummy_func(
*ptr = attr;
}
op(_RETURN_GENERATOR, (-- res)) {
inst(RETURN_GENERATOR, (-- res)) {
assert(PyStackRef_FunctionCheck(frame->f_funcobj));
PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
@ -5097,10 +5090,6 @@ dummy_func(
LLTRACE_RESUME_FRAME();
}
macro(RETURN_GENERATOR) =
_RECORD_CALLER_CODE +
_RETURN_GENERATOR;
inst(BUILD_SLICE, (args[oparg] -- slice)) {
PyObject *start_o = PyStackRef_AsPyObjectBorrow(args[0]);
PyObject *stop_o = PyStackRef_AsPyObjectBorrow(args[1]);
@ -5646,6 +5635,12 @@ dummy_func(
Py_UNREACHABLE();
}
tier2 op(_GUARD_CODE, (version/2 -- )) {
PyObject *code = PyStackRef_AsPyObjectBorrow(frame->f_executable);
EXIT_IF(code == Py_None);
EXIT_IF(((PyCodeObject *)code)->co_version != version);
}
tier2 op(_GUARD_IP__PUSH_FRAME, (ip/4 --)) {
_Py_CODEUNIT *target = frame->instr_ptr;
if (target != (_Py_CODEUNIT *)ip) {
@ -5694,6 +5689,14 @@ dummy_func(
RECORD_VALUE(PyStackRef_AsPyObjectBorrow(nos));
}
tier2 op(_RECORD_NOS_GEN_FUNC, (nos, tos -- nos, tos)) {
PyObject *obj = PyStackRef_AsPyObjectBorrow(nos);
if (PyGen_Check(obj)) {
PyObject *func = (PyObject *)_PyFrame_GetFunction(&((PyGenObject *)obj)->gi_iframe);
RECORD_VALUE(func);
}
}
tier2 op(_RECORD_4OS, (value, _3os, nos, tos -- value, _3os, nos, tos)) {
RECORD_VALUE(PyStackRef_AsPyObjectBorrow(value));
}
@ -5710,12 +5713,9 @@ dummy_func(
}
}
tier2 op(_RECORD_CALLER_CODE, ( -- )) {
_PyInterpreterFrame *caller_frame = frame->previous;
if (caller_frame->owner < FRAME_OWNED_BY_INTERPRETER) {
PyCodeObject *code = _PyFrame_GetCode(frame->previous);
RECORD_VALUE(code);
}
/* Inserted by the JIT tracer. Never executed. */
tier2 op(_RECORD_CODE, ( -- )) {
RECORD_VALUE(NULL);
}
label(pop_2_error) {

View file

@ -6184,7 +6184,6 @@
JUMP_TO_JUMP_TARGET();
}
getitem = PyStackRef_FromPyObjectNew(getitem_o);
STAT_INC(BINARY_OP, hit);
_tos_cache2 = getitem;
_tos_cache1 = _stack_item_1;
_tos_cache0 = container;
@ -6203,6 +6202,7 @@
getitem = stack_pointer[-1];
sub = stack_pointer[-2];
container = stack_pointer[-3];
STAT_INC(BINARY_OP, hit);
_PyInterpreterFrame* pushed_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame);
pushed_frame->localsplus[0] = container;
pushed_frame->localsplus[1] = sub;
@ -6227,6 +6227,7 @@
getitem = _stack_item_0;
sub = stack_pointer[-1];
container = stack_pointer[-2];
STAT_INC(BINARY_OP, hit);
_PyInterpreterFrame* pushed_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame);
pushed_frame->localsplus[0] = container;
pushed_frame->localsplus[1] = sub;
@ -6252,6 +6253,7 @@
getitem = _stack_item_1;
sub = _stack_item_0;
container = stack_pointer[-1];
STAT_INC(BINARY_OP, hit);
_PyInterpreterFrame* pushed_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame);
pushed_frame->localsplus[0] = container;
pushed_frame->localsplus[1] = sub;
@ -6278,6 +6280,7 @@
getitem = _stack_item_2;
sub = _stack_item_1;
container = _stack_item_0;
STAT_INC(BINARY_OP, hit);
_PyInterpreterFrame* pushed_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame);
pushed_frame->localsplus[0] = container;
pushed_frame->localsplus[1] = sub;
@ -20142,6 +20145,110 @@
GOTO_TIER_ONE(target);
}
case _GUARD_CODE_r00: {
CHECK_CURRENT_CACHED_VALUES(0);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
uint32_t version = (uint32_t)CURRENT_OPERAND0_32();
PyObject *code = PyStackRef_AsPyObjectBorrow(frame->f_executable);
if (code == Py_None) {
UOP_STAT_INC(uopcode, miss);
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_JUMP_TARGET();
}
if (((PyCodeObject *)code)->co_version != version) {
UOP_STAT_INC(uopcode, miss);
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_JUMP_TARGET();
}
SET_CURRENT_CACHED_VALUES(0);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_CODE_r11: {
CHECK_CURRENT_CACHED_VALUES(1);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef _stack_item_0 = _tos_cache0;
uint32_t version = (uint32_t)CURRENT_OPERAND0_32();
PyObject *code = PyStackRef_AsPyObjectBorrow(frame->f_executable);
if (code == Py_None) {
UOP_STAT_INC(uopcode, miss);
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(1);
JUMP_TO_JUMP_TARGET();
}
if (((PyCodeObject *)code)->co_version != version) {
UOP_STAT_INC(uopcode, miss);
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(1);
JUMP_TO_JUMP_TARGET();
}
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(1);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_CODE_r22: {
CHECK_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
uint32_t version = (uint32_t)CURRENT_OPERAND0_32();
PyObject *code = PyStackRef_AsPyObjectBorrow(frame->f_executable);
if (code == Py_None) {
UOP_STAT_INC(uopcode, miss);
_tos_cache1 = _stack_item_1;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(2);
JUMP_TO_JUMP_TARGET();
}
if (((PyCodeObject *)code)->co_version != version) {
UOP_STAT_INC(uopcode, miss);
_tos_cache1 = _stack_item_1;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(2);
JUMP_TO_JUMP_TARGET();
}
_tos_cache1 = _stack_item_1;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_CODE_r33: {
CHECK_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
_PyStackRef _stack_item_2 = _tos_cache2;
uint32_t version = (uint32_t)CURRENT_OPERAND0_32();
PyObject *code = PyStackRef_AsPyObjectBorrow(frame->f_executable);
if (code == Py_None) {
UOP_STAT_INC(uopcode, miss);
_tos_cache2 = _stack_item_2;
_tos_cache1 = _stack_item_1;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(3);
JUMP_TO_JUMP_TARGET();
}
if (((PyCodeObject *)code)->co_version != version) {
UOP_STAT_INC(uopcode, miss);
_tos_cache2 = _stack_item_2;
_tos_cache1 = _stack_item_1;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(3);
JUMP_TO_JUMP_TARGET();
}
_tos_cache2 = _stack_item_2;
_tos_cache1 = _stack_item_1;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _GUARD_IP__PUSH_FRAME_r00: {
CHECK_CURRENT_CACHED_VALUES(0);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());

View file

@ -749,11 +749,11 @@
JUMP_TO_PREDICTED(BINARY_OP);
}
getitem = PyStackRef_FromPyObjectNew(getitem_o);
STAT_INC(BINARY_OP, hit);
}
// _BINARY_OP_SUBSCR_INIT_CALL
{
sub = stack_pointer[-1];
STAT_INC(BINARY_OP, hit);
_PyInterpreterFrame* pushed_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame);
pushed_frame->localsplus[0] = container;
pushed_frame->localsplus[1] = sub;
@ -10446,33 +10446,30 @@
next_instr += 1;
INSTRUCTION_STATS(RETURN_GENERATOR);
_PyStackRef res;
// _RETURN_GENERATOR
{
assert(PyStackRef_FunctionCheck(frame->f_funcobj));
PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (gen == NULL) {
JUMP_TO_LABEL(error);
}
assert(STACK_LEVEL() <= 2);
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyInterpreterFrame *gen_frame = &gen->gi_iframe;
frame->instr_ptr++;
_PyFrame_Copy(frame, gen_frame);
assert(frame->frame_obj == NULL);
gen->gi_frame_state = FRAME_CREATED;
gen_frame->owner = FRAME_OWNED_BY_GENERATOR;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *prev = frame->previous;
_PyThreadState_PopFrame(tstate, frame);
frame = tstate->current_frame = prev;
LOAD_IP(frame->return_offset);
stack_pointer = _PyFrame_GetStackPointer(frame);
res = PyStackRef_FromPyObjectStealMortal((PyObject *)gen);
LLTRACE_RESUME_FRAME();
assert(PyStackRef_FunctionCheck(frame->f_funcobj));
PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (gen == NULL) {
JUMP_TO_LABEL(error);
}
assert(STACK_LEVEL() <= 2);
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyInterpreterFrame *gen_frame = &gen->gi_iframe;
frame->instr_ptr++;
_PyFrame_Copy(frame, gen_frame);
assert(frame->frame_obj == NULL);
gen->gi_frame_state = FRAME_CREATED;
gen_frame->owner = FRAME_OWNED_BY_GENERATOR;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *prev = frame->previous;
_PyThreadState_PopFrame(tstate, frame);
frame = tstate->current_frame = prev;
LOAD_IP(frame->return_offset);
stack_pointer = _PyFrame_GetStackPointer(frame);
res = PyStackRef_FromPyObjectStealMortal((PyObject *)gen);
LLTRACE_RESUME_FRAME();
stack_pointer[0] = res;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
@ -10489,24 +10486,21 @@
INSTRUCTION_STATS(RETURN_VALUE);
_PyStackRef retval;
_PyStackRef res;
// _RETURN_VALUE
{
retval = stack_pointer[-1];
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
_PyStackRef temp = PyStackRef_MakeHeapSafe(retval);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
assert(STACK_LEVEL() == 0);
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *dying = frame;
frame = tstate->current_frame = dying->previous;
_PyEval_FrameClearAndPop(tstate, dying);
stack_pointer = _PyFrame_GetStackPointer(frame);
LOAD_IP(frame->return_offset);
res = temp;
LLTRACE_RESUME_FRAME();
}
retval = stack_pointer[-1];
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
_PyStackRef temp = PyStackRef_MakeHeapSafe(retval);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
assert(STACK_LEVEL() == 0);
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *dying = frame;
frame = tstate->current_frame = dying->previous;
_PyEval_FrameClearAndPop(tstate, dying);
stack_pointer = _PyFrame_GetStackPointer(frame);
LOAD_IP(frame->return_offset);
res = temp;
LLTRACE_RESUME_FRAME();
stack_pointer[0] = res;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
@ -12323,40 +12317,37 @@
INSTRUCTION_STATS(YIELD_VALUE);
_PyStackRef retval;
_PyStackRef value;
// _YIELD_VALUE
{
retval = stack_pointer[-1];
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
frame->instr_ptr++;
PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame);
assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1);
assert(oparg == 0 || oparg == 1);
_PyStackRef temp = retval;
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
tstate->exc_info = gen->gi_exc_state.previous_item;
gen->gi_exc_state.previous_item = NULL;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *gen_frame = frame;
frame = tstate->current_frame = frame->previous;
gen_frame->previous = NULL;
((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD;
FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_SUSPENDED + oparg);
assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER);
#if TIER_ONE
assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE ||
retval = stack_pointer[-1];
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
frame->instr_ptr++;
PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame);
assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1);
assert(oparg == 0 || oparg == 1);
_PyStackRef temp = retval;
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
tstate->exc_info = gen->gi_exc_state.previous_item;
gen->gi_exc_state.previous_item = NULL;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *gen_frame = frame;
frame = tstate->current_frame = frame->previous;
gen_frame->previous = NULL;
((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD;
FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_SUSPENDED + oparg);
assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER);
#if TIER_ONE
assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE ||
frame->instr_ptr->op.code == INSTRUMENTED_INSTRUCTION ||
_PyOpcode_Deopt[frame->instr_ptr->op.code] == SEND ||
_PyOpcode_Deopt[frame->instr_ptr->op.code] == FOR_ITER ||
_PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT ||
_PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR);
#endif
stack_pointer = _PyFrame_GetStackPointer(frame);
LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND);
value = PyStackRef_MakeHeapSafe(temp);
LLTRACE_RESUME_FRAME();
}
#endif
stack_pointer = _PyFrame_GetStackPointer(frame);
LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND);
value = PyStackRef_MakeHeapSafe(temp);
LLTRACE_RESUME_FRAME();
stack_pointer[0] = value;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);

View file

@ -928,22 +928,8 @@ _PyJit_translate_single_bytecode_to_trace(
}
if (uop == _PUSH_FRAME || uop == _RETURN_VALUE || uop == _RETURN_GENERATOR || uop == _YIELD_VALUE) {
PyCodeObject *new_code = (PyCodeObject *)PyStackRef_AsPyObjectBorrow(frame->f_executable);
PyFunctionObject *new_func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj);
operand = 0;
if (frame->owner < FRAME_OWNED_BY_INTERPRETER) {
// Don't add nested code objects to the dependency.
// It causes endless re-traces.
if (new_func != NULL && !Py_IsNone((PyObject*)new_func) && !(new_code->co_flags & CO_NESTED)) {
operand = (uintptr_t)new_func;
DPRINTF(2, "Adding %p func to op\n", (void *)operand);
_Py_BloomFilter_Add(dependencies, new_func);
}
else if (new_code != NULL && !Py_IsNone((PyObject*)new_code)) {
operand = (uintptr_t)new_code | 1;
DPRINTF(2, "Adding %p code to op\n", (void *)operand);
_Py_BloomFilter_Add(dependencies, new_code);
}
if (new_code != NULL && !Py_IsNone((PyObject*)new_code)) {
_Py_BloomFilter_Add(dependencies, new_code);
}
ADD_TO_TRACE(uop, oparg, operand, target);
uop_buffer_last(trace)->operand1 = PyStackRef_IsNone(frame->f_executable) ? 2 : ((int)(frame->stackpointer - _PyFrame_Stackbase(frame)));
@ -974,7 +960,13 @@ _PyJit_translate_single_bytecode_to_trace(
DPRINTF(1, "Unknown uop needing guard ip %s\n", _PyOpcode_uop_name[uop_buffer_last(trace)->opcode]);
Py_UNREACHABLE();
}
PyObject *code = PyStackRef_AsPyObjectBorrow(frame->f_executable);
Py_INCREF(code);
ADD_TO_TRACE(_RECORD_CODE, 0, (uintptr_t)code, 0);
ADD_TO_TRACE(guard_ip, 0, (uintptr_t)next_instr, 0);
if (PyCode_Check(code)) {
ADD_TO_TRACE(_GUARD_CODE, 0, ((PyCodeObject *)code)->co_version, 0);
}
}
// Loop back to the start
int is_first_instr = tracer->initial_state.close_loop_instr == next_instr ||
@ -1224,7 +1216,8 @@ prepare_for_execution(_PyUOpInstruction *buffer, int length)
base_opcode == _GUARD_IP__PUSH_FRAME ||
base_opcode == _GUARD_IP_RETURN_VALUE ||
base_opcode == _GUARD_IP_YIELD_VALUE ||
base_opcode == _GUARD_IP_RETURN_GENERATOR
base_opcode == _GUARD_IP_RETURN_GENERATOR ||
base_opcode == _GUARD_CODE
) {
base_exit_op = _DYNAMIC_EXIT;
}

View file

@ -226,6 +226,7 @@ add_op(JitOptContext *ctx, _PyUOpInstruction *this_instr,
uint16_t opcode, uint16_t oparg, uintptr_t operand0)
{
_PyUOpInstruction *out = ctx->out_buffer.next;
assert(out < ctx->out_buffer.end);
out->opcode = (opcode);
out->format = this_instr->format;
out->oparg = (oparg);
@ -261,6 +262,7 @@ add_op(JitOptContext *ctx, _PyUOpInstruction *this_instr,
#define sym_is_bottom _Py_uop_sym_is_bottom
#define sym_truthiness _Py_uop_sym_truthiness
#define frame_new _Py_uop_frame_new
#define frame_new_from_symbol _Py_uop_frame_new_from_symbol
#define frame_pop _Py_uop_frame_pop
#define sym_new_tuple _Py_uop_sym_new_tuple
#define sym_tuple_getitem _Py_uop_sym_tuple_getitem
@ -271,6 +273,11 @@ add_op(JitOptContext *ctx, _PyUOpInstruction *this_instr,
#define sym_new_truthiness _Py_uop_sym_new_truthiness
#define sym_new_predicate _Py_uop_sym_new_predicate
#define sym_apply_predicate_narrowing _Py_uop_sym_apply_predicate_narrowing
#define sym_set_recorded_type(SYM, TYPE) _Py_uop_sym_set_recorded_type(ctx, SYM, TYPE)
#define sym_set_recorded_value(SYM, VAL) _Py_uop_sym_set_recorded_value(ctx, SYM, VAL)
#define sym_set_recorded_gen_func(SYM, VAL) _Py_uop_sym_set_recorded_gen_func(ctx, SYM, VAL)
#define sym_get_probable_func_code _Py_uop_sym_get_probable_func_code
#define sym_get_probable_value _Py_uop_sym_get_probable_value
/* Comparison oparg masks */
#define COMPARE_LT_MASK 2
@ -355,30 +362,6 @@ lookup_attr(JitOptContext *ctx, _PyBloomFilter *dependencies, _PyUOpInstruction
return sym_new_not_null(ctx);
}
static PyCodeObject *
get_code_with_logging(_PyUOpInstruction *op)
{
PyCodeObject *co = NULL;
uint64_t push_operand = op->operand0;
if (push_operand & 1) {
co = (PyCodeObject *)(push_operand & ~1);
DPRINTF(3, " code=%p\n", co);
assert(PyCode_Check(co));
}
else {
PyFunctionObject *func = (PyFunctionObject *)push_operand;
DPRINTF(3, " func=%p ", func);
if (func == NULL) {
DPRINTF(3, "\n");
DPRINTF(1, "Missing function\n");
return NULL;
}
co = (PyCodeObject *)func->func_code;
DPRINTF(3, "code=%p\n", co);
}
return co;
}
static
PyCodeObject *
get_current_code_object(JitOptContext *ctx)

View file

@ -30,6 +30,7 @@ typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame;
#define sym_set_compact_int(SYM) _Py_uop_sym_set_compact_int(ctx, SYM)
#define sym_is_bottom _Py_uop_sym_is_bottom
#define frame_new _Py_uop_frame_new
#define frame_new_from_symbol _Py_uop_frame_new_from_symbol
#define frame_pop _Py_uop_frame_pop
#define sym_new_tuple _Py_uop_sym_new_tuple
#define sym_tuple_getitem _Py_uop_sym_tuple_getitem
@ -40,6 +41,11 @@ typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame;
#define sym_new_truthiness _Py_uop_sym_new_truthiness
#define sym_new_predicate _Py_uop_sym_new_predicate
#define sym_apply_predicate_narrowing _Py_uop_sym_apply_predicate_narrowing
#define sym_set_recorded_type(SYM, TYPE) _Py_uop_sym_set_recorded_type(ctx, SYM, TYPE)
#define sym_set_recorded_value(SYM, VAL) _Py_uop_sym_set_recorded_value(ctx, SYM, VAL)
#define sym_set_recorded_gen_func(SYM, VAL) _Py_uop_sym_set_recorded_gen_func(ctx, SYM, VAL)
#define sym_get_probable_func_code _Py_uop_sym_get_probable_func_code
#define sym_get_probable_value _Py_uop_sym_get_probable_value
extern int
optimize_to_bool(
@ -337,14 +343,23 @@ dummy_func(void) {
GETLOCAL(this_instr->operand0) = sym_new_null(ctx);
}
op(_BINARY_OP_SUBSCR_INIT_CALL, (container, sub, getitem -- new_frame)) {
assert((this_instr + 1)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging(this_instr + 1);
if (co == NULL) {
ctx->done = true;
break;
op(_BINARY_OP_SUBSCR_CHECK_FUNC, (container, unused -- container, unused, getitem)) {
getitem = sym_new_not_null(ctx);
PyTypeObject *tp = sym_get_type(container);
if (tp == NULL) {
PyObject *c = sym_get_probable_value(container);
if (c != NULL) {
tp = Py_TYPE(c);
}
}
_Py_UOpsAbstractFrame *f = frame_new(ctx, co, 0, NULL, 0);
if (tp != NULL) {
PyObject *getitem_o = ((PyHeapTypeObject *)tp)->_spec_cache.getitem;
sym_set_recorded_value(getitem, getitem_o);
}
}
op(_BINARY_OP_SUBSCR_INIT_CALL, (container, sub, getitem -- new_frame)) {
_Py_UOpsAbstractFrame *f = frame_new_from_symbol(ctx, getitem, 0, NULL, 0);
if (f == NULL) {
break;
}
@ -556,17 +571,10 @@ dummy_func(void) {
}
op(_COMPARE_OP_STR, (left, right -- res, l, r)) {
int cmp_mask = oparg & (COMPARE_LT_MASK | COMPARE_GT_MASK | COMPARE_EQ_MASK);
if (cmp_mask == COMPARE_EQ_MASK) {
res = sym_new_predicate(ctx, left, right, JIT_PRED_EQ);
}
else if (cmp_mask == (COMPARE_LT_MASK | COMPARE_GT_MASK)) {
res = sym_new_predicate(ctx, left, right, JIT_PRED_NE);
}
else {
res = sym_new_type(ctx, &PyBool_Type);
}
/* Cannot use predicate optimization here, as `a == b`
* does not imply that `a` is equivalent to `b`. `a` may be
* mortal, while `b` is immortal */
res = sym_new_type(ctx, &PyBool_Type);
l = left;
r = right;
REPLACE_OPCODE_IF_EVALUATES_PURE(left, right, res);
@ -814,12 +822,8 @@ dummy_func(void) {
op(_LOAD_ATTR_PROPERTY_FRAME, (fget/4, owner -- new_frame)) {
// + 1 for _SAVE_RETURN_OFFSET
assert((this_instr + 2)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging(this_instr + 2);
if (co == NULL) {
ctx->done = true;
break;
}
// FIX ME -- This needs a version check and function watcher
PyCodeObject *co = (PyCodeObject *)((PyFunctionObject *)fget)->func_code;
_Py_UOpsAbstractFrame *f = frame_new(ctx, co, 0, NULL, 0);
if (f == NULL) {
break;
@ -872,14 +876,6 @@ dummy_func(void) {
op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null, args[oparg] -- new_frame)) {
int argcount = oparg;
assert((this_instr + 2)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging((this_instr + 2));
if (co == NULL) {
ctx->done = true;
break;
}
assert(!PyJitRef_IsNull(self_or_null));
assert(args != NULL);
if (sym_is_not_null(self_or_null)) {
@ -889,9 +885,9 @@ dummy_func(void) {
}
if (sym_is_null(self_or_null) || sym_is_not_null(self_or_null)) {
new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, args, argcount));
new_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, callable, 0, args, argcount));
} else {
new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0));
new_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, callable, 0, NULL, 0));
}
}
@ -902,36 +898,15 @@ dummy_func(void) {
}
op(_PY_FRAME_GENERAL, (callable, self_or_null, args[oparg] -- new_frame)) {
assert((this_instr + 2)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging((this_instr + 2));
if (co == NULL) {
ctx->done = true;
break;
}
new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0));
new_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, callable, 0, NULL, 0));
}
op(_PY_FRAME_KW, (callable, self_or_null, args[oparg], kwnames -- new_frame)) {
assert((this_instr + 2)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging((this_instr + 2));
if (co == NULL) {
ctx->done = true;
break;
}
new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0));
new_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, callable, 0, NULL, 0));
}
op(_PY_FRAME_EX, (func_st, null, callargs_st, kwargs_st -- ex_frame)) {
assert((this_instr + 2)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging((this_instr + 2));
if (co == NULL) {
ctx->done = true;
break;
}
ex_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0));
ex_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, func_st, 0, NULL, 0));
}
op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable, self_or_null, args[oparg] -- callable, self_or_null, args[oparg])) {
@ -954,8 +929,7 @@ dummy_func(void) {
ctx->frame = shim;
ctx->curr_frame_depth++;
assert((this_instr + 1)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging((this_instr + 1));
init_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, args-1, oparg+1));
init_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, init, 0, args-1, oparg+1));
}
op(_RETURN_VALUE, (retval -- res)) {
@ -964,7 +938,9 @@ dummy_func(void) {
DEAD(retval);
SAVE_STACK();
ctx->frame->stack_pointer = stack_pointer;
PyCodeObject *returning_code = get_code_with_logging(this_instr);
assert(this_instr[1].opcode == _RECORD_CODE);
PyCodeObject *returning_code = (PyCodeObject *)this_instr[1].operand0;
assert(PyCode_Check(returning_code));
if (returning_code == NULL) {
ctx->done = true;
break;
@ -973,8 +949,8 @@ dummy_func(void) {
if (ctx->curr_frame_depth >= 2) {
PyCodeObject *expected_code = ctx->frames[ctx->curr_frame_depth - 2].code;
if (expected_code == returning_code) {
assert((this_instr + 1)->opcode == _GUARD_IP_RETURN_VALUE);
REPLACE_OP((this_instr + 1), _NOP, 0, 0);
assert(this_instr[2].opcode == _GUARD_IP_RETURN_VALUE);
REPLACE_OP((this_instr + 2), _NOP, 0, 0);
}
}
if (frame_pop(ctx, returning_code, returning_stacklevel)) {
@ -989,7 +965,9 @@ dummy_func(void) {
op(_RETURN_GENERATOR, ( -- res)) {
SYNC_SP();
ctx->frame->stack_pointer = stack_pointer;
PyCodeObject *returning_code = get_code_with_logging(this_instr);
assert(this_instr[1].opcode == _RECORD_CODE);
PyCodeObject *returning_code = (PyCodeObject *)this_instr[1].operand0;
assert(PyCode_Check(returning_code));
if (returning_code == NULL) {
ctx->done = true;
break;
@ -1009,7 +987,9 @@ dummy_func(void) {
DEAD(retval);
SAVE_STACK();
ctx->frame->stack_pointer = stack_pointer;
PyCodeObject *returning_code = get_code_with_logging(this_instr);
assert(this_instr[1].opcode == _RECORD_CODE);
PyCodeObject *returning_code = (PyCodeObject *)this_instr[1].operand0;
assert(PyCode_Check(returning_code));
if (returning_code == NULL) {
ctx->done = true;
break;
@ -1035,14 +1015,8 @@ dummy_func(void) {
}
}
op(_FOR_ITER_GEN_FRAME, (unused, unused -- unused, unused, gen_frame)) {
assert((this_instr + 1)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging((this_instr + 1));
if (co == NULL) {
ctx->done = true;
break;
}
_Py_UOpsAbstractFrame *new_frame = frame_new(ctx, co, 1, NULL, 0);
op(_FOR_ITER_GEN_FRAME, (iter, unused -- iter, unused, gen_frame)) {
_Py_UOpsAbstractFrame *new_frame = frame_new_from_symbol(ctx, iter, 1, NULL, 0);
if (new_frame == NULL) {
ctx->done = true;
break;
@ -1051,14 +1025,8 @@ dummy_func(void) {
gen_frame = PyJitRef_WrapInvalid(new_frame);
}
op(_SEND_GEN_FRAME, (unused, v -- unused, gen_frame)) {
assert((this_instr + 1)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging((this_instr + 1));
if (co == NULL) {
ctx->done = true;
break;
}
_Py_UOpsAbstractFrame *new_frame = frame_new(ctx, co, 1, NULL, 0);
op(_SEND_GEN_FRAME, (receiver, v -- receiver, gen_frame)) {
_Py_UOpsAbstractFrame *new_frame = frame_new_from_symbol(ctx, receiver, 1, NULL, 0);
if (new_frame == NULL) {
ctx->done = true;
break;
@ -1067,9 +1035,8 @@ dummy_func(void) {
gen_frame = PyJitRef_WrapInvalid(new_frame);
}
op(_CHECK_STACK_SPACE, (unused, unused, unused[oparg] -- unused, unused, unused[oparg])) {
assert((this_instr + 4)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging((this_instr + 4));
op(_CHECK_STACK_SPACE, (callable, unused, unused[oparg] -- callable, unused, unused[oparg])) {
PyCodeObject *co = sym_get_probable_func_code(callable);
if (co == NULL) {
ctx->done = true;
break;
@ -1089,22 +1056,12 @@ dummy_func(void) {
ctx->frame = (_Py_UOpsAbstractFrame *)PyJitRef_Unwrap(new_frame);
ctx->curr_frame_depth++;
stack_pointer = ctx->frame->stack_pointer;
uint64_t operand = this_instr->operand0;
if (operand == 0) {
ctx->done = true;
break;
}
if (!(operand & 1)) {
PyFunctionObject *func = (PyFunctionObject *)operand;
// No need to re-add to dependencies here. Already
// handled by the tracer.
ctx->frame->func = func;
}
// Fixed calls don't need IP guards.
if ((this_instr-1)->opcode == _CREATE_INIT_FRAME) {
assert((this_instr+1)->opcode == _GUARD_IP__PUSH_FRAME);
REPLACE_OP(this_instr+1, _NOP, 0, 0);
}
assert(ctx->frame->locals != NULL);
}
op(_UNPACK_SEQUENCE, (seq -- values[oparg], top[0])) {
@ -1653,6 +1610,32 @@ dummy_func(void) {
ss = sub_st;
}
op(_RECORD_TOS, (tos -- tos)) {
sym_set_recorded_value(tos, (PyObject *)this_instr->operand0);
}
op(_RECORD_TOS_TYPE, (tos -- tos)) {
PyTypeObject *tp = (PyTypeObject *)this_instr->operand0;
sym_set_recorded_type(tos, tp);
}
op(_RECORD_NOS, (nos, tos -- nos, tos)) {
sym_set_recorded_value(nos, (PyObject *)this_instr->operand0);
}
op(_RECORD_4OS, (value, _3os, nos, tos -- value, _3os, nos, tos)) {
sym_set_recorded_value(value, (PyObject *)this_instr->operand0);
}
op(_RECORD_CALLABLE, (func, self, args[oparg] -- func, self, args[oparg])) {
sym_set_recorded_value(func, (PyObject *)this_instr->operand0);
}
op(_RECORD_NOS_GEN_FUNC, (nos, tos -- nos, tos)) {
PyFunctionObject *func = (PyFunctionObject *)this_instr->operand0;
assert(func == NULL || PyFunction_Check(func));
sym_set_recorded_gen_func(nos, func);
}
// END BYTECODES //

View file

@ -1115,8 +1115,21 @@
}
case _BINARY_OP_SUBSCR_CHECK_FUNC: {
JitOptRef container;
JitOptRef getitem;
container = stack_pointer[-2];
getitem = sym_new_not_null(ctx);
PyTypeObject *tp = sym_get_type(container);
if (tp == NULL) {
PyObject *c = sym_get_probable_value(container);
if (c != NULL) {
tp = Py_TYPE(c);
}
}
if (tp != NULL) {
PyObject *getitem_o = ((PyHeapTypeObject *)tp)->_spec_cache.getitem;
sym_set_recorded_value(getitem, getitem_o);
}
CHECK_STACK_BOUNDS(1);
stack_pointer[0] = getitem;
stack_pointer += 1;
@ -1125,18 +1138,14 @@
}
case _BINARY_OP_SUBSCR_INIT_CALL: {
JitOptRef getitem;
JitOptRef sub;
JitOptRef container;
JitOptRef new_frame;
getitem = stack_pointer[-1];
sub = stack_pointer[-2];
container = stack_pointer[-3];
assert((this_instr + 1)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging(this_instr + 1);
if (co == NULL) {
ctx->done = true;
break;
}
_Py_UOpsAbstractFrame *f = frame_new(ctx, co, 0, NULL, 0);
_Py_UOpsAbstractFrame *f = frame_new_from_symbol(ctx, getitem, 0, NULL, 0);
if (f == NULL) {
break;
}
@ -1239,7 +1248,9 @@
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
ctx->frame->stack_pointer = stack_pointer;
PyCodeObject *returning_code = get_code_with_logging(this_instr);
assert(this_instr[1].opcode == _RECORD_CODE);
PyCodeObject *returning_code = (PyCodeObject *)this_instr[1].operand0;
assert(PyCode_Check(returning_code));
if (returning_code == NULL) {
ctx->done = true;
break;
@ -1248,8 +1259,8 @@
if (ctx->curr_frame_depth >= 2) {
PyCodeObject *expected_code = ctx->frames[ctx->curr_frame_depth - 2].code;
if (expected_code == returning_code) {
assert((this_instr + 1)->opcode == _GUARD_IP_RETURN_VALUE);
REPLACE_OP((this_instr + 1), _NOP, 0, 0);
assert(this_instr[2].opcode == _GUARD_IP_RETURN_VALUE);
REPLACE_OP((this_instr + 2), _NOP, 0, 0);
}
}
if (frame_pop(ctx, returning_code, returning_stacklevel)) {
@ -1292,15 +1303,11 @@
case _SEND_GEN_FRAME: {
JitOptRef v;
JitOptRef receiver;
JitOptRef gen_frame;
v = stack_pointer[-1];
assert((this_instr + 1)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging((this_instr + 1));
if (co == NULL) {
ctx->done = true;
break;
}
_Py_UOpsAbstractFrame *new_frame = frame_new(ctx, co, 1, NULL, 0);
receiver = stack_pointer[-2];
_Py_UOpsAbstractFrame *new_frame = frame_new_from_symbol(ctx, receiver, 1, NULL, 0);
if (new_frame == NULL) {
ctx->done = true;
break;
@ -1320,7 +1327,9 @@
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
ctx->frame->stack_pointer = stack_pointer;
PyCodeObject *returning_code = get_code_with_logging(this_instr);
assert(this_instr[1].opcode == _RECORD_CODE);
PyCodeObject *returning_code = (PyCodeObject *)this_instr[1].operand0;
assert(PyCode_Check(returning_code));
if (returning_code == NULL) {
ctx->done = true;
break;
@ -1984,12 +1993,7 @@
JitOptRef new_frame;
owner = stack_pointer[-1];
PyObject *fget = (PyObject *)this_instr->operand0;
assert((this_instr + 2)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging(this_instr + 2);
if (co == NULL) {
ctx->done = true;
break;
}
PyCodeObject *co = (PyCodeObject *)((PyFunctionObject *)fget)->func_code;
_Py_UOpsAbstractFrame *f = frame_new(ctx, co, 0, NULL, 0);
if (f == NULL) {
break;
@ -2267,16 +2271,7 @@
JitOptRef r;
right = stack_pointer[-1];
left = stack_pointer[-2];
int cmp_mask = oparg & (COMPARE_LT_MASK | COMPARE_GT_MASK | COMPARE_EQ_MASK);
if (cmp_mask == COMPARE_EQ_MASK) {
res = sym_new_predicate(ctx, left, right, JIT_PRED_EQ);
}
else if (cmp_mask == (COMPARE_LT_MASK | COMPARE_GT_MASK)) {
res = sym_new_predicate(ctx, left, right, JIT_PRED_NE);
}
else {
res = sym_new_type(ctx, &PyBool_Type);
}
res = sym_new_type(ctx, &PyBool_Type);
l = left;
r = right;
if (
@ -2694,14 +2689,10 @@
}
case _FOR_ITER_GEN_FRAME: {
JitOptRef iter;
JitOptRef gen_frame;
assert((this_instr + 1)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging((this_instr + 1));
if (co == NULL) {
ctx->done = true;
break;
}
_Py_UOpsAbstractFrame *new_frame = frame_new(ctx, co, 1, NULL, 0);
iter = stack_pointer[-2];
_Py_UOpsAbstractFrame *new_frame = frame_new_from_symbol(ctx, iter, 1, NULL, 0);
if (new_frame == NULL) {
ctx->done = true;
break;
@ -2884,14 +2875,10 @@
/* _MONITOR_CALL is not a viable micro-op for tier 2 */
case _PY_FRAME_GENERAL: {
JitOptRef callable;
JitOptRef new_frame;
assert((this_instr + 2)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging((this_instr + 2));
if (co == NULL) {
ctx->done = true;
break;
}
new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0));
callable = stack_pointer[-2 - oparg];
new_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, callable, 0, NULL, 0));
CHECK_STACK_BOUNDS(-1 - oparg);
stack_pointer[-2 - oparg] = new_frame;
stack_pointer += -1 - oparg;
@ -2996,8 +2983,9 @@
}
case _CHECK_STACK_SPACE: {
assert((this_instr + 4)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging((this_instr + 4));
JitOptRef callable;
callable = stack_pointer[-2 - oparg];
PyCodeObject *co = sym_get_probable_func_code(callable);
if (co == NULL) {
ctx->done = true;
break;
@ -3013,16 +3001,12 @@
case _INIT_CALL_PY_EXACT_ARGS: {
JitOptRef *args;
JitOptRef self_or_null;
JitOptRef callable;
JitOptRef new_frame;
args = &stack_pointer[-oparg];
self_or_null = stack_pointer[-1 - oparg];
callable = stack_pointer[-2 - oparg];
int argcount = oparg;
assert((this_instr + 2)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging((this_instr + 2));
if (co == NULL) {
ctx->done = true;
break;
}
assert(!PyJitRef_IsNull(self_or_null));
assert(args != NULL);
if (sym_is_not_null(self_or_null)) {
@ -3030,9 +3014,9 @@
argcount++;
}
if (sym_is_null(self_or_null) || sym_is_not_null(self_or_null)) {
new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, args, argcount));
new_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, callable, 0, args, argcount));
} else {
new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0));
new_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, callable, 0, NULL, 0));
}
CHECK_STACK_BOUNDS(-1 - oparg);
stack_pointer[-2 - oparg] = new_frame;
@ -3053,19 +3037,11 @@
ctx->frame = (_Py_UOpsAbstractFrame *)PyJitRef_Unwrap(new_frame);
ctx->curr_frame_depth++;
stack_pointer = ctx->frame->stack_pointer;
uint64_t operand = this_instr->operand0;
if (operand == 0) {
ctx->done = true;
break;
}
if (!(operand & 1)) {
PyFunctionObject *func = (PyFunctionObject *)operand;
ctx->frame->func = func;
}
if ((this_instr-1)->opcode == _CREATE_INIT_FRAME) {
assert((this_instr+1)->opcode == _GUARD_IP__PUSH_FRAME);
REPLACE_OP(this_instr+1, _NOP, 0, 0);
}
assert(ctx->frame->locals != NULL);
break;
}
@ -3212,9 +3188,11 @@
case _CREATE_INIT_FRAME: {
JitOptRef *args;
JitOptRef self;
JitOptRef init;
JitOptRef init_frame;
args = &stack_pointer[-oparg];
self = stack_pointer[-1 - oparg];
init = stack_pointer[-2 - oparg];
ctx->frame->stack_pointer = stack_pointer - oparg - 2;
_Py_UOpsAbstractFrame *shim = frame_new(ctx, (PyCodeObject *)&_Py_InitCleanup, 0, NULL, 0);
if (shim == NULL) {
@ -3226,8 +3204,7 @@
ctx->frame = shim;
ctx->curr_frame_depth++;
assert((this_instr + 1)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging((this_instr + 1));
init_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, args-1, oparg+1));
init_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, init, 0, args-1, oparg+1));
CHECK_STACK_BOUNDS(-1 - oparg);
stack_pointer[-2 - oparg] = init_frame;
stack_pointer += -1 - oparg;
@ -3501,14 +3478,10 @@
/* _DO_CALL_KW is not a viable micro-op for tier 2 */
case _PY_FRAME_KW: {
JitOptRef callable;
JitOptRef new_frame;
assert((this_instr + 2)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging((this_instr + 2));
if (co == NULL) {
ctx->done = true;
break;
}
new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0));
callable = stack_pointer[-3 - oparg];
new_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, callable, 0, NULL, 0));
CHECK_STACK_BOUNDS(-2 - oparg);
stack_pointer[-3 - oparg] = new_frame;
stack_pointer += -2 - oparg;
@ -3553,14 +3526,10 @@
}
case _PY_FRAME_EX: {
JitOptRef func_st;
JitOptRef ex_frame;
assert((this_instr + 2)->opcode == _PUSH_FRAME);
PyCodeObject *co = get_code_with_logging((this_instr + 2));
if (co == NULL) {
ctx->done = true;
break;
}
ex_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0));
func_st = stack_pointer[-4];
ex_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, func_st, 0, NULL, 0));
CHECK_STACK_BOUNDS(-3);
stack_pointer[-4] = ex_frame;
stack_pointer += -3;
@ -3602,7 +3571,9 @@
case _RETURN_GENERATOR: {
JitOptRef res;
ctx->frame->stack_pointer = stack_pointer;
PyCodeObject *returning_code = get_code_with_logging(this_instr);
assert(this_instr[1].opcode == _RECORD_CODE);
PyCodeObject *returning_code = (PyCodeObject *)this_instr[1].operand0;
assert(PyCode_Check(returning_code));
if (returning_code == NULL) {
ctx->done = true;
break;
@ -4167,6 +4138,10 @@
break;
}
case _GUARD_CODE: {
break;
}
case _GUARD_IP__PUSH_FRAME: {
break;
}
@ -4184,22 +4159,47 @@
}
case _RECORD_TOS: {
JitOptRef tos;
tos = stack_pointer[-1];
sym_set_recorded_value(tos, (PyObject *)this_instr->operand0);
break;
}
case _RECORD_TOS_TYPE: {
JitOptRef tos;
tos = stack_pointer[-1];
PyTypeObject *tp = (PyTypeObject *)this_instr->operand0;
sym_set_recorded_type(tos, tp);
break;
}
case _RECORD_NOS: {
JitOptRef nos;
nos = stack_pointer[-2];
sym_set_recorded_value(nos, (PyObject *)this_instr->operand0);
break;
}
case _RECORD_NOS_GEN_FUNC: {
JitOptRef nos;
nos = stack_pointer[-2];
PyFunctionObject *func = (PyFunctionObject *)this_instr->operand0;
assert(func == NULL || PyFunction_Check(func));
sym_set_recorded_gen_func(nos, func);
break;
}
case _RECORD_4OS: {
JitOptRef value;
value = stack_pointer[-4];
sym_set_recorded_value(value, (PyObject *)this_instr->operand0);
break;
}
case _RECORD_CALLABLE: {
JitOptRef func;
func = stack_pointer[-2 - oparg];
sym_set_recorded_value(func, (PyObject *)this_instr->operand0);
break;
}
@ -4207,7 +4207,7 @@
break;
}
case _RECORD_CALLER_CODE: {
case _RECORD_CODE: {
break;
}

View file

@ -4,6 +4,7 @@
#include "pycore_code.h"
#include "pycore_frame.h"
#include "pycore_interpframe.h"
#include "pycore_long.h"
#include "pycore_optimizer.h"
#include "pycore_stats.h"
@ -25,26 +26,26 @@ state represents no information, and the BOTTOM state represents contradictory
information. Though symbols logically progress through all intermediate nodes,
we often skip in-between states for convenience:
UNKNOWN-------------------+
| | |
NULL | |
| | | <- Anything below this level is an object.
| NON_NULL-+ |
| | | | <- Anything below this level has a known type version.
| TYPE_VERSION | |
| | | | <- Anything below this level has a known type.
| KNOWN_CLASS | |
| | | | | | PREDICATE
| | | INT* | | |
| | | | | | | <- Anything below this level has a known truthiness.
| | | | | TRUTHINESS |
| | | | | | |
| TUPLE | | | | |
| | | | | | | <- Anything below this level is a known constant.
| KNOWN_VALUE--+----------+
| | <- Anything below this level is unreachable.
UNKNOWN-------------------+------+
| | | |
NULL | | RECORDED_VALUE*
| | | | <- Anything below this level is an object.
| NON_NULL-+ | |
| | | | | <- Anything below this level has a known type version.
| TYPE_VERSION | | |
| | | | | <- Anything below this level has a known type.
| KNOWN_CLASS | | |
| | | | | | PREDICATE RECORDED_VALUE(known type)
| | | INT* | | | |
| | | | | | | | <- Anything below this level has a known truthiness.
| TUPLE | | | TRUTHINESS | |
| | | | | | | | <- Anything below this level is a known constant.
| KNOWN_VALUE--+----------+------+
| | <- Anything below this level is unreachable.
BOTTOM
For example, after guarding that the type of an UNKNOWN local is int, we can
narrow the symbol to KNOWN_CLASS (logically progressing though NON_NULL and
TYPE_VERSION to get there). Later, we may learn that it is falsey based on the
@ -54,6 +55,7 @@ the same symbol, that would be a contradiction, and the symbol would be set to
BOTTOM (indicating that the code is unreachable).
INT* is a limited range int, currently a "compact" int.
RECORDED_VALUE* includes RECORDED_TYPE and RECORDED_GEN_FUNC
*/
@ -81,7 +83,8 @@ _PyUOpSymPrint(JitOptRef ref)
return;
}
JitOptSymbol *sym = PyJitRef_Unwrap(ref);
switch (sym->tag) {
JitSymType tag = sym->tag;
switch (tag) {
case JIT_SYM_UNKNOWN_TAG:
printf("<? at %p>", (void *)sym);
break;
@ -116,8 +119,17 @@ _PyUOpSymPrint(JitOptRef ref)
case JIT_SYM_PREDICATE_TAG:
printf("<predicate at %p>", (void *)sym);
break;
case JIT_SYM_RECORDED_VALUE_TAG:
printf("<recorded value %p>", sym->recorded_value.value);
break;
case JIT_SYM_RECORDED_TYPE_TAG:
printf("<recorded type %s>", sym->recorded_type.type->tp_name);
break;
case JIT_SYM_RECORDED_GEN_FUNC_TAG:
printf("<recorded gen func at %p>", (void *)sym);
break;
default:
printf("<tag=%d at %p>", sym->tag, (void *)sym);
printf("<tag=%d at %p>", tag, (void *)sym);
break;
}
}
@ -304,8 +316,31 @@ _Py_uop_sym_set_type(JitOptContext *ctx, JitOptRef ref, PyTypeObject *typ)
sym_set_bottom(ctx, sym);
}
return;
case JIT_SYM_RECORDED_GEN_FUNC_TAG:
if (typ != &PyGen_Type) {
sym_set_bottom(ctx, sym);
}
return;
case JIT_SYM_BOTTOM_TAG:
return;
case JIT_SYM_RECORDED_VALUE_TAG:
if (Py_TYPE(sym->recorded_value.value) == typ) {
sym->recorded_value.known_type = true;
}
else {
sym_set_bottom(ctx, sym);
}
return;
case JIT_SYM_RECORDED_TYPE_TAG:
if (sym->recorded_type.type == typ) {
sym->tag = JIT_SYM_KNOWN_CLASS_TAG;
sym->cls.version = 0;
sym->cls.type = typ;
}
else {
sym_set_bottom(ctx, sym);
}
return;
case JIT_SYM_NON_NULL_TAG:
case JIT_SYM_UNKNOWN_TAG:
sym->tag = JIT_SYM_KNOWN_CLASS_TAG;
@ -361,6 +396,12 @@ _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptRef ref, unsigned int ver
return false;
};
return true;
case JIT_SYM_RECORDED_GEN_FUNC_TAG:
if (PyGen_Type.tp_version_tag != version) {
sym_set_bottom(ctx, sym);
return false;
}
return true;
case JIT_SYM_TYPE_VERSION_TAG:
if (sym->version.version != version) {
sym_set_bottom(ctx, sym);
@ -387,6 +428,29 @@ _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptRef ref, unsigned int ver
return false;
}
return true;
case JIT_SYM_RECORDED_VALUE_TAG:
if (Py_TYPE(sym->recorded_value.value)->tp_version_tag == version) {
sym->recorded_value.known_type = true;
sym->tag = JIT_SYM_KNOWN_CLASS_TAG;
sym->cls.type = Py_TYPE(sym->recorded_value.value);
sym->cls.version = version;
return true;
}
else {
sym_set_bottom(ctx, sym);
return false;
}
case JIT_SYM_RECORDED_TYPE_TAG:
if (sym->recorded_type.type->tp_version_tag == version) {
sym->tag = JIT_SYM_KNOWN_CLASS_TAG;
sym->cls.type = sym->recorded_type.type;
sym->cls.version = version;
return true;
}
else {
sym_set_bottom(ctx, sym);
return false;
}
}
Py_UNREACHABLE();
}
@ -398,6 +462,7 @@ _Py_uop_sym_set_const(JitOptContext *ctx, JitOptRef ref, PyObject *const_val)
JitSymType tag = sym->tag;
switch(tag) {
case JIT_SYM_NULL_TAG:
case JIT_SYM_RECORDED_GEN_FUNC_TAG:
sym_set_bottom(ctx, sym);
return;
case JIT_SYM_KNOWN_CLASS_TAG:
@ -437,6 +502,11 @@ _Py_uop_sym_set_const(JitOptContext *ctx, JitOptRef ref, PyObject *const_val)
return;
case JIT_SYM_BOTTOM_TAG:
return;
case JIT_SYM_RECORDED_VALUE_TAG:
case JIT_SYM_RECORDED_TYPE_TAG:
/* The given value might contradict the recorded one,
* in which case we could return bottom.
* Just discard the recorded value for now */
case JIT_SYM_NON_NULL_TAG:
case JIT_SYM_UNKNOWN_TAG:
make_const(sym, const_val);
@ -592,6 +662,12 @@ _Py_uop_sym_get_type(JitOptRef ref)
case JIT_SYM_BOTTOM_TAG:
case JIT_SYM_NON_NULL_TAG:
case JIT_SYM_UNKNOWN_TAG:
case JIT_SYM_RECORDED_TYPE_TAG:
return NULL;
case JIT_SYM_RECORDED_VALUE_TAG:
if (sym->recorded_value.known_type) {
return Py_TYPE(sym->recorded_value.value);
}
return NULL;
case JIT_SYM_KNOWN_CLASS_TAG:
return sym->cls.type;
@ -606,7 +682,8 @@ _Py_uop_sym_get_type(JitOptRef ref)
return &PyBool_Type;
case JIT_SYM_COMPACT_INT:
return &PyLong_Type;
case JIT_SYM_RECORDED_GEN_FUNC_TAG:
return &PyGen_Type;
}
Py_UNREACHABLE();
}
@ -621,6 +698,8 @@ _Py_uop_sym_get_type_version(JitOptRef ref)
case JIT_SYM_BOTTOM_TAG:
case JIT_SYM_NON_NULL_TAG:
case JIT_SYM_UNKNOWN_TAG:
case JIT_SYM_RECORDED_VALUE_TAG:
case JIT_SYM_RECORDED_TYPE_TAG:
return 0;
case JIT_SYM_TYPE_VERSION_TAG:
return sym->version.version;
@ -635,6 +714,8 @@ _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_RECORDED_GEN_FUNC_TAG:
return PyGen_Type.tp_version_tag;
}
Py_UNREACHABLE();
}
@ -658,11 +739,69 @@ _Py_uop_sym_matches_type_version(JitOptRef sym, unsigned int version)
return _Py_uop_sym_get_type_version(sym) == version;
}
PyObject *
_Py_uop_sym_get_probable_value(JitOptRef ref)
{
JitOptSymbol *sym = PyJitRef_Unwrap(ref);
JitSymType tag = sym->tag;
switch(tag) {
case JIT_SYM_NULL_TAG:
case JIT_SYM_BOTTOM_TAG:
case JIT_SYM_NON_NULL_TAG:
case JIT_SYM_UNKNOWN_TAG:
case JIT_SYM_RECORDED_TYPE_TAG:
case JIT_SYM_TYPE_VERSION_TAG:
case JIT_SYM_TUPLE_TAG:
case JIT_SYM_PREDICATE_TAG:
case JIT_SYM_TRUTHINESS_TAG:
case JIT_SYM_COMPACT_INT:
case JIT_SYM_KNOWN_CLASS_TAG:
case JIT_SYM_RECORDED_GEN_FUNC_TAG:
return NULL;
case JIT_SYM_RECORDED_VALUE_TAG:
return sym->recorded_value.value;
case JIT_SYM_KNOWN_VALUE_TAG:
return sym->value.value;
}
Py_UNREACHABLE();
}
PyCodeObject *
_Py_uop_sym_get_probable_func_code(JitOptRef ref)
{
JitOptSymbol *sym = PyJitRef_Unwrap(ref);
if (sym->tag == JIT_SYM_RECORDED_GEN_FUNC_TAG) {
return (PyCodeObject *)PyFunction_GET_CODE(sym->recorded_gen_func.func);
}
PyObject *obj = _Py_uop_sym_get_probable_value(ref);
if (obj != NULL) {
if (PyFunction_Check(obj)) {
return (PyCodeObject *)PyFunction_GET_CODE(obj);
}
}
return NULL;
}
PyFunctionObject *
_Py_uop_sym_get_probable_function(JitOptRef ref)
{
JitOptSymbol *sym = PyJitRef_Unwrap(ref);
if (sym->tag == JIT_SYM_RECORDED_GEN_FUNC_TAG) {
return sym->recorded_gen_func.func;
}
PyObject *obj = _Py_uop_sym_get_probable_value(ref);
if (obj != NULL && PyFunction_Check(obj)) {
return (PyFunctionObject *)obj;
}
return NULL;
}
int
_Py_uop_sym_truthiness(JitOptContext *ctx, JitOptRef ref)
{
JitOptSymbol *sym = PyJitRef_Unwrap(ref);
switch(sym->tag) {
JitSymType tag = sym->tag;
switch (tag) {
case JIT_SYM_NULL_TAG:
case JIT_SYM_TYPE_VERSION_TAG:
case JIT_SYM_BOTTOM_TAG:
@ -670,6 +809,9 @@ _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_RECORDED_VALUE_TAG:
case JIT_SYM_RECORDED_TYPE_TAG:
case JIT_SYM_RECORDED_GEN_FUNC_TAG:
return -1;
case JIT_SYM_KNOWN_CLASS_TAG:
/* TODO :
@ -681,7 +823,7 @@ _Py_uop_sym_truthiness(JitOptContext *ctx, JitOptRef ref)
case JIT_SYM_TUPLE_TAG:
return sym->tuple.length != 0;
case JIT_SYM_TRUTHINESS_TAG:
;
{
JitOptSymbol *value = allocation_base(ctx) + sym->truthiness.value;
int truthiness = _Py_uop_sym_truthiness(ctx,
PyJitRef_Wrap(value));
@ -691,6 +833,7 @@ _Py_uop_sym_truthiness(JitOptContext *ctx, JitOptRef ref)
truthiness ^= sym->truthiness.invert;
make_const(sym, truthiness ? Py_True : Py_False);
return truthiness;
}
}
PyObject *value = sym->value.value;
/* Only handle a few known safe types */
@ -801,6 +944,7 @@ _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef ref)
JitSymType tag = sym->tag;
switch(tag) {
case JIT_SYM_NULL_TAG:
case JIT_SYM_RECORDED_GEN_FUNC_TAG:
sym_set_bottom(ctx, sym);
return;
case JIT_SYM_KNOWN_CLASS_TAG:
@ -832,6 +976,11 @@ _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef ref)
case JIT_SYM_BOTTOM_TAG:
case JIT_SYM_COMPACT_INT:
return;
case JIT_SYM_RECORDED_VALUE_TAG:
case JIT_SYM_RECORDED_TYPE_TAG:
/* The given value might contradict the recorded one,
* in which case we could return bottom.
* Just discard the recorded value for now */
case JIT_SYM_NON_NULL_TAG:
case JIT_SYM_UNKNOWN_TAG:
sym->tag = JIT_SYM_COMPACT_INT;
@ -941,6 +1090,222 @@ _Py_uop_sym_new_compact_int(JitOptContext *ctx)
return PyJitRef_Wrap(sym);
}
void
_Py_uop_sym_set_recorded_value(JitOptContext *ctx, JitOptRef ref, PyObject *value)
{
// It is possible for value to be NULL due to respecialization
// during execution of the traced instruction.
if (value == NULL) {
return;
}
JitOptSymbol *sym = PyJitRef_Unwrap(ref);
JitSymType tag = sym->tag;
switch(tag) {
case JIT_SYM_NULL_TAG:
sym_set_bottom(ctx, sym);
return;
case JIT_SYM_BOTTOM_TAG:
return;
case JIT_SYM_NON_NULL_TAG:
case JIT_SYM_UNKNOWN_TAG:
sym->tag = JIT_SYM_RECORDED_VALUE_TAG;
sym->recorded_value.known_type = false;
sym->recorded_value.value = value;
return;
case JIT_SYM_RECORDED_VALUE_TAG:
if (sym->recorded_value.value != value) {
sym_set_bottom(ctx, sym);
}
return;
case JIT_SYM_RECORDED_TYPE_TAG:
if (sym->recorded_type.type == Py_TYPE(value)) {
sym->tag = JIT_SYM_RECORDED_VALUE_TAG;
sym->recorded_value.known_type = false;
sym->recorded_value.value = value;
}
else {
sym_set_bottom(ctx, sym);
}
return;
case JIT_SYM_KNOWN_CLASS_TAG:
if (sym->cls.type == Py_TYPE(value)) {
sym->tag = JIT_SYM_RECORDED_VALUE_TAG;
sym->recorded_value.known_type = true;
sym->recorded_value.value = value;
}
else {
sym_set_bottom(ctx, sym);
}
return;
case JIT_SYM_KNOWN_VALUE_TAG:
return;
case JIT_SYM_TYPE_VERSION_TAG:
if (sym->version.version == Py_TYPE(value)->tp_version_tag) {
sym->tag = JIT_SYM_RECORDED_VALUE_TAG;
sym->recorded_value.known_type = true;
sym->recorded_value.value = value;
}
else {
sym_set_bottom(ctx, sym);
}
return;
// In these cases the original information is more valuable
case JIT_SYM_RECORDED_GEN_FUNC_TAG:
case JIT_SYM_TUPLE_TAG:
case JIT_SYM_PREDICATE_TAG:
case JIT_SYM_TRUTHINESS_TAG:
case JIT_SYM_COMPACT_INT:
return;
}
Py_UNREACHABLE();
}
void
_Py_uop_sym_set_recorded_gen_func(JitOptContext *ctx, JitOptRef ref, PyFunctionObject *value)
{
// It is possible for value to be NULL due to respecialization
// during execution of the traced instruction.
if (value == NULL) {
return;
}
assert(!PyJitRef_IsNull(ref));
JitOptSymbol *sym = PyJitRef_Unwrap(ref);
JitSymType tag = sym->tag;
switch(tag) {
case JIT_SYM_NULL_TAG:
case JIT_SYM_RECORDED_VALUE_TAG:
case JIT_SYM_KNOWN_VALUE_TAG:
case JIT_SYM_TUPLE_TAG:
case JIT_SYM_PREDICATE_TAG:
case JIT_SYM_TRUTHINESS_TAG:
case JIT_SYM_COMPACT_INT:
sym_set_bottom(ctx, sym);
return;
case JIT_SYM_BOTTOM_TAG:
return;
case JIT_SYM_NON_NULL_TAG:
case JIT_SYM_UNKNOWN_TAG:
sym->tag = JIT_SYM_RECORDED_GEN_FUNC_TAG;
sym->recorded_gen_func.func = value;
return;
case JIT_SYM_RECORDED_TYPE_TAG:
if (sym->recorded_type.type == &PyGen_Type) {
sym->tag = JIT_SYM_RECORDED_GEN_FUNC_TAG;
sym->recorded_gen_func.func = value;
}
else {
sym_set_bottom(ctx, sym);
}
return;
case JIT_SYM_KNOWN_CLASS_TAG:
if (sym->cls.type == &PyGen_Type) {
sym->tag = JIT_SYM_RECORDED_GEN_FUNC_TAG;
sym->recorded_gen_func.func = value;
}
else {
sym_set_bottom(ctx, sym);
}
return;
case JIT_SYM_TYPE_VERSION_TAG:
if (sym->version.version == PyGen_Type.tp_version_tag) {
sym->tag = JIT_SYM_RECORDED_GEN_FUNC_TAG;
sym->recorded_gen_func.func = value;
}
else {
sym_set_bottom(ctx, sym);
}
return;
case JIT_SYM_RECORDED_GEN_FUNC_TAG:
if (sym->recorded_gen_func.func != value) {
sym_set_bottom(ctx, sym);
}
return;
}
Py_UNREACHABLE();
}
void
_Py_uop_sym_set_recorded_type(JitOptContext *ctx, JitOptRef ref, PyTypeObject *type)
{
// It is possible for type to be NULL due to respecialization
// during execution of the traced instruction.
if (type == NULL) {
return;
}
assert(PyType_Check((PyObject *)type));
JitOptSymbol *sym = PyJitRef_Unwrap(ref);
JitSymType tag = sym->tag;
switch(tag) {
case JIT_SYM_NULL_TAG:
sym_set_bottom(ctx, sym);
return;
case JIT_SYM_BOTTOM_TAG:
return;
case JIT_SYM_NON_NULL_TAG:
case JIT_SYM_UNKNOWN_TAG:
sym->tag = JIT_SYM_RECORDED_TYPE_TAG;
sym->recorded_type.type = type;
return;
case JIT_SYM_RECORDED_VALUE_TAG:
if (Py_TYPE(sym->recorded_value.value) != type) {
sym_set_bottom(ctx, sym);
}
return;
case JIT_SYM_RECORDED_TYPE_TAG:
if (sym->recorded_type.type != type) {
sym_set_bottom(ctx, sym);
}
return;
case JIT_SYM_KNOWN_CLASS_TAG:
return;
case JIT_SYM_KNOWN_VALUE_TAG:
return;
case JIT_SYM_TYPE_VERSION_TAG:
if (sym->version.version == type->tp_version_tag) {
sym->tag = JIT_SYM_KNOWN_CLASS_TAG;
sym->cls.type = type;
}
else {
sym_set_bottom(ctx, sym);
}
return;
// In these cases the original information is more valuable
case JIT_SYM_TUPLE_TAG:
case JIT_SYM_PREDICATE_TAG:
case JIT_SYM_TRUTHINESS_TAG:
case JIT_SYM_COMPACT_INT:
case JIT_SYM_RECORDED_GEN_FUNC_TAG:
return;
}
Py_UNREACHABLE();
}
// 0 on success, -1 on error.
_Py_UOpsAbstractFrame *
_Py_uop_frame_new_from_symbol(
JitOptContext *ctx,
JitOptRef callable,
int curr_stackentries,
JitOptRef *args,
int arg_len)
{
PyCodeObject *co = _Py_uop_sym_get_probable_func_code(callable);
if (co == NULL) {
ctx->done = true;
return NULL;
}
_Py_UOpsAbstractFrame *frame = _Py_uop_frame_new(ctx, co, curr_stackentries, args, arg_len);
if (frame == NULL) {
return NULL;
}
PyFunctionObject *func = _Py_uop_sym_get_probable_function(callable);
if (func != NULL) {
assert(PyFunction_Check(func));
frame->func = func;
}
assert(frame->stack_pointer != NULL);
return frame;
}
// 0 on success, -1 on error.
_Py_UOpsAbstractFrame *
_Py_uop_frame_new(
@ -950,6 +1315,7 @@ _Py_uop_frame_new(
JitOptRef *args,
int arg_len)
{
assert(co != NULL);
if (ctx->curr_frame_depth >= MAX_ABSTRACT_FRAME_DEPTH) {
ctx->done = true;
ctx->out_of_space = true;
@ -988,13 +1354,13 @@ _Py_uop_frame_new(
frame->locals[i] = local;
}
// Initialize the stack as well
for (int i = 0; i < curr_stackentries; i++) {
JitOptRef stackvar = _Py_uop_sym_new_unknown(ctx);
frame->stack[i] = stackvar;
}
assert(frame->locals != NULL);
return frame;
}
@ -1052,6 +1418,7 @@ _Py_uop_frame_pop(JitOptContext *ctx, PyCodeObject *co, int curr_stackentries)
if (ctx->curr_frame_depth >= 1) {
ctx->frame = &ctx->frames[ctx->curr_frame_depth - 1];
assert(ctx->frame->locals != NULL);
// We returned to the correct code. Nothing to do here.
if (co == ctx->frame->code) {
@ -1079,6 +1446,7 @@ _Py_uop_frame_pop(JitOptContext *ctx, PyCodeObject *co, int curr_stackentries)
ctx->curr_frame_depth++;
ctx->frame = new_frame;
assert(ctx->frame->locals != NULL);
return 0;
}
@ -1111,6 +1479,7 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
PyObject *val_43 = NULL;
PyObject *val_big = NULL;
PyObject *tuple = NULL;
PyFunctionObject *func = NULL;
// Use a single 'sym' variable so copy-pasting tests is easier.
JitOptRef ref = _Py_uop_sym_new_unknown(ctx);
@ -1521,11 +1890,118 @@ _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");
// Test recorded values
/* Test that recorded values aren't treated as known values*/
JitOptRef rv1 = _Py_uop_sym_new_unknown(ctx);
_Py_uop_sym_set_recorded_value(ctx, rv1, val_42);
TEST_PREDICATE(!_Py_uop_sym_matches_type(rv1, &PyLong_Type), "recorded value is treated as known");
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rv1) == NULL, "recorded value is treated as known");
TEST_PREDICATE(!_Py_uop_sym_is_compact_int(rv1), "recorded value is treated as known");
/* Test that setting type or value narrows correctly */
JitOptRef rv2 = _Py_uop_sym_new_unknown(ctx);
_Py_uop_sym_set_recorded_value(ctx, rv2, val_42);
_Py_uop_sym_set_const(ctx, rv2, val_42);
TEST_PREDICATE(_Py_uop_sym_matches_type(rv2, &PyLong_Type), "recorded value doesn't narrow");
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rv2) == val_42, "recorded value doesn't narrow");
JitOptRef rv3 = _Py_uop_sym_new_unknown(ctx);
_Py_uop_sym_set_recorded_value(ctx, rv3, val_42);
_Py_uop_sym_set_type(ctx, rv3, &PyLong_Type);
TEST_PREDICATE(_Py_uop_sym_matches_type(rv3, &PyLong_Type), "recorded value doesn't narrow");
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rv3) == NULL, "recorded value with type is treated as known");
JitOptRef rv4 = _Py_uop_sym_new_unknown(ctx);
_Py_uop_sym_set_recorded_value(ctx, rv4, val_42);
_Py_uop_sym_set_type_version(ctx, rv4, PyLong_Type.tp_version_tag);
TEST_PREDICATE(_Py_uop_sym_matches_type(rv4, &PyLong_Type), "recorded value doesn't narrow");
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rv4) == NULL, "recorded value with type is treated as known");
// test recorded types
/* Test that recorded type aren't treated as known values*/
JitOptRef rt1 = _Py_uop_sym_new_unknown(ctx);
_Py_uop_sym_set_recorded_type(ctx, rt1, &PyLong_Type);
TEST_PREDICATE(!_Py_uop_sym_matches_type(rt1, &PyLong_Type), "recorded type is treated as known");
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rt1) == NULL, "recorded type is treated as known value");
/* Test that setting type or value narrows correctly */
JitOptRef rt2 = _Py_uop_sym_new_unknown(ctx);
_Py_uop_sym_set_recorded_type(ctx, rt2, &PyLong_Type);
_Py_uop_sym_set_const(ctx, rt2, val_42);
TEST_PREDICATE(_Py_uop_sym_matches_type(rt2, &PyLong_Type), "recorded value doesn't narrow");
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rt2) == val_42, "recorded value doesn't narrow");
JitOptRef rt3 = _Py_uop_sym_new_unknown(ctx);
_Py_uop_sym_set_recorded_type(ctx, rt3, &PyLong_Type);
_Py_uop_sym_set_type(ctx, rt3, &PyLong_Type);
TEST_PREDICATE(_Py_uop_sym_matches_type(rt3, &PyLong_Type), "recorded value doesn't narrow");
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rt3) == NULL, "known type is treated as known value");
JitOptRef rt4 = _Py_uop_sym_new_unknown(ctx);
_Py_uop_sym_set_recorded_type(ctx, rt4, &PyLong_Type);
_Py_uop_sym_set_type_version(ctx, rt4, PyLong_Type.tp_version_tag);
TEST_PREDICATE(_Py_uop_sym_matches_type(rt4, &PyLong_Type), "recorded value doesn't narrow");
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rt4) == NULL, "recorded value with type is treated as known");
// test recorded gen function
PyObject *dict = PyDict_New();
if (dict == NULL) {
goto fail;
}
PyCodeObject *code = PyCode_NewEmpty(__FILE__, "uop_symbols_test", __LINE__);
if (code == NULL) {
goto fail;
}
func = (PyFunctionObject *)PyFunction_New((PyObject *)code, dict);
if (func == NULL) {
goto fail;
}
/* Test that recorded type aren't treated as known values*/
JitOptRef rg1 = _Py_uop_sym_new_unknown(ctx);
_Py_uop_sym_set_recorded_gen_func(ctx, rg1, func);
TEST_PREDICATE(_Py_uop_sym_matches_type(rg1, &PyGen_Type), "recorded gen func not treated as generator");
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rg1) == NULL, "recorded gen func is treated as known value");
/* Test that setting type narrows correctly */
JitOptRef rg2 = _Py_uop_sym_new_unknown(ctx);
_Py_uop_sym_set_recorded_gen_func(ctx, rg2, func);
_Py_uop_sym_set_type(ctx, rg2, &PyGen_Type);
TEST_PREDICATE(_Py_uop_sym_matches_type(rg1, &PyGen_Type), "recorded gen func not treated as generator");
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rg2) == NULL, "known type is treated as known value");
JitOptRef rg3 = _Py_uop_sym_new_unknown(ctx);
_Py_uop_sym_set_recorded_gen_func(ctx, rg3, func);
_Py_uop_sym_set_type_version(ctx, rg3, PyGen_Type.tp_version_tag);
TEST_PREDICATE(_Py_uop_sym_matches_type(rg1, &PyGen_Type), "recorded gen func not treated as generator");
TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rg3) == NULL, "recorded value with type is treated as known");
/* Test contradictions */
_Py_uop_sym_set_type(ctx, rv1, &PyFloat_Type);
TEST_PREDICATE(_Py_uop_sym_is_bottom(rv1), "recorded value cast to other type isn't bottom");
_Py_uop_sym_set_type_version(ctx, rv2, PyFloat_Type.tp_version_tag);
TEST_PREDICATE(_Py_uop_sym_is_bottom(rv2), "recorded value cast to other type version isn't bottom");
_Py_uop_sym_set_type(ctx, rt1, &PyFloat_Type);
TEST_PREDICATE(_Py_uop_sym_is_bottom(rv1), "recorded type cast to other type isn't bottom");
_Py_uop_sym_set_type_version(ctx, rt2, PyFloat_Type.tp_version_tag);
TEST_PREDICATE(_Py_uop_sym_is_bottom(rv2), "recorded type cast to other type version isn't bottom");
_Py_uop_sym_set_type(ctx, rg1, &PyFloat_Type);
TEST_PREDICATE(_Py_uop_sym_is_bottom(rg1), "recorded gen func cast to other type isn't bottom");
_Py_uop_sym_set_type_version(ctx, rg2, PyFloat_Type.tp_version_tag);
TEST_PREDICATE(_Py_uop_sym_is_bottom(rg2), "recorded gen func cast to other type version isn't bottom");
_Py_uop_abstractcontext_fini(ctx);
Py_DECREF(val_42);
Py_DECREF(val_43);
Py_DECREF(val_big);
Py_DECREF(tuple);
Py_DECREF(func);
Py_RETURN_NONE;
fail:
@ -1533,7 +2009,8 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
Py_XDECREF(val_42);
Py_XDECREF(val_43);
Py_XDECREF(val_big);
Py_DECREF(tuple);
Py_XDECREF(tuple);
Py_XDECREF(func);
return NULL;
}

View file

@ -27,6 +27,19 @@ void _PyOpcode_RecordFunction_NOS(_PyInterpreterFrame *frame, _PyStackRef *stack
Py_INCREF(*recorded_value);
}
void _PyOpcode_RecordFunction_NOS_GEN_FUNC(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, int oparg, PyObject **recorded_value) {
_PyStackRef nos;
nos = stack_pointer[-2];
PyObject *obj = PyStackRef_AsPyObjectBorrow(nos);
if (PyGen_Check(obj)) {
_PyFrame_SetStackPointer(frame, stack_pointer);
PyObject *func = (PyObject *)_PyFrame_GetFunction(&((PyGenObject *)obj)->gi_iframe);
stack_pointer = _PyFrame_GetStackPointer(frame);
*recorded_value = (PyObject *)func;
Py_INCREF(*recorded_value);
}
}
void _PyOpcode_RecordFunction_4OS(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, int oparg, PyObject **recorded_value) {
_PyStackRef value;
value = stack_pointer[-4];
@ -52,27 +65,21 @@ void _PyOpcode_RecordFunction_BOUND_METHOD(_PyInterpreterFrame *frame, _PyStackR
}
}
void _PyOpcode_RecordFunction_CALLER_CODE(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, int oparg, PyObject **recorded_value) {
_PyInterpreterFrame *caller_frame = frame->previous;
if (caller_frame->owner < FRAME_OWNED_BY_INTERPRETER) {
PyCodeObject *code = _PyFrame_GetCode(frame->previous);
*recorded_value = (PyObject *)code;
Py_INCREF(*recorded_value);
}
void _PyOpcode_RecordFunction_CODE(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, int oparg, PyObject **recorded_value) {
*recorded_value = (PyObject *)NULL;
Py_INCREF(*recorded_value);
}
#define _RECORD_TOS_TYPE_INDEX 1
#define _RECORD_TOS_INDEX 2
#define _RECORD_CALLER_CODE_INDEX 3
#define _RECORD_NOS_INDEX 4
#define _RECORD_CALLABLE_INDEX 5
#define _RECORD_BOUND_METHOD_INDEX 6
#define _RECORD_4OS_INDEX 7
#define _RECORD_NOS_INDEX 2
#define _RECORD_NOS_GEN_FUNC_INDEX 3
#define _RECORD_CALLABLE_INDEX 4
#define _RECORD_BOUND_METHOD_INDEX 5
#define _RECORD_4OS_INDEX 6
const uint8_t _PyOpcode_RecordFunctionIndices[256] = {
[TO_BOOL_ALWAYS_TRUE] = _RECORD_TOS_TYPE_INDEX,
[BINARY_OP_SUBSCR_GETITEM] = _RECORD_TOS_INDEX,
[RETURN_VALUE] = _RECORD_CALLER_CODE_INDEX,
[YIELD_VALUE] = _RECORD_CALLER_CODE_INDEX,
[BINARY_OP_SUBSCR_GETITEM] = _RECORD_NOS_INDEX,
[SEND_GEN] = _RECORD_NOS_GEN_FUNC_INDEX,
[LOAD_ATTR_INSTANCE_VALUE] = _RECORD_TOS_TYPE_INDEX,
[LOAD_ATTR_WITH_HINT] = _RECORD_TOS_TYPE_INDEX,
[LOAD_ATTR_SLOT] = _RECORD_TOS_TYPE_INDEX,
@ -80,7 +87,7 @@ const uint8_t _PyOpcode_RecordFunctionIndices[256] = {
[LOAD_ATTR_PROPERTY] = _RECORD_TOS_TYPE_INDEX,
[STORE_ATTR_WITH_HINT] = _RECORD_TOS_TYPE_INDEX,
[STORE_ATTR_SLOT] = _RECORD_TOS_TYPE_INDEX,
[FOR_ITER_GEN] = _RECORD_NOS_INDEX,
[FOR_ITER_GEN] = _RECORD_NOS_GEN_FUNC_INDEX,
[LOAD_ATTR_METHOD_WITH_VALUES] = _RECORD_TOS_TYPE_INDEX,
[LOAD_ATTR_METHOD_NO_DICT] = _RECORD_TOS_TYPE_INDEX,
[LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = _RECORD_TOS_TYPE_INDEX,
@ -100,15 +107,13 @@ const uint8_t _PyOpcode_RecordFunctionIndices[256] = {
[CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = _RECORD_CALLABLE_INDEX,
[CALL_METHOD_DESCRIPTOR_NOARGS] = _RECORD_CALLABLE_INDEX,
[CALL_EX_PY] = _RECORD_4OS_INDEX,
[RETURN_GENERATOR] = _RECORD_CALLER_CODE_INDEX,
};
const _Py_RecordFuncPtr _PyOpcode_RecordFunctions[8] = {
const _Py_RecordFuncPtr _PyOpcode_RecordFunctions[7] = {
[0] = NULL,
[_RECORD_TOS_TYPE_INDEX] = _PyOpcode_RecordFunction_TOS_TYPE,
[_RECORD_TOS_INDEX] = _PyOpcode_RecordFunction_TOS,
[_RECORD_CALLER_CODE_INDEX] = _PyOpcode_RecordFunction_CALLER_CODE,
[_RECORD_NOS_INDEX] = _PyOpcode_RecordFunction_NOS,
[_RECORD_NOS_GEN_FUNC_INDEX] = _PyOpcode_RecordFunction_NOS_GEN_FUNC,
[_RECORD_CALLABLE_INDEX] = _PyOpcode_RecordFunction_CALLABLE,
[_RECORD_BOUND_METHOD_INDEX] = _PyOpcode_RecordFunction_BOUND_METHOD,
[_RECORD_4OS_INDEX] = _PyOpcode_RecordFunction_4OS,