From 5b38288fcd08a8fc5c1a1503577e20d37cfb10f7 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 27 Jan 2023 23:48:06 +0800 Subject: [PATCH 001/280] Generate the tier 2 interpreter --- Python/bytecodes.c | 10 +- Python/generated_cases.c.h | 30 +- Python/generated_cases_tier2.c.h | 3713 +++++++++++++++++++++++ Python/opcode_metadata_tier2.h | 883 ++++++ Tools/cases_generator/generate_cases.py | 94 +- Tools/cases_generator/parser.py | 28 +- 6 files changed, 4727 insertions(+), 31 deletions(-) create mode 100644 Python/generated_cases_tier2.c.h create mode 100644 Python/opcode_metadata_tier2.h diff --git a/Python/bytecodes.c b/Python/bytecodes.c index e5769f61fc28d0..d8532fc0d0c3b4 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -284,10 +284,13 @@ dummy_func( ERROR_IF(sum == NULL, error); } - inst(BINARY_OP_ADD_INT, (unused/1, left, right -- sum)) { + u_inst(BINARY_OP_ADD_INT_TYPE_CHECK, (unused / 1, left, right -- left, right)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); + } + + u_inst(BINARY_OP_ADD_INST_REST, (unused / 1, left, right -- sum)) { STAT_INC(BINARY_OP, hit); sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -295,6 +298,11 @@ dummy_func( ERROR_IF(sum == NULL, error); } + macro_inst(BINARY_OP_ADD_INT, (unused/1, left, right -- sum)) { + BINARY_OP_ADD_INT_TYPE_CHECK(); + BINARY_OP_ADD_INST_REST(); + } + family(binary_subscr, INLINE_CACHE_ENTRIES_BINARY_SUBSCR) = { BINARY_SUBSCR, BINARY_SUBSCR_DICT, diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 287a1f1f042089..c3b455177e33e3 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1,7 +1,23 @@ -// This file is generated by Tools/cases_generator/generate_cases.py -// from Python/bytecodes.c +// This file is generated by Tools\cases_generator\generate_cases.py +// from Python\bytecodes.c // Do not edit! + #define BINARY_OP_ADD_INT_TYPE_CHECK() \ + do { \ + assert(cframe.use_tracing == 0);\ + DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);\ + DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);\ + } while (0) + + #define BINARY_OP_ADD_INST_REST() \ + do { \ + STAT_INC(BINARY_OP, hit);\ + sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right);\ + _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);\ + _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);\ + if (sum == NULL) goto pop_2_error;\ + } while (0) + TARGET(NOP) { DISPATCH(); } @@ -390,14 +406,8 @@ PyObject *right = PEEK(1); PyObject *left = PEEK(2); PyObject *sum; - assert(cframe.use_tracing == 0); - DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); - DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); - STAT_INC(BINARY_OP, hit); - sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); - _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - if (sum == NULL) goto pop_2_error; + BINARY_OP_ADD_INT_TYPE_CHECK(); + BINARY_OP_ADD_INST_REST(); STACK_SHRINK(1); POKE(1, sum); JUMPBY(1); diff --git a/Python/generated_cases_tier2.c.h b/Python/generated_cases_tier2.c.h new file mode 100644 index 00000000000000..91f4265c139aad --- /dev/null +++ b/Python/generated_cases_tier2.c.h @@ -0,0 +1,3713 @@ +// This file is generated by Tools\cases_generator\generate_cases.py +// from Python\bytecodes.c +// Do not edit! + + TARGET(NOP) { + DISPATCH(); + } + + TARGET(RESUME) { + assert(tstate->cframe == &cframe); + assert(frame == cframe.current_frame); + if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { + goto handle_eval_breaker; + } + DISPATCH(); + } + + TARGET(LOAD_CLOSURE) { + PyObject *value; + /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ + value = GETLOCAL(oparg); + if (value == NULL) goto unbound_local_error; + Py_INCREF(value); + STACK_GROW(1); + POKE(1, value); + DISPATCH(); + } + + TARGET(LOAD_FAST_CHECK) { + PyObject *value; + value = GETLOCAL(oparg); + if (value == NULL) goto unbound_local_error; + Py_INCREF(value); + STACK_GROW(1); + POKE(1, value); + DISPATCH(); + } + + TARGET(LOAD_FAST) { + PyObject *value; + value = GETLOCAL(oparg); + assert(value != NULL); + Py_INCREF(value); + STACK_GROW(1); + POKE(1, value); + DISPATCH(); + } + + TARGET(LOAD_CONST) { + PREDICTED(LOAD_CONST); + PyObject *value; + value = GETITEM(consts, oparg); + Py_INCREF(value); + STACK_GROW(1); + POKE(1, value); + DISPATCH(); + } + + TARGET(STORE_FAST) { + PyObject *value = PEEK(1); + SETLOCAL(oparg, value); + STACK_SHRINK(1); + DISPATCH(); + } + + TARGET(LOAD_FAST__LOAD_FAST) { + PyObject *_tmp_1; + PyObject *_tmp_2; + { + PyObject *value; + value = GETLOCAL(oparg); + assert(value != NULL); + Py_INCREF(value); + _tmp_2 = value; + } + NEXTOPARG(); + JUMPBY(1); + { + PyObject *value; + value = GETLOCAL(oparg); + assert(value != NULL); + Py_INCREF(value); + _tmp_1 = value; + } + STACK_GROW(2); + POKE(1, _tmp_1); + POKE(2, _tmp_2); + DISPATCH(); + } + + TARGET(LOAD_FAST__LOAD_CONST) { + PyObject *_tmp_1; + PyObject *_tmp_2; + { + PyObject *value; + value = GETLOCAL(oparg); + assert(value != NULL); + Py_INCREF(value); + _tmp_2 = value; + } + NEXTOPARG(); + JUMPBY(1); + { + PyObject *value; + value = GETITEM(consts, oparg); + Py_INCREF(value); + _tmp_1 = value; + } + STACK_GROW(2); + POKE(1, _tmp_1); + POKE(2, _tmp_2); + DISPATCH(); + } + + TARGET(STORE_FAST__LOAD_FAST) { + PyObject *_tmp_1 = PEEK(1); + { + PyObject *value = _tmp_1; + SETLOCAL(oparg, value); + } + NEXTOPARG(); + JUMPBY(1); + { + PyObject *value; + value = GETLOCAL(oparg); + assert(value != NULL); + Py_INCREF(value); + _tmp_1 = value; + } + POKE(1, _tmp_1); + DISPATCH(); + } + + TARGET(STORE_FAST__STORE_FAST) { + PyObject *_tmp_1 = PEEK(1); + PyObject *_tmp_2 = PEEK(2); + { + PyObject *value = _tmp_1; + SETLOCAL(oparg, value); + } + NEXTOPARG(); + JUMPBY(1); + { + PyObject *value = _tmp_2; + SETLOCAL(oparg, value); + } + STACK_SHRINK(2); + DISPATCH(); + } + + TARGET(LOAD_CONST__LOAD_FAST) { + PyObject *_tmp_1; + PyObject *_tmp_2; + { + PyObject *value; + value = GETITEM(consts, oparg); + Py_INCREF(value); + _tmp_2 = value; + } + NEXTOPARG(); + JUMPBY(1); + { + PyObject *value; + value = GETLOCAL(oparg); + assert(value != NULL); + Py_INCREF(value); + _tmp_1 = value; + } + STACK_GROW(2); + POKE(1, _tmp_1); + POKE(2, _tmp_2); + DISPATCH(); + } + + TARGET(POP_TOP) { + PyObject *value = PEEK(1); + Py_DECREF(value); + STACK_SHRINK(1); + DISPATCH(); + } + + TARGET(PUSH_NULL) { + PyObject *res; + res = NULL; + STACK_GROW(1); + POKE(1, res); + DISPATCH(); + } + + TARGET(END_FOR) { + PyObject *_tmp_1 = PEEK(1); + PyObject *_tmp_2 = PEEK(2); + { + PyObject *value = _tmp_1; + Py_DECREF(value); + } + { + PyObject *value = _tmp_2; + Py_DECREF(value); + } + STACK_SHRINK(2); + DISPATCH(); + } + + TARGET(UNARY_NEGATIVE) { + PyObject *value = PEEK(1); + PyObject *res; + res = PyNumber_Negative(value); + Py_DECREF(value); + if (res == NULL) goto pop_1_error; + POKE(1, res); + DISPATCH(); + } + + TARGET(UNARY_NOT) { + PyObject *value = PEEK(1); + PyObject *res; + int err = PyObject_IsTrue(value); + Py_DECREF(value); + if (err < 0) goto pop_1_error; + if (err == 0) { + res = Py_True; + } + else { + res = Py_False; + } + Py_INCREF(res); + POKE(1, res); + DISPATCH(); + } + + TARGET(UNARY_INVERT) { + PyObject *value = PEEK(1); + PyObject *res; + res = PyNumber_Invert(value); + Py_DECREF(value); + if (res == NULL) goto pop_1_error; + POKE(1, res); + DISPATCH(); + } + + TARGET(BINARY_OP_MULTIPLY_INT) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + PyObject *prod; + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); + DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); + STAT_INC(BINARY_OP, hit); + prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); + _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); + _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); + if (prod == NULL) goto pop_2_error; + STACK_SHRINK(1); + POKE(1, prod); + JUMPBY(1); + DISPATCH(); + } + + TARGET(BINARY_OP_MULTIPLY_FLOAT) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + PyObject *prod; + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); + DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); + STAT_INC(BINARY_OP, hit); + double dprod = ((PyFloatObject *)left)->ob_fval * + ((PyFloatObject *)right)->ob_fval; + prod = PyFloat_FromDouble(dprod); + _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); + _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); + if (prod == NULL) goto pop_2_error; + STACK_SHRINK(1); + POKE(1, prod); + JUMPBY(1); + DISPATCH(); + } + + TARGET(BINARY_OP_SUBTRACT_INT) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + PyObject *sub; + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); + DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); + STAT_INC(BINARY_OP, hit); + sub = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); + _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); + _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); + if (sub == NULL) goto pop_2_error; + STACK_SHRINK(1); + POKE(1, sub); + JUMPBY(1); + DISPATCH(); + } + + TARGET(BINARY_OP_SUBTRACT_FLOAT) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + PyObject *sub; + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); + DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); + STAT_INC(BINARY_OP, hit); + double dsub = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; + sub = PyFloat_FromDouble(dsub); + _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); + _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); + if (sub == NULL) goto pop_2_error; + STACK_SHRINK(1); + POKE(1, sub); + JUMPBY(1); + DISPATCH(); + } + + TARGET(BINARY_OP_ADD_UNICODE) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + PyObject *res; + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); + DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); + STAT_INC(BINARY_OP, hit); + res = PyUnicode_Concat(left, right); + _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); + _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); + if (res == NULL) goto pop_2_error; + STACK_SHRINK(1); + POKE(1, res); + JUMPBY(1); + DISPATCH(); + } + + TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); + DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); + _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP]; + assert(_Py_OPCODE(true_next) == STORE_FAST || + _Py_OPCODE(true_next) == STORE_FAST__LOAD_FAST); + PyObject **target_local = &GETLOCAL(_Py_OPARG(true_next)); + DEOPT_IF(*target_local != left, BINARY_OP); + STAT_INC(BINARY_OP, hit); + /* Handle `left = left + right` or `left += right` for str. + * + * When possible, extend `left` in place rather than + * allocating a new PyUnicodeObject. This attempts to avoid + * quadratic behavior when one neglects to use str.join(). + * + * If `left` has only two references remaining (one from + * the stack, one in the locals), DECREFing `left` leaves + * only the locals reference, so PyUnicode_Append knows + * that the string is safe to mutate. + */ + assert(Py_REFCNT(left) >= 2); + _Py_DECREF_NO_DEALLOC(left); + PyUnicode_Append(target_local, right); + _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); + if (*target_local == NULL) goto pop_2_error; + // The STORE_FAST is already done. + JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); + STACK_SHRINK(2); + DISPATCH(); + } + + TARGET(BINARY_OP_ADD_FLOAT) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + PyObject *sum; + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); + DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); + STAT_INC(BINARY_OP, hit); + double dsum = ((PyFloatObject *)left)->ob_fval + + ((PyFloatObject *)right)->ob_fval; + sum = PyFloat_FromDouble(dsum); + _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); + _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); + if (sum == NULL) goto pop_2_error; + STACK_SHRINK(1); + POKE(1, sum); + JUMPBY(1); + DISPATCH(); + } + + TARGET(BINARY_OP_ADD_INT_TYPE_CHECK) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); + DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); + JUMPBY(1); + DISPATCH(); + } + + TARGET(BINARY_OP_ADD_INST_REST) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + PyObject *sum; + STAT_INC(BINARY_OP, hit); + sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); + _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); + _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); + if (sum == NULL) goto pop_2_error; + STACK_SHRINK(1); + POKE(1, sum); + JUMPBY(1); + DISPATCH(); + } + + TARGET(BINARY_SUBSCR) { + PREDICTED(BINARY_SUBSCR); + static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 4, "incorrect cache size"); + PyObject *sub = PEEK(1); + PyObject *container = PEEK(2); + PyObject *res; + #if ENABLE_SPECIALIZATION + _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + assert(cframe.use_tracing == 0); + next_instr--; + _Py_Specialize_BinarySubscr(container, sub, next_instr); + DISPATCH_SAME_OPARG(); + } + STAT_INC(BINARY_SUBSCR, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ + res = PyObject_GetItem(container, sub); + Py_DECREF(container); + Py_DECREF(sub); + if (res == NULL) goto pop_2_error; + STACK_SHRINK(1); + POKE(1, res); + JUMPBY(4); + DISPATCH(); + } + + TARGET(BINARY_SLICE) { + PyObject *stop = PEEK(1); + PyObject *start = PEEK(2); + PyObject *container = PEEK(3); + PyObject *res; + PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); + // Can't use ERROR_IF() here, because we haven't + // DECREF'ed container yet, and we still own slice. + if (slice == NULL) { + res = NULL; + } + else { + res = PyObject_GetItem(container, slice); + Py_DECREF(slice); + } + Py_DECREF(container); + if (res == NULL) goto pop_3_error; + STACK_SHRINK(2); + POKE(1, res); + DISPATCH(); + } + + TARGET(STORE_SLICE) { + PyObject *stop = PEEK(1); + PyObject *start = PEEK(2); + PyObject *container = PEEK(3); + PyObject *v = PEEK(4); + PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); + int err; + if (slice == NULL) { + err = 1; + } + else { + err = PyObject_SetItem(container, slice, v); + Py_DECREF(slice); + } + Py_DECREF(v); + Py_DECREF(container); + if (err) goto pop_4_error; + STACK_SHRINK(4); + DISPATCH(); + } + + TARGET(BINARY_SUBSCR_LIST_INT) { + PyObject *sub = PEEK(1); + PyObject *list = PEEK(2); + PyObject *res; + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); + DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); + + // Deopt unless 0 <= sub < PyList_Size(list) + DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); + assert(((PyLongObject *)_PyLong_GetZero())->ob_digit[0] == 0); + Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0]; + DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); + STAT_INC(BINARY_SUBSCR, hit); + res = PyList_GET_ITEM(list, index); + assert(res != NULL); + Py_INCREF(res); + _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + Py_DECREF(list); + STACK_SHRINK(1); + POKE(1, res); + JUMPBY(4); + DISPATCH(); + } + + TARGET(BINARY_SUBSCR_TUPLE_INT) { + PyObject *sub = PEEK(1); + PyObject *tuple = PEEK(2); + PyObject *res; + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); + DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); + + // Deopt unless 0 <= sub < PyTuple_Size(list) + DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); + assert(((PyLongObject *)_PyLong_GetZero())->ob_digit[0] == 0); + Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0]; + DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); + STAT_INC(BINARY_SUBSCR, hit); + res = PyTuple_GET_ITEM(tuple, index); + assert(res != NULL); + Py_INCREF(res); + _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + Py_DECREF(tuple); + STACK_SHRINK(1); + POKE(1, res); + JUMPBY(4); + DISPATCH(); + } + + TARGET(BINARY_SUBSCR_DICT) { + PyObject *sub = PEEK(1); + PyObject *dict = PEEK(2); + PyObject *res; + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); + STAT_INC(BINARY_SUBSCR, hit); + res = PyDict_GetItemWithError(dict, sub); + if (res == NULL) { + if (!_PyErr_Occurred(tstate)) { + _PyErr_SetKeyError(sub); + } + Py_DECREF(dict); + Py_DECREF(sub); + if (true) goto pop_2_error; + } + Py_INCREF(res); // Do this before DECREF'ing dict, sub + Py_DECREF(dict); + Py_DECREF(sub); + STACK_SHRINK(1); + POKE(1, res); + JUMPBY(4); + DISPATCH(); + } + + TARGET(BINARY_SUBSCR_GETITEM) { + PyObject *sub = PEEK(1); + PyObject *container = PEEK(2); + uint32_t type_version = read_u32(&next_instr[1].cache); + uint16_t func_version = read_u16(&next_instr[3].cache); + PyTypeObject *tp = Py_TYPE(container); + DEOPT_IF(tp->tp_version_tag != type_version, BINARY_SUBSCR); + assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE); + PyObject *cached = ((PyHeapTypeObject *)tp)->_spec_cache.getitem; + assert(PyFunction_Check(cached)); + PyFunctionObject *getitem = (PyFunctionObject *)cached; + DEOPT_IF(getitem->func_version != func_version, BINARY_SUBSCR); + PyCodeObject *code = (PyCodeObject *)getitem->func_code; + assert(code->co_argcount == 2); + DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), BINARY_SUBSCR); + STAT_INC(BINARY_SUBSCR, hit); + Py_INCREF(getitem); + _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, getitem, 2); + STACK_SHRINK(2); + new_frame->localsplus[0] = container; + new_frame->localsplus[1] = sub; + JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); + DISPATCH_INLINED(new_frame); + } + + TARGET(LIST_APPEND) { + PyObject *v = PEEK(1); + PyObject *list = PEEK(2 + (oparg-1)); + if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; + STACK_SHRINK(1); + PREDICT(JUMP_BACKWARD); + DISPATCH(); + } + + TARGET(SET_ADD) { + PyObject *v = PEEK(1); + PyObject *set = PEEK(2 + (oparg-1)); + int err = PySet_Add(set, v); + Py_DECREF(v); + if (err) goto pop_1_error; + STACK_SHRINK(1); + PREDICT(JUMP_BACKWARD); + DISPATCH(); + } + + TARGET(STORE_SUBSCR) { + PREDICTED(STORE_SUBSCR); + PyObject *sub = PEEK(1); + PyObject *container = PEEK(2); + PyObject *v = PEEK(3); + uint16_t counter = read_u16(&next_instr[0].cache); + #if ENABLE_SPECIALIZATION + if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { + assert(cframe.use_tracing == 0); + next_instr--; + _Py_Specialize_StoreSubscr(container, sub, next_instr); + DISPATCH_SAME_OPARG(); + } + STAT_INC(STORE_SUBSCR, deferred); + _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr; + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #else + (void)counter; // Unused. + #endif /* ENABLE_SPECIALIZATION */ + /* container[sub] = v */ + int err = PyObject_SetItem(container, sub, v); + Py_DECREF(v); + Py_DECREF(container); + Py_DECREF(sub); + if (err) goto pop_3_error; + STACK_SHRINK(3); + JUMPBY(1); + DISPATCH(); + } + + TARGET(STORE_SUBSCR_LIST_INT) { + PyObject *sub = PEEK(1); + PyObject *list = PEEK(2); + PyObject *value = PEEK(3); + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); + DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); + + // Ensure nonnegative, zero-or-one-digit ints. + DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), STORE_SUBSCR); + Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0]; + // Ensure index < len(list) + DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); + STAT_INC(STORE_SUBSCR, hit); + + PyObject *old_value = PyList_GET_ITEM(list, index); + PyList_SET_ITEM(list, index, value); + assert(old_value != NULL); + Py_DECREF(old_value); + _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); + Py_DECREF(list); + STACK_SHRINK(3); + JUMPBY(1); + DISPATCH(); + } + + TARGET(STORE_SUBSCR_DICT) { + PyObject *sub = PEEK(1); + PyObject *dict = PEEK(2); + PyObject *value = PEEK(3); + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); + STAT_INC(STORE_SUBSCR, hit); + int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); + Py_DECREF(dict); + if (err) goto pop_3_error; + STACK_SHRINK(3); + JUMPBY(1); + DISPATCH(); + } + + TARGET(DELETE_SUBSCR) { + PyObject *sub = PEEK(1); + PyObject *container = PEEK(2); + /* del container[sub] */ + int err = PyObject_DelItem(container, sub); + Py_DECREF(container); + Py_DECREF(sub); + if (err) goto pop_2_error; + STACK_SHRINK(2); + DISPATCH(); + } + + TARGET(CALL_INTRINSIC_1) { + PyObject *value = PEEK(1); + PyObject *res; + assert(oparg <= MAX_INTRINSIC_1); + res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); + Py_DECREF(value); + if (res == NULL) goto pop_1_error; + POKE(1, res); + DISPATCH(); + } + + TARGET(RAISE_VARARGS) { + PyObject **args = &PEEK(oparg); + PyObject *cause = NULL, *exc = NULL; + switch (oparg) { + case 2: + cause = args[1]; + /* fall through */ + case 1: + exc = args[0]; + /* fall through */ + case 0: + if (do_raise(tstate, exc, cause)) { STACK_SHRINK(oparg); goto exception_unwind; } + break; + default: + _PyErr_SetString(tstate, PyExc_SystemError, + "bad RAISE_VARARGS oparg"); + break; + } + if (true) { STACK_SHRINK(oparg); goto error; } + } + + TARGET(INTERPRETER_EXIT) { + PyObject *retval = PEEK(1); + assert(frame == &entry_frame); + assert(_PyFrame_IsIncomplete(frame)); + STACK_SHRINK(1); // Since we're not going to DISPATCH() + assert(EMPTY()); + /* Restore previous cframe and return. */ + tstate->cframe = cframe.previous; + tstate->cframe->use_tracing = cframe.use_tracing; + assert(tstate->cframe->current_frame == frame->previous); + assert(!_PyErr_Occurred(tstate)); + _Py_LeaveRecursiveCallTstate(tstate); + return retval; + } + + TARGET(RETURN_VALUE) { + PyObject *retval = PEEK(1); + STACK_SHRINK(1); + assert(EMPTY()); + _PyFrame_SetStackPointer(frame, stack_pointer); + TRACE_FUNCTION_EXIT(); + DTRACE_FUNCTION_EXIT(); + _Py_LeaveRecursiveCallPy(tstate); + assert(frame != &entry_frame); + // GH-99729: We need to unlink the frame *before* clearing it: + _PyInterpreterFrame *dying = frame; + frame = cframe.current_frame = dying->previous; + _PyEvalFrameClearAndPop(tstate, dying); + _PyFrame_StackPush(frame, retval); + goto resume_frame; + } + + TARGET(GET_AITER) { + PyObject *obj = PEEK(1); + PyObject *iter; + unaryfunc getter = NULL; + PyTypeObject *type = Py_TYPE(obj); + + if (type->tp_as_async != NULL) { + getter = type->tp_as_async->am_aiter; + } + + if (getter == NULL) { + _PyErr_Format(tstate, PyExc_TypeError, + "'async for' requires an object with " + "__aiter__ method, got %.100s", + type->tp_name); + Py_DECREF(obj); + if (true) goto pop_1_error; + } + + iter = (*getter)(obj); + Py_DECREF(obj); + if (iter == NULL) goto pop_1_error; + + if (Py_TYPE(iter)->tp_as_async == NULL || + Py_TYPE(iter)->tp_as_async->am_anext == NULL) { + + _PyErr_Format(tstate, PyExc_TypeError, + "'async for' received an object from __aiter__ " + "that does not implement __anext__: %.100s", + Py_TYPE(iter)->tp_name); + Py_DECREF(iter); + if (true) goto pop_1_error; + } + POKE(1, iter); + DISPATCH(); + } + + TARGET(GET_ANEXT) { + PyObject *aiter = PEEK(1); + PyObject *awaitable; + unaryfunc getter = NULL; + PyObject *next_iter = NULL; + PyTypeObject *type = Py_TYPE(aiter); + + if (PyAsyncGen_CheckExact(aiter)) { + awaitable = type->tp_as_async->am_anext(aiter); + if (awaitable == NULL) { + goto error; + } + } else { + if (type->tp_as_async != NULL){ + getter = type->tp_as_async->am_anext; + } + + if (getter != NULL) { + next_iter = (*getter)(aiter); + if (next_iter == NULL) { + goto error; + } + } + else { + _PyErr_Format(tstate, PyExc_TypeError, + "'async for' requires an iterator with " + "__anext__ method, got %.100s", + type->tp_name); + goto error; + } + + awaitable = _PyCoro_GetAwaitableIter(next_iter); + if (awaitable == NULL) { + _PyErr_FormatFromCause( + PyExc_TypeError, + "'async for' received an invalid object " + "from __anext__: %.100s", + Py_TYPE(next_iter)->tp_name); + + Py_DECREF(next_iter); + goto error; + } else { + Py_DECREF(next_iter); + } + } + + STACK_GROW(1); + POKE(1, awaitable); + PREDICT(LOAD_CONST); + DISPATCH(); + } + + TARGET(GET_AWAITABLE) { + PREDICTED(GET_AWAITABLE); + PyObject *iterable = PEEK(1); + PyObject *iter; + iter = _PyCoro_GetAwaitableIter(iterable); + + if (iter == NULL) { + format_awaitable_error(tstate, Py_TYPE(iterable), oparg); + } + + Py_DECREF(iterable); + + if (iter != NULL && PyCoro_CheckExact(iter)) { + PyObject *yf = _PyGen_yf((PyGenObject*)iter); + if (yf != NULL) { + /* `iter` is a coroutine object that is being + awaited, `yf` is a pointer to the current awaitable + being awaited on. */ + Py_DECREF(yf); + Py_CLEAR(iter); + _PyErr_SetString(tstate, PyExc_RuntimeError, + "coroutine is being awaited already"); + /* The code below jumps to `error` if `iter` is NULL. */ + } + } + + if (iter == NULL) goto pop_1_error; + + POKE(1, iter); + PREDICT(LOAD_CONST); + DISPATCH(); + } + + TARGET(SEND) { + assert(frame != &entry_frame); + assert(STACK_LEVEL() >= 2); + PyObject *v = POP(); + PyObject *receiver = TOP(); + PySendResult gen_status; + PyObject *retval; + if (tstate->c_tracefunc == NULL) { + gen_status = PyIter_Send(receiver, v, &retval); + } else { + if (Py_IsNone(v) && PyIter_Check(receiver)) { + retval = Py_TYPE(receiver)->tp_iternext(receiver); + } + else { + retval = PyObject_CallMethodOneArg(receiver, &_Py_ID(send), v); + } + if (retval == NULL) { + if (tstate->c_tracefunc != NULL + && _PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) + call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame); + if (_PyGen_FetchStopIterationValue(&retval) == 0) { + gen_status = PYGEN_RETURN; + } + else { + gen_status = PYGEN_ERROR; + } + } + else { + gen_status = PYGEN_NEXT; + } + } + Py_DECREF(v); + if (gen_status == PYGEN_ERROR) { + assert(retval == NULL); + goto error; + } + if (gen_status == PYGEN_RETURN) { + assert(retval != NULL); + Py_DECREF(receiver); + SET_TOP(retval); + JUMPBY(oparg); + } + else { + assert(gen_status == PYGEN_NEXT); + assert(retval != NULL); + PUSH(retval); + } + DISPATCH(); + } + + TARGET(YIELD_VALUE) { + PyObject *retval = PEEK(1); + // 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. + assert(frame != &entry_frame); + PyGenObject *gen = _PyFrame_GetGenerator(frame); + gen->gi_frame_state = FRAME_SUSPENDED; + _PyFrame_SetStackPointer(frame, stack_pointer - 1); + TRACE_FUNCTION_EXIT(); + DTRACE_FUNCTION_EXIT(); + tstate->exc_info = gen->gi_exc_state.previous_item; + gen->gi_exc_state.previous_item = NULL; + _Py_LeaveRecursiveCallPy(tstate); + _PyInterpreterFrame *gen_frame = frame; + frame = cframe.current_frame = frame->previous; + gen_frame->previous = NULL; + frame->prev_instr -= frame->yield_offset; + _PyFrame_StackPush(frame, retval); + goto resume_frame; + } + + TARGET(POP_EXCEPT) { + PyObject *exc_value = PEEK(1); + _PyErr_StackItem *exc_info = tstate->exc_info; + Py_XSETREF(exc_info->exc_value, exc_value); + STACK_SHRINK(1); + DISPATCH(); + } + + TARGET(RERAISE) { + if (oparg) { + PyObject *lasti = PEEK(oparg + 1); + if (PyLong_Check(lasti)) { + frame->prev_instr = _PyCode_CODE(frame->f_code) + PyLong_AsLong(lasti); + assert(!_PyErr_Occurred(tstate)); + } + else { + assert(PyLong_Check(lasti)); + _PyErr_SetString(tstate, PyExc_SystemError, "lasti is not an int"); + goto error; + } + } + PyObject *val = POP(); + assert(val && PyExceptionInstance_Check(val)); + PyObject *exc = Py_NewRef(PyExceptionInstance_Class(val)); + PyObject *tb = PyException_GetTraceback(val); + _PyErr_Restore(tstate, exc, val, tb); + goto exception_unwind; + } + + TARGET(PREP_RERAISE_STAR) { + PyObject *excs = PEEK(1); + PyObject *orig = PEEK(2); + PyObject *val; + assert(PyList_Check(excs)); + + val = _PyExc_PrepReraiseStar(orig, excs); + Py_DECREF(orig); + Py_DECREF(excs); + + if (val == NULL) goto pop_2_error; + STACK_SHRINK(1); + POKE(1, val); + DISPATCH(); + } + + TARGET(END_ASYNC_FOR) { + PyObject *val = POP(); + assert(val && PyExceptionInstance_Check(val)); + if (PyErr_GivenExceptionMatches(val, PyExc_StopAsyncIteration)) { + Py_DECREF(val); + Py_DECREF(POP()); + } + else { + PyObject *exc = Py_NewRef(PyExceptionInstance_Class(val)); + PyObject *tb = PyException_GetTraceback(val); + _PyErr_Restore(tstate, exc, val, tb); + goto exception_unwind; + } + DISPATCH(); + } + + TARGET(CLEANUP_THROW) { + assert(throwflag); + PyObject *exc_value = TOP(); + assert(exc_value && PyExceptionInstance_Check(exc_value)); + if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { + PyObject *value = ((PyStopIterationObject *)exc_value)->value; + Py_INCREF(value); + Py_DECREF(POP()); // The StopIteration. + Py_DECREF(POP()); // The last sent value. + Py_DECREF(POP()); // The delegated sub-iterator. + PUSH(value); + } + else { + PyObject *exc_type = Py_NewRef(Py_TYPE(exc_value)); + PyObject *exc_traceback = PyException_GetTraceback(exc_value); + _PyErr_Restore(tstate, exc_type, Py_NewRef(exc_value), exc_traceback); + goto exception_unwind; + } + DISPATCH(); + } + + TARGET(LOAD_ASSERTION_ERROR) { + PyObject *value; + value = Py_NewRef(PyExc_AssertionError); + STACK_GROW(1); + POKE(1, value); + DISPATCH(); + } + + TARGET(LOAD_BUILD_CLASS) { + PyObject *bc; + if (PyDict_CheckExact(BUILTINS())) { + bc = _PyDict_GetItemWithError(BUILTINS(), + &_Py_ID(__build_class__)); + if (bc == NULL) { + if (!_PyErr_Occurred(tstate)) { + _PyErr_SetString(tstate, PyExc_NameError, + "__build_class__ not found"); + } + if (true) goto error; + } + Py_INCREF(bc); + } + else { + bc = PyObject_GetItem(BUILTINS(), &_Py_ID(__build_class__)); + if (bc == NULL) { + if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) + _PyErr_SetString(tstate, PyExc_NameError, + "__build_class__ not found"); + if (true) goto error; + } + } + STACK_GROW(1); + POKE(1, bc); + DISPATCH(); + } + + TARGET(STORE_NAME) { + PyObject *v = PEEK(1); + PyObject *name = GETITEM(names, oparg); + PyObject *ns = LOCALS(); + int err; + if (ns == NULL) { + _PyErr_Format(tstate, PyExc_SystemError, + "no locals found when storing %R", name); + Py_DECREF(v); + if (true) goto pop_1_error; + } + if (PyDict_CheckExact(ns)) + err = PyDict_SetItem(ns, name, v); + else + err = PyObject_SetItem(ns, name, v); + Py_DECREF(v); + if (err) goto pop_1_error; + STACK_SHRINK(1); + DISPATCH(); + } + + TARGET(DELETE_NAME) { + PyObject *name = GETITEM(names, oparg); + PyObject *ns = LOCALS(); + int err; + if (ns == NULL) { + _PyErr_Format(tstate, PyExc_SystemError, + "no locals when deleting %R", name); + goto error; + } + err = PyObject_DelItem(ns, name); + // Can't use ERROR_IF here. + if (err != 0) { + format_exc_check_arg(tstate, PyExc_NameError, + NAME_ERROR_MSG, + name); + goto error; + } + DISPATCH(); + } + + TARGET(UNPACK_SEQUENCE) { + PREDICTED(UNPACK_SEQUENCE); + #if ENABLE_SPECIALIZATION + _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + assert(cframe.use_tracing == 0); + PyObject *seq = TOP(); + next_instr--; + _Py_Specialize_UnpackSequence(seq, next_instr, oparg); + DISPATCH_SAME_OPARG(); + } + STAT_INC(UNPACK_SEQUENCE, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ + PyObject *seq = POP(); + PyObject **top = stack_pointer + oparg; + if (!unpack_iterable(tstate, seq, oparg, -1, top)) { + Py_DECREF(seq); + goto error; + } + STACK_GROW(oparg); + Py_DECREF(seq); + JUMPBY(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE); + DISPATCH(); + } + + TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { + PyObject *seq = TOP(); + DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); + DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); + STAT_INC(UNPACK_SEQUENCE, hit); + SET_TOP(Py_NewRef(PyTuple_GET_ITEM(seq, 1))); + PUSH(Py_NewRef(PyTuple_GET_ITEM(seq, 0))); + Py_DECREF(seq); + JUMPBY(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE); + DISPATCH(); + } + + TARGET(UNPACK_SEQUENCE_TUPLE) { + PyObject *seq = TOP(); + DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); + DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); + STAT_INC(UNPACK_SEQUENCE, hit); + STACK_SHRINK(1); + PyObject **items = _PyTuple_ITEMS(seq); + while (oparg--) { + PUSH(Py_NewRef(items[oparg])); + } + Py_DECREF(seq); + JUMPBY(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE); + DISPATCH(); + } + + TARGET(UNPACK_SEQUENCE_LIST) { + PyObject *seq = TOP(); + DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); + DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); + STAT_INC(UNPACK_SEQUENCE, hit); + STACK_SHRINK(1); + PyObject **items = _PyList_ITEMS(seq); + while (oparg--) { + PUSH(Py_NewRef(items[oparg])); + } + Py_DECREF(seq); + JUMPBY(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE); + DISPATCH(); + } + + TARGET(UNPACK_EX) { + int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); + PyObject *seq = POP(); + PyObject **top = stack_pointer + totalargs; + if (!unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top)) { + Py_DECREF(seq); + goto error; + } + STACK_GROW(totalargs); + Py_DECREF(seq); + DISPATCH(); + } + + TARGET(STORE_ATTR) { + PREDICTED(STORE_ATTR); + PyObject *owner = PEEK(1); + PyObject *v = PEEK(2); + uint16_t counter = read_u16(&next_instr[0].cache); + #if ENABLE_SPECIALIZATION + if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { + assert(cframe.use_tracing == 0); + PyObject *name = GETITEM(names, oparg); + next_instr--; + _Py_Specialize_StoreAttr(owner, next_instr, name); + DISPATCH_SAME_OPARG(); + } + STAT_INC(STORE_ATTR, deferred); + _PyAttrCache *cache = (_PyAttrCache *)next_instr; + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #else + (void)counter; // Unused. + #endif /* ENABLE_SPECIALIZATION */ + PyObject *name = GETITEM(names, oparg); + int err = PyObject_SetAttr(owner, name, v); + Py_DECREF(v); + Py_DECREF(owner); + if (err) goto pop_2_error; + STACK_SHRINK(2); + JUMPBY(4); + DISPATCH(); + } + + TARGET(DELETE_ATTR) { + PyObject *owner = PEEK(1); + PyObject *name = GETITEM(names, oparg); + int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); + Py_DECREF(owner); + if (err) goto pop_1_error; + STACK_SHRINK(1); + DISPATCH(); + } + + TARGET(STORE_GLOBAL) { + PyObject *v = PEEK(1); + PyObject *name = GETITEM(names, oparg); + int err = PyDict_SetItem(GLOBALS(), name, v); + Py_DECREF(v); + if (err) goto pop_1_error; + STACK_SHRINK(1); + DISPATCH(); + } + + TARGET(DELETE_GLOBAL) { + PyObject *name = GETITEM(names, oparg); + int err; + err = PyDict_DelItem(GLOBALS(), name); + // Can't use ERROR_IF here. + if (err != 0) { + if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + format_exc_check_arg(tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } + goto error; + } + DISPATCH(); + } + + TARGET(LOAD_NAME) { + PyObject *v; + PyObject *name = GETITEM(names, oparg); + PyObject *locals = LOCALS(); + if (locals == NULL) { + _PyErr_Format(tstate, PyExc_SystemError, + "no locals when loading %R", name); + goto error; + } + if (PyDict_CheckExact(locals)) { + v = PyDict_GetItemWithError(locals, name); + if (v != NULL) { + Py_INCREF(v); + } + else if (_PyErr_Occurred(tstate)) { + goto error; + } + } + else { + v = PyObject_GetItem(locals, name); + if (v == NULL) { + if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) + goto error; + _PyErr_Clear(tstate); + } + } + if (v == NULL) { + v = PyDict_GetItemWithError(GLOBALS(), name); + if (v != NULL) { + Py_INCREF(v); + } + else if (_PyErr_Occurred(tstate)) { + goto error; + } + else { + if (PyDict_CheckExact(BUILTINS())) { + v = PyDict_GetItemWithError(BUILTINS(), name); + if (v == NULL) { + if (!_PyErr_Occurred(tstate)) { + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } + goto error; + } + Py_INCREF(v); + } + else { + v = PyObject_GetItem(BUILTINS(), name); + if (v == NULL) { + if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } + goto error; + } + } + } + } + STACK_GROW(1); + POKE(1, v); + DISPATCH(); + } + + TARGET(LOAD_GLOBAL) { + PREDICTED(LOAD_GLOBAL); + #if ENABLE_SPECIALIZATION + _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + assert(cframe.use_tracing == 0); + PyObject *name = GETITEM(names, oparg>>1); + next_instr--; + _Py_Specialize_LoadGlobal(GLOBALS(), BUILTINS(), next_instr, name); + DISPATCH_SAME_OPARG(); + } + STAT_INC(LOAD_GLOBAL, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ + int push_null = oparg & 1; + PEEK(0) = NULL; + PyObject *name = GETITEM(names, oparg>>1); + PyObject *v; + if (PyDict_CheckExact(GLOBALS()) + && PyDict_CheckExact(BUILTINS())) + { + v = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(), + (PyDictObject *)BUILTINS(), + name); + if (v == NULL) { + if (!_PyErr_Occurred(tstate)) { + /* _PyDict_LoadGlobal() returns NULL without raising + * an exception if the key doesn't exist */ + format_exc_check_arg(tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } + goto error; + } + Py_INCREF(v); + } + else { + /* Slow-path if globals or builtins is not a dict */ + + /* namespace 1: globals */ + v = PyObject_GetItem(GLOBALS(), name); + if (v == NULL) { + if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + goto error; + } + _PyErr_Clear(tstate); + + /* namespace 2: builtins */ + v = PyObject_GetItem(BUILTINS(), name); + if (v == NULL) { + if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + format_exc_check_arg( + tstate, PyExc_NameError, + NAME_ERROR_MSG, name); + } + goto error; + } + } + } + /* Skip over inline cache */ + JUMPBY(INLINE_CACHE_ENTRIES_LOAD_GLOBAL); + STACK_GROW(push_null); + PUSH(v); + DISPATCH(); + } + + TARGET(LOAD_GLOBAL_MODULE) { + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); + PyDictObject *dict = (PyDictObject *)GLOBALS(); + _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; + uint32_t version = read_u32(cache->module_keys_version); + DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); + assert(DK_IS_UNICODE(dict->ma_keys)); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); + PyObject *res = entries[cache->index].me_value; + DEOPT_IF(res == NULL, LOAD_GLOBAL); + int push_null = oparg & 1; + PEEK(0) = NULL; + JUMPBY(INLINE_CACHE_ENTRIES_LOAD_GLOBAL); + STAT_INC(LOAD_GLOBAL, hit); + STACK_GROW(push_null+1); + SET_TOP(Py_NewRef(res)); + DISPATCH(); + } + + TARGET(LOAD_GLOBAL_BUILTIN) { + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); + DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); + PyDictObject *mdict = (PyDictObject *)GLOBALS(); + PyDictObject *bdict = (PyDictObject *)BUILTINS(); + _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; + uint32_t mod_version = read_u32(cache->module_keys_version); + uint16_t bltn_version = cache->builtin_keys_version; + DEOPT_IF(mdict->ma_keys->dk_version != mod_version, LOAD_GLOBAL); + DEOPT_IF(bdict->ma_keys->dk_version != bltn_version, LOAD_GLOBAL); + assert(DK_IS_UNICODE(bdict->ma_keys)); + PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys); + PyObject *res = entries[cache->index].me_value; + DEOPT_IF(res == NULL, LOAD_GLOBAL); + int push_null = oparg & 1; + PEEK(0) = NULL; + JUMPBY(INLINE_CACHE_ENTRIES_LOAD_GLOBAL); + STAT_INC(LOAD_GLOBAL, hit); + STACK_GROW(push_null+1); + SET_TOP(Py_NewRef(res)); + DISPATCH(); + } + + TARGET(DELETE_FAST) { + PyObject *v = GETLOCAL(oparg); + if (v == NULL) goto unbound_local_error; + SETLOCAL(oparg, NULL); + DISPATCH(); + } + + TARGET(MAKE_CELL) { + // "initial" is probably NULL but not if it's an arg (or set + // via PyFrame_LocalsToFast() before MAKE_CELL has run). + PyObject *initial = GETLOCAL(oparg); + PyObject *cell = PyCell_New(initial); + if (cell == NULL) { + goto resume_with_error; + } + SETLOCAL(oparg, cell); + DISPATCH(); + } + + TARGET(DELETE_DEREF) { + PyObject *cell = GETLOCAL(oparg); + PyObject *oldobj = PyCell_GET(cell); + // Can't use ERROR_IF here. + // Fortunately we don't need its superpower. + if (oldobj == NULL) { + format_exc_unbound(tstate, frame->f_code, oparg); + goto error; + } + PyCell_SET(cell, NULL); + Py_DECREF(oldobj); + DISPATCH(); + } + + TARGET(LOAD_CLASSDEREF) { + PyObject *value; + PyObject *name, *locals = LOCALS(); + assert(locals); + assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); + name = PyTuple_GET_ITEM(frame->f_code->co_localsplusnames, oparg); + if (PyDict_CheckExact(locals)) { + value = PyDict_GetItemWithError(locals, name); + if (value != NULL) { + Py_INCREF(value); + } + else if (_PyErr_Occurred(tstate)) { + goto error; + } + } + else { + value = PyObject_GetItem(locals, name); + if (value == NULL) { + if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { + goto error; + } + _PyErr_Clear(tstate); + } + } + if (!value) { + PyObject *cell = GETLOCAL(oparg); + value = PyCell_GET(cell); + if (value == NULL) { + format_exc_unbound(tstate, frame->f_code, oparg); + goto error; + } + Py_INCREF(value); + } + STACK_GROW(1); + POKE(1, value); + DISPATCH(); + } + + TARGET(LOAD_DEREF) { + PyObject *value; + PyObject *cell = GETLOCAL(oparg); + value = PyCell_GET(cell); + if (value == NULL) { + format_exc_unbound(tstate, frame->f_code, oparg); + if (true) goto error; + } + Py_INCREF(value); + STACK_GROW(1); + POKE(1, value); + DISPATCH(); + } + + TARGET(STORE_DEREF) { + PyObject *v = PEEK(1); + PyObject *cell = GETLOCAL(oparg); + PyObject *oldobj = PyCell_GET(cell); + PyCell_SET(cell, v); + Py_XDECREF(oldobj); + STACK_SHRINK(1); + DISPATCH(); + } + + TARGET(COPY_FREE_VARS) { + /* Copy closure variables to free variables */ + PyCodeObject *co = frame->f_code; + assert(PyFunction_Check(frame->f_funcobj)); + PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure; + assert(oparg == co->co_nfreevars); + int offset = co->co_nlocalsplus - oparg; + for (int i = 0; i < oparg; ++i) { + PyObject *o = PyTuple_GET_ITEM(closure, i); + frame->localsplus[offset + i] = Py_NewRef(o); + } + DISPATCH(); + } + + TARGET(BUILD_STRING) { + PyObject **pieces = &PEEK(oparg); + PyObject *str; + str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); + for (int i = 0; i < oparg; i++) { + Py_DECREF(pieces[i]); + } + if (str == NULL) { STACK_SHRINK(oparg); goto error; } + STACK_SHRINK(oparg); + STACK_GROW(1); + POKE(1, str); + DISPATCH(); + } + + TARGET(BUILD_TUPLE) { + PyObject **values = &PEEK(oparg); + PyObject *tup; + tup = _PyTuple_FromArraySteal(values, oparg); + if (tup == NULL) { STACK_SHRINK(oparg); goto error; } + STACK_SHRINK(oparg); + STACK_GROW(1); + POKE(1, tup); + DISPATCH(); + } + + TARGET(BUILD_LIST) { + PyObject **values = &PEEK(oparg); + PyObject *list; + list = _PyList_FromArraySteal(values, oparg); + if (list == NULL) { STACK_SHRINK(oparg); goto error; } + STACK_SHRINK(oparg); + STACK_GROW(1); + POKE(1, list); + DISPATCH(); + } + + TARGET(LIST_EXTEND) { + PyObject *iterable = PEEK(1); + PyObject *list = PEEK(2 + (oparg-1)); + PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); + if (none_val == NULL) { + if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && + (Py_TYPE(iterable)->tp_iter == NULL && !PySequence_Check(iterable))) + { + _PyErr_Clear(tstate); + _PyErr_Format(tstate, PyExc_TypeError, + "Value after * must be an iterable, not %.200s", + Py_TYPE(iterable)->tp_name); + } + Py_DECREF(iterable); + if (true) goto pop_1_error; + } + Py_DECREF(none_val); + Py_DECREF(iterable); + STACK_SHRINK(1); + DISPATCH(); + } + + TARGET(SET_UPDATE) { + PyObject *iterable = PEEK(1); + PyObject *set = PEEK(2 + (oparg-1)); + int err = _PySet_Update(set, iterable); + Py_DECREF(iterable); + if (err < 0) goto pop_1_error; + STACK_SHRINK(1); + DISPATCH(); + } + + TARGET(BUILD_SET) { + PyObject **values = &PEEK(oparg); + PyObject *set; + set = PySet_New(NULL); + int err = 0; + for (int i = 0; i < oparg; i++) { + PyObject *item = values[i]; + if (err == 0) + err = PySet_Add(set, item); + Py_DECREF(item); + } + if (err != 0) { + Py_DECREF(set); + if (true) { STACK_SHRINK(oparg); goto error; } + } + STACK_SHRINK(oparg); + STACK_GROW(1); + POKE(1, set); + DISPATCH(); + } + + TARGET(BUILD_MAP) { + PyObject **values = &PEEK(oparg*2); + PyObject *map; + map = _PyDict_FromItems( + values, 2, + values+1, 2, + oparg); + if (map == NULL) + goto error; + + for (int i = 0; i < oparg; i++) { + Py_DECREF(values[i*2]); + Py_DECREF(values[i*2+1]); + } + if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } + STACK_SHRINK(oparg*2); + STACK_GROW(1); + POKE(1, map); + DISPATCH(); + } + + TARGET(SETUP_ANNOTATIONS) { + int err; + PyObject *ann_dict; + if (LOCALS() == NULL) { + _PyErr_Format(tstate, PyExc_SystemError, + "no locals found when setting up annotations"); + if (true) goto error; + } + /* check if __annotations__ in locals()... */ + if (PyDict_CheckExact(LOCALS())) { + ann_dict = _PyDict_GetItemWithError(LOCALS(), + &_Py_ID(__annotations__)); + if (ann_dict == NULL) { + if (_PyErr_Occurred(tstate)) goto error; + /* ...if not, create a new one */ + ann_dict = PyDict_New(); + if (ann_dict == NULL) goto error; + err = PyDict_SetItem(LOCALS(), &_Py_ID(__annotations__), + ann_dict); + Py_DECREF(ann_dict); + if (err) goto error; + } + } + else { + /* do the same if locals() is not a dict */ + ann_dict = PyObject_GetItem(LOCALS(), &_Py_ID(__annotations__)); + if (ann_dict == NULL) { + if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) goto error; + _PyErr_Clear(tstate); + ann_dict = PyDict_New(); + if (ann_dict == NULL) goto error; + err = PyObject_SetItem(LOCALS(), &_Py_ID(__annotations__), + ann_dict); + Py_DECREF(ann_dict); + if (err) goto error; + } + else { + Py_DECREF(ann_dict); + } + } + DISPATCH(); + } + + TARGET(BUILD_CONST_KEY_MAP) { + PyObject *keys = PEEK(1); + PyObject **values = &PEEK(1 + oparg); + PyObject *map; + if (!PyTuple_CheckExact(keys) || + PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { + _PyErr_SetString(tstate, PyExc_SystemError, + "bad BUILD_CONST_KEY_MAP keys argument"); + goto error; // Pop the keys and values. + } + map = _PyDict_FromItems( + &PyTuple_GET_ITEM(keys, 0), 1, + values, 1, oparg); + Py_DECREF(keys); + for (int i = 0; i < oparg; i++) { + Py_DECREF(values[i]); + } + if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } + STACK_SHRINK(oparg); + POKE(1, map); + DISPATCH(); + } + + TARGET(DICT_UPDATE) { + PyObject *update = PEEK(1); + PyObject *dict = PEEK(oparg + 1); // update is still on the stack + if (PyDict_Update(dict, update) < 0) { + if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.200s' object is not a mapping", + Py_TYPE(update)->tp_name); + } + Py_DECREF(update); + if (true) goto pop_1_error; + } + Py_DECREF(update); + STACK_SHRINK(1); + DISPATCH(); + } + + TARGET(DICT_MERGE) { + PyObject *update = PEEK(1); + PyObject *dict = PEEK(oparg + 1); // update is still on the stack + + if (_PyDict_MergeEx(dict, update, 2) < 0) { + format_kwargs_error(tstate, PEEK(3 + oparg), update); + Py_DECREF(update); + if (true) goto pop_1_error; + } + Py_DECREF(update); + STACK_SHRINK(1); + PREDICT(CALL_FUNCTION_EX); + DISPATCH(); + } + + TARGET(MAP_ADD) { + PyObject *value = PEEK(1); + PyObject *key = PEEK(2); + PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack + assert(PyDict_CheckExact(dict)); + /* dict[key] = value */ + // Do not DECREF INPUTS because the function steals the references + if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; + STACK_SHRINK(2); + PREDICT(JUMP_BACKWARD); + DISPATCH(); + } + + TARGET(LOAD_ATTR) { + PREDICTED(LOAD_ATTR); + #if ENABLE_SPECIALIZATION + _PyAttrCache *cache = (_PyAttrCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + assert(cframe.use_tracing == 0); + PyObject *owner = TOP(); + PyObject *name = GETITEM(names, oparg>>1); + next_instr--; + _Py_Specialize_LoadAttr(owner, next_instr, name); + DISPATCH_SAME_OPARG(); + } + STAT_INC(LOAD_ATTR, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ + PyObject *name = GETITEM(names, oparg >> 1); + PyObject *owner = TOP(); + if (oparg & 1) { + /* Designed to work in tandem with CALL. */ + PyObject* meth = NULL; + + int meth_found = _PyObject_GetMethod(owner, name, &meth); + + if (meth == NULL) { + /* Most likely attribute wasn't found. */ + goto error; + } + + if (meth_found) { + /* We can bypass temporary bound method object. + meth is unbound method and obj is self. + + meth | self | arg1 | ... | argN + */ + SET_TOP(meth); + PUSH(owner); // self + } + else { + /* meth is not an unbound method (but a regular attr, or + something was returned by a descriptor protocol). Set + the second element of the stack to NULL, to signal + CALL that it's not a method call. + + NULL | meth | arg1 | ... | argN + */ + SET_TOP(NULL); + Py_DECREF(owner); + PUSH(meth); + } + } + else { + PyObject *res = PyObject_GetAttr(owner, name); + if (res == NULL) { + goto error; + } + Py_DECREF(owner); + SET_TOP(res); + } + JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + DISPATCH(); + } + + TARGET(LOAD_ATTR_INSTANCE_VALUE) { + assert(cframe.use_tracing == 0); + PyObject *owner = TOP(); + PyObject *res; + PyTypeObject *tp = Py_TYPE(owner); + _PyAttrCache *cache = (_PyAttrCache *)next_instr; + uint32_t type_version = read_u32(cache->version); + assert(type_version != 0); + DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); + assert(tp->tp_dictoffset < 0); + assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR); + res = _PyDictOrValues_GetValues(dorv)->values[cache->index]; + DEOPT_IF(res == NULL, LOAD_ATTR); + STAT_INC(LOAD_ATTR, hit); + Py_INCREF(res); + SET_TOP(NULL); + STACK_GROW((oparg & 1)); + SET_TOP(res); + Py_DECREF(owner); + JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + DISPATCH(); + } + + TARGET(LOAD_ATTR_MODULE) { + assert(cframe.use_tracing == 0); + PyObject *owner = TOP(); + PyObject *res; + _PyAttrCache *cache = (_PyAttrCache *)next_instr; + DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); + PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; + assert(dict != NULL); + DEOPT_IF(dict->ma_keys->dk_version != read_u32(cache->version), + LOAD_ATTR); + assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE); + assert(cache->index < dict->ma_keys->dk_nentries); + PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + cache->index; + res = ep->me_value; + DEOPT_IF(res == NULL, LOAD_ATTR); + STAT_INC(LOAD_ATTR, hit); + Py_INCREF(res); + SET_TOP(NULL); + STACK_GROW((oparg & 1)); + SET_TOP(res); + Py_DECREF(owner); + JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + DISPATCH(); + } + + TARGET(LOAD_ATTR_WITH_HINT) { + assert(cframe.use_tracing == 0); + PyObject *owner = TOP(); + PyObject *res; + PyTypeObject *tp = Py_TYPE(owner); + _PyAttrCache *cache = (_PyAttrCache *)next_instr; + uint32_t type_version = read_u32(cache->version); + assert(type_version != 0); + DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); + assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + DEOPT_IF(_PyDictOrValues_IsValues(dorv), LOAD_ATTR); + PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); + DEOPT_IF(dict == NULL, LOAD_ATTR); + assert(PyDict_CheckExact((PyObject *)dict)); + PyObject *name = GETITEM(names, oparg>>1); + uint16_t hint = cache->index; + DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, LOAD_ATTR); + if (DK_IS_UNICODE(dict->ma_keys)) { + PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; + DEOPT_IF(ep->me_key != name, LOAD_ATTR); + res = ep->me_value; + } + else { + PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint; + DEOPT_IF(ep->me_key != name, LOAD_ATTR); + res = ep->me_value; + } + DEOPT_IF(res == NULL, LOAD_ATTR); + STAT_INC(LOAD_ATTR, hit); + Py_INCREF(res); + SET_TOP(NULL); + STACK_GROW((oparg & 1)); + SET_TOP(res); + Py_DECREF(owner); + JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + DISPATCH(); + } + + TARGET(LOAD_ATTR_SLOT) { + assert(cframe.use_tracing == 0); + PyObject *owner = TOP(); + PyObject *res; + PyTypeObject *tp = Py_TYPE(owner); + _PyAttrCache *cache = (_PyAttrCache *)next_instr; + uint32_t type_version = read_u32(cache->version); + assert(type_version != 0); + DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); + char *addr = (char *)owner + cache->index; + res = *(PyObject **)addr; + DEOPT_IF(res == NULL, LOAD_ATTR); + STAT_INC(LOAD_ATTR, hit); + Py_INCREF(res); + SET_TOP(NULL); + STACK_GROW((oparg & 1)); + SET_TOP(res); + Py_DECREF(owner); + JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + DISPATCH(); + } + + TARGET(LOAD_ATTR_CLASS) { + assert(cframe.use_tracing == 0); + _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; + + PyObject *cls = TOP(); + DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); + uint32_t type_version = read_u32(cache->type_version); + DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, + LOAD_ATTR); + assert(type_version != 0); + + STAT_INC(LOAD_ATTR, hit); + PyObject *res = read_obj(cache->descr); + assert(res != NULL); + Py_INCREF(res); + SET_TOP(NULL); + STACK_GROW((oparg & 1)); + SET_TOP(res); + Py_DECREF(cls); + JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + DISPATCH(); + } + + TARGET(LOAD_ATTR_PROPERTY) { + assert(cframe.use_tracing == 0); + DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); + _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; + + PyObject *owner = TOP(); + PyTypeObject *cls = Py_TYPE(owner); + uint32_t type_version = read_u32(cache->type_version); + DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); + assert(type_version != 0); + PyObject *fget = read_obj(cache->descr); + assert(Py_IS_TYPE(fget, &PyFunction_Type)); + PyFunctionObject *f = (PyFunctionObject *)fget; + uint32_t func_version = read_u32(cache->keys_version); + assert(func_version != 0); + DEOPT_IF(f->func_version != func_version, LOAD_ATTR); + PyCodeObject *code = (PyCodeObject *)f->func_code; + assert(code->co_argcount == 1); + DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR); + STAT_INC(LOAD_ATTR, hit); + Py_INCREF(fget); + _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 1); + SET_TOP(NULL); + int shrink_stack = !(oparg & 1); + STACK_SHRINK(shrink_stack); + new_frame->localsplus[0] = owner; + JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + DISPATCH_INLINED(new_frame); + } + + TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { + assert(cframe.use_tracing == 0); + DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); + _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; + PyObject *owner = TOP(); + PyTypeObject *cls = Py_TYPE(owner); + uint32_t type_version = read_u32(cache->type_version); + DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); + assert(type_version != 0); + PyObject *getattribute = read_obj(cache->descr); + assert(Py_IS_TYPE(getattribute, &PyFunction_Type)); + PyFunctionObject *f = (PyFunctionObject *)getattribute; + uint32_t func_version = read_u32(cache->keys_version); + assert(func_version != 0); + DEOPT_IF(f->func_version != func_version, LOAD_ATTR); + PyCodeObject *code = (PyCodeObject *)f->func_code; + assert(code->co_argcount == 2); + DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR); + STAT_INC(LOAD_ATTR, hit); + + PyObject *name = GETITEM(names, oparg >> 1); + Py_INCREF(f); + _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2); + SET_TOP(NULL); + int shrink_stack = !(oparg & 1); + STACK_SHRINK(shrink_stack); + new_frame->localsplus[0] = owner; + new_frame->localsplus[1] = Py_NewRef(name); + JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + DISPATCH_INLINED(new_frame); + } + + TARGET(STORE_ATTR_INSTANCE_VALUE) { + PyObject *owner = PEEK(1); + PyObject *value = PEEK(2); + uint32_t type_version = read_u32(&next_instr[1].cache); + uint16_t index = read_u16(&next_instr[3].cache); + assert(cframe.use_tracing == 0); + PyTypeObject *tp = Py_TYPE(owner); + assert(type_version != 0); + DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); + assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + DEOPT_IF(!_PyDictOrValues_IsValues(dorv), STORE_ATTR); + STAT_INC(STORE_ATTR, hit); + PyDictValues *values = _PyDictOrValues_GetValues(dorv); + PyObject *old_value = values->values[index]; + values->values[index] = value; + if (old_value == NULL) { + _PyDictValues_AddToInsertionOrder(values, index); + } + else { + Py_DECREF(old_value); + } + Py_DECREF(owner); + STACK_SHRINK(2); + JUMPBY(4); + DISPATCH(); + } + + TARGET(STORE_ATTR_WITH_HINT) { + PyObject *owner = PEEK(1); + PyObject *value = PEEK(2); + uint32_t type_version = read_u32(&next_instr[1].cache); + uint16_t hint = read_u16(&next_instr[3].cache); + assert(cframe.use_tracing == 0); + PyTypeObject *tp = Py_TYPE(owner); + assert(type_version != 0); + DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); + assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + DEOPT_IF(_PyDictOrValues_IsValues(dorv), STORE_ATTR); + PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); + DEOPT_IF(dict == NULL, STORE_ATTR); + assert(PyDict_CheckExact((PyObject *)dict)); + PyObject *name = GETITEM(names, oparg); + DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, STORE_ATTR); + PyObject *old_value; + uint64_t new_version; + if (DK_IS_UNICODE(dict->ma_keys)) { + PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; + DEOPT_IF(ep->me_key != name, STORE_ATTR); + old_value = ep->me_value; + DEOPT_IF(old_value == NULL, STORE_ATTR); + new_version = _PyDict_NotifyEvent(PyDict_EVENT_MODIFIED, dict, name, value); + ep->me_value = value; + } + else { + PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint; + DEOPT_IF(ep->me_key != name, STORE_ATTR); + old_value = ep->me_value; + DEOPT_IF(old_value == NULL, STORE_ATTR); + new_version = _PyDict_NotifyEvent(PyDict_EVENT_MODIFIED, dict, name, value); + ep->me_value = value; + } + Py_DECREF(old_value); + STAT_INC(STORE_ATTR, hit); + /* Ensure dict is GC tracked if it needs to be */ + if (!_PyObject_GC_IS_TRACKED(dict) && _PyObject_GC_MAY_BE_TRACKED(value)) { + _PyObject_GC_TRACK(dict); + } + /* PEP 509 */ + dict->ma_version_tag = new_version; + Py_DECREF(owner); + STACK_SHRINK(2); + JUMPBY(4); + DISPATCH(); + } + + TARGET(STORE_ATTR_SLOT) { + PyObject *owner = PEEK(1); + PyObject *value = PEEK(2); + uint32_t type_version = read_u32(&next_instr[1].cache); + uint16_t index = read_u16(&next_instr[3].cache); + assert(cframe.use_tracing == 0); + PyTypeObject *tp = Py_TYPE(owner); + assert(type_version != 0); + DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); + char *addr = (char *)owner + index; + STAT_INC(STORE_ATTR, hit); + PyObject *old_value = *(PyObject **)addr; + *(PyObject **)addr = value; + Py_XDECREF(old_value); + Py_DECREF(owner); + STACK_SHRINK(2); + JUMPBY(4); + DISPATCH(); + } + + TARGET(COMPARE_OP) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + PyObject *res; + STAT_INC(COMPARE_OP, deferred); + assert((oparg >> 4) <= Py_GE); + res = PyObject_RichCompare(left, right, oparg>>4); + Py_DECREF(left); + Py_DECREF(right); + if (res == NULL) goto pop_2_error; + STACK_SHRINK(1); + POKE(1, res); + JUMPBY(1); + DISPATCH(); + } + + TARGET(COMPARE_AND_BRANCH) { + PREDICTED(COMPARE_AND_BRANCH); + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + #if ENABLE_SPECIALIZATION + _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + assert(cframe.use_tracing == 0); + next_instr--; + _Py_Specialize_CompareAndBranch(left, right, next_instr, oparg); + DISPATCH_SAME_OPARG(); + } + STAT_INC(COMPARE_AND_BRANCH, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ + assert((oparg >> 4) <= Py_GE); + PyObject *cond = PyObject_RichCompare(left, right, oparg>>4); + Py_DECREF(left); + Py_DECREF(right); + if (cond == NULL) goto pop_2_error; + assert(_Py_OPCODE(next_instr[1]) == POP_JUMP_IF_FALSE || + _Py_OPCODE(next_instr[1]) == POP_JUMP_IF_TRUE); + bool jump_on_true = _Py_OPCODE(next_instr[1]) == POP_JUMP_IF_TRUE; + int offset = _Py_OPARG(next_instr[1]); + int err = PyObject_IsTrue(cond); + Py_DECREF(cond); + if (err < 0) { + goto error; + } + if (jump_on_true == (err != 0)) { + JUMPBY(offset); + } + STACK_SHRINK(2); + JUMPBY(2); + DISPATCH(); + } + + TARGET(COMPARE_AND_BRANCH_FLOAT) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_AND_BRANCH); + DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_AND_BRANCH); + STAT_INC(COMPARE_AND_BRANCH, hit); + double dleft = PyFloat_AS_DOUBLE(left); + double dright = PyFloat_AS_DOUBLE(right); + // 1 if NaN, 2 if <, 4 if >, 8 if ==; this matches low four bits of the oparg + int sign_ish = COMPARISON_BIT(dleft, dright); + _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); + _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); + if (sign_ish & oparg) { + int offset = _Py_OPARG(next_instr[1]); + JUMPBY(offset); + } + STACK_SHRINK(2); + JUMPBY(2); + DISPATCH(); + } + + TARGET(COMPARE_AND_BRANCH_INT) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); + DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); + DEOPT_IF((size_t)(Py_SIZE(left) + 1) > 2, COMPARE_AND_BRANCH); + DEOPT_IF((size_t)(Py_SIZE(right) + 1) > 2, COMPARE_AND_BRANCH); + STAT_INC(COMPARE_AND_BRANCH, hit); + assert(Py_ABS(Py_SIZE(left)) <= 1 && Py_ABS(Py_SIZE(right)) <= 1); + Py_ssize_t ileft = Py_SIZE(left) * ((PyLongObject *)left)->ob_digit[0]; + Py_ssize_t iright = Py_SIZE(right) * ((PyLongObject *)right)->ob_digit[0]; + // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg + int sign_ish = COMPARISON_BIT(ileft, iright); + _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); + _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); + if (sign_ish & oparg) { + int offset = _Py_OPARG(next_instr[1]); + JUMPBY(offset); + } + STACK_SHRINK(2); + JUMPBY(2); + DISPATCH(); + } + + TARGET(COMPARE_AND_BRANCH_STR) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_AND_BRANCH); + DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_AND_BRANCH); + STAT_INC(COMPARE_AND_BRANCH, hit); + int res = _PyUnicode_Equal(left, right); + assert((oparg >>4) == Py_EQ || (oparg >>4) == Py_NE); + _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); + _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); + assert(res == 0 || res == 1); + assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); + assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); + if ((res + COMPARISON_NOT_EQUALS) & oparg) { + int offset = _Py_OPARG(next_instr[1]); + JUMPBY(offset); + } + STACK_SHRINK(2); + JUMPBY(2); + DISPATCH(); + } + + TARGET(IS_OP) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + PyObject *b; + int res = Py_Is(left, right) ^ oparg; + Py_DECREF(left); + Py_DECREF(right); + b = Py_NewRef(res ? Py_True : Py_False); + STACK_SHRINK(1); + POKE(1, b); + DISPATCH(); + } + + TARGET(CONTAINS_OP) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + PyObject *b; + int res = PySequence_Contains(right, left); + Py_DECREF(left); + Py_DECREF(right); + if (res < 0) goto pop_2_error; + b = Py_NewRef((res^oparg) ? Py_True : Py_False); + STACK_SHRINK(1); + POKE(1, b); + DISPATCH(); + } + + TARGET(CHECK_EG_MATCH) { + PyObject *match_type = PEEK(1); + PyObject *exc_value = PEEK(2); + PyObject *rest; + PyObject *match; + if (check_except_star_type_valid(tstate, match_type) < 0) { + Py_DECREF(exc_value); + Py_DECREF(match_type); + if (true) goto pop_2_error; + } + + match = NULL; + rest = NULL; + int res = exception_group_match(exc_value, match_type, + &match, &rest); + Py_DECREF(exc_value); + Py_DECREF(match_type); + if (res < 0) goto pop_2_error; + + assert((match == NULL) == (rest == NULL)); + if (match == NULL) goto pop_2_error; + + if (!Py_IsNone(match)) { + PyErr_SetExcInfo(NULL, Py_NewRef(match), NULL); + } + POKE(1, match); + POKE(2, rest); + DISPATCH(); + } + + TARGET(CHECK_EXC_MATCH) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + PyObject *b; + assert(PyExceptionInstance_Check(left)); + if (check_except_type_valid(tstate, right) < 0) { + Py_DECREF(right); + if (true) goto pop_1_error; + } + + int res = PyErr_GivenExceptionMatches(left, right); + Py_DECREF(right); + b = Py_NewRef(res ? Py_True : Py_False); + POKE(1, b); + DISPATCH(); + } + + TARGET(IMPORT_NAME) { + PyObject *fromlist = PEEK(1); + PyObject *level = PEEK(2); + PyObject *res; + PyObject *name = GETITEM(names, oparg); + res = import_name(tstate, frame, name, fromlist, level); + Py_DECREF(level); + Py_DECREF(fromlist); + if (res == NULL) goto pop_2_error; + STACK_SHRINK(1); + POKE(1, res); + DISPATCH(); + } + + TARGET(IMPORT_FROM) { + PyObject *from = PEEK(1); + PyObject *res; + PyObject *name = GETITEM(names, oparg); + res = import_from(tstate, from, name); + if (res == NULL) goto error; + STACK_GROW(1); + POKE(1, res); + DISPATCH(); + } + + TARGET(JUMP_FORWARD) { + JUMPBY(oparg); + DISPATCH(); + } + + TARGET(JUMP_BACKWARD) { + PREDICTED(JUMP_BACKWARD); + assert(oparg < INSTR_OFFSET()); + JUMPBY(-oparg); + CHECK_EVAL_BREAKER(); + DISPATCH(); + } + + TARGET(POP_JUMP_IF_FALSE) { + PREDICTED(POP_JUMP_IF_FALSE); + PyObject *cond = POP(); + if (Py_IsTrue(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + } + else if (Py_IsFalse(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + JUMPBY(oparg); + } + else { + int err = PyObject_IsTrue(cond); + Py_DECREF(cond); + if (err > 0) + ; + else if (err == 0) { + JUMPBY(oparg); + } + else + goto error; + } + DISPATCH(); + } + + TARGET(POP_JUMP_IF_TRUE) { + PyObject *cond = POP(); + if (Py_IsFalse(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + } + else if (Py_IsTrue(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + JUMPBY(oparg); + } + else { + int err = PyObject_IsTrue(cond); + Py_DECREF(cond); + if (err > 0) { + JUMPBY(oparg); + } + else if (err == 0) + ; + else + goto error; + } + DISPATCH(); + } + + TARGET(POP_JUMP_IF_NOT_NONE) { + PyObject *value = POP(); + if (!Py_IsNone(value)) { + JUMPBY(oparg); + } + Py_DECREF(value); + DISPATCH(); + } + + TARGET(POP_JUMP_IF_NONE) { + PyObject *value = POP(); + if (Py_IsNone(value)) { + _Py_DECREF_NO_DEALLOC(value); + JUMPBY(oparg); + } + else { + Py_DECREF(value); + } + DISPATCH(); + } + + TARGET(JUMP_IF_FALSE_OR_POP) { + PyObject *cond = TOP(); + int err; + if (Py_IsTrue(cond)) { + STACK_SHRINK(1); + _Py_DECREF_NO_DEALLOC(cond); + } + else if (Py_IsFalse(cond)) { + JUMPBY(oparg); + } + else { + err = PyObject_IsTrue(cond); + if (err > 0) { + STACK_SHRINK(1); + Py_DECREF(cond); + } + else if (err == 0) { + JUMPBY(oparg); + } + else { + goto error; + } + } + DISPATCH(); + } + + TARGET(JUMP_IF_TRUE_OR_POP) { + PyObject *cond = TOP(); + int err; + if (Py_IsFalse(cond)) { + STACK_SHRINK(1); + _Py_DECREF_NO_DEALLOC(cond); + } + else if (Py_IsTrue(cond)) { + JUMPBY(oparg); + } + else { + err = PyObject_IsTrue(cond); + if (err > 0) { + JUMPBY(oparg); + } + else if (err == 0) { + STACK_SHRINK(1); + Py_DECREF(cond); + } + else { + goto error; + } + } + DISPATCH(); + } + + TARGET(JUMP_BACKWARD_NO_INTERRUPT) { + /* This bytecode is used in the `yield from` or `await` loop. + * If there is an interrupt, we want it handled in the innermost + * generator or coroutine, so we deliberately do not check it here. + * (see bpo-30039). + */ + JUMPBY(-oparg); + DISPATCH(); + } + + TARGET(GET_LEN) { + // PUSH(len(TOS)) + Py_ssize_t len_i = PyObject_Length(TOP()); + if (len_i < 0) { + goto error; + } + PyObject *len_o = PyLong_FromSsize_t(len_i); + if (len_o == NULL) { + goto error; + } + PUSH(len_o); + DISPATCH(); + } + + TARGET(MATCH_CLASS) { + PyObject *names = PEEK(1); + PyObject *type = PEEK(2); + PyObject *subject = PEEK(3); + PyObject *attrs; + // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or + // None on failure. + assert(PyTuple_CheckExact(names)); + attrs = match_class(tstate, subject, type, oparg, names); + Py_DECREF(subject); + Py_DECREF(type); + Py_DECREF(names); + if (attrs) { + assert(PyTuple_CheckExact(attrs)); // Success! + } + else { + if (_PyErr_Occurred(tstate)) goto pop_3_error; + attrs = Py_NewRef(Py_None); // Failure! + } + STACK_SHRINK(2); + POKE(1, attrs); + DISPATCH(); + } + + TARGET(MATCH_MAPPING) { + PyObject *subject = PEEK(1); + PyObject *res; + int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; + res = Py_NewRef(match ? Py_True : Py_False); + STACK_GROW(1); + POKE(1, res); + PREDICT(POP_JUMP_IF_FALSE); + DISPATCH(); + } + + TARGET(MATCH_SEQUENCE) { + PyObject *subject = PEEK(1); + PyObject *res; + int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; + res = Py_NewRef(match ? Py_True : Py_False); + STACK_GROW(1); + POKE(1, res); + PREDICT(POP_JUMP_IF_FALSE); + DISPATCH(); + } + + TARGET(MATCH_KEYS) { + PyObject *keys = PEEK(1); + PyObject *subject = PEEK(2); + PyObject *values_or_none; + // On successful match, PUSH(values). Otherwise, PUSH(None). + values_or_none = match_keys(tstate, subject, keys); + if (values_or_none == NULL) goto error; + STACK_GROW(1); + POKE(1, values_or_none); + DISPATCH(); + } + + TARGET(GET_ITER) { + /* before: [obj]; after [getiter(obj)] */ + PyObject *iterable = TOP(); + PyObject *iter = PyObject_GetIter(iterable); + Py_DECREF(iterable); + SET_TOP(iter); + if (iter == NULL) + goto error; + DISPATCH(); + } + + TARGET(GET_YIELD_FROM_ITER) { + /* before: [obj]; after [getiter(obj)] */ + PyObject *iterable = TOP(); + PyObject *iter; + if (PyCoro_CheckExact(iterable)) { + /* `iterable` is a coroutine */ + if (!(frame->f_code->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) { + /* and it is used in a 'yield from' expression of a + regular generator. */ + Py_DECREF(iterable); + SET_TOP(NULL); + _PyErr_SetString(tstate, PyExc_TypeError, + "cannot 'yield from' a coroutine object " + "in a non-coroutine generator"); + goto error; + } + } + else if (!PyGen_CheckExact(iterable)) { + /* `iterable` is not a generator. */ + iter = PyObject_GetIter(iterable); + Py_DECREF(iterable); + SET_TOP(iter); + if (iter == NULL) + goto error; + } + PREDICT(LOAD_CONST); + DISPATCH(); + } + + TARGET(FOR_ITER) { + PREDICTED(FOR_ITER); + #if ENABLE_SPECIALIZATION + _PyForIterCache *cache = (_PyForIterCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + assert(cframe.use_tracing == 0); + next_instr--; + _Py_Specialize_ForIter(TOP(), next_instr, oparg); + DISPATCH_SAME_OPARG(); + } + STAT_INC(FOR_ITER, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ + /* before: [iter]; after: [iter, iter()] *or* [] */ + PyObject *iter = TOP(); + PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); + if (next != NULL) { + PUSH(next); + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + } + else { + if (_PyErr_Occurred(tstate)) { + if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { + goto error; + } + else if (tstate->c_tracefunc != NULL) { + call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame); + } + _PyErr_Clear(tstate); + } + /* iterator ended normally */ + assert(_Py_OPCODE(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg]) == END_FOR); + STACK_SHRINK(1); + Py_DECREF(iter); + /* Skip END_FOR */ + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); + } + DISPATCH(); + } + + TARGET(FOR_ITER_LIST) { + assert(cframe.use_tracing == 0); + _PyListIterObject *it = (_PyListIterObject *)TOP(); + DEOPT_IF(Py_TYPE(it) != &PyListIter_Type, FOR_ITER); + STAT_INC(FOR_ITER, hit); + PyListObject *seq = it->it_seq; + if (seq) { + if (it->it_index < PyList_GET_SIZE(seq)) { + PyObject *next = PyList_GET_ITEM(seq, it->it_index++); + PUSH(Py_NewRef(next)); + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + goto end_for_iter_list; // End of this instruction + } + it->it_seq = NULL; + Py_DECREF(seq); + } + STACK_SHRINK(1); + Py_DECREF(it); + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); + end_for_iter_list: + DISPATCH(); + } + + TARGET(FOR_ITER_TUPLE) { + assert(cframe.use_tracing == 0); + _PyTupleIterObject *it = (_PyTupleIterObject *)TOP(); + DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); + STAT_INC(FOR_ITER, hit); + PyTupleObject *seq = it->it_seq; + if (seq) { + if (it->it_index < PyTuple_GET_SIZE(seq)) { + PyObject *next = PyTuple_GET_ITEM(seq, it->it_index++); + PUSH(Py_NewRef(next)); + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + goto end_for_iter_tuple; // End of this instruction + } + it->it_seq = NULL; + Py_DECREF(seq); + } + STACK_SHRINK(1); + Py_DECREF(it); + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); + end_for_iter_tuple: + DISPATCH(); + } + + TARGET(FOR_ITER_RANGE) { + assert(cframe.use_tracing == 0); + _PyRangeIterObject *r = (_PyRangeIterObject *)TOP(); + DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); + STAT_INC(FOR_ITER, hit); + _Py_CODEUNIT next = next_instr[INLINE_CACHE_ENTRIES_FOR_ITER]; + assert(_PyOpcode_Deopt[_Py_OPCODE(next)] == STORE_FAST); + if (r->len <= 0) { + STACK_SHRINK(1); + Py_DECREF(r); + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); + } + else { + long value = r->start; + r->start = value + r->step; + r->len--; + if (_PyLong_AssignValue(&GETLOCAL(_Py_OPARG(next)), value) < 0) { + goto error; + } + // The STORE_FAST is already done. + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + 1); + } + DISPATCH(); + } + + TARGET(FOR_ITER_GEN) { + assert(cframe.use_tracing == 0); + PyGenObject *gen = (PyGenObject *)TOP(); + DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); + DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER); + STAT_INC(FOR_ITER, hit); + _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; + frame->yield_offset = oparg; + _PyFrame_StackPush(gen_frame, Py_NewRef(Py_None)); + gen->gi_frame_state = FRAME_EXECUTING; + gen->gi_exc_state.previous_item = tstate->exc_info; + tstate->exc_info = &gen->gi_exc_state; + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg); + assert(_Py_OPCODE(*next_instr) == END_FOR); + DISPATCH_INLINED(gen_frame); + } + + TARGET(BEFORE_ASYNC_WITH) { + PyObject *mgr = TOP(); + PyObject *res; + PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); + if (enter == NULL) { + if (!_PyErr_Occurred(tstate)) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.200s' object does not support the " + "asynchronous context manager protocol", + Py_TYPE(mgr)->tp_name); + } + goto error; + } + PyObject *exit = _PyObject_LookupSpecial(mgr, &_Py_ID(__aexit__)); + if (exit == NULL) { + if (!_PyErr_Occurred(tstate)) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.200s' object does not support the " + "asynchronous context manager protocol " + "(missed __aexit__ method)", + Py_TYPE(mgr)->tp_name); + } + Py_DECREF(enter); + goto error; + } + SET_TOP(exit); + Py_DECREF(mgr); + res = _PyObject_CallNoArgs(enter); + Py_DECREF(enter); + if (res == NULL) + goto error; + PUSH(res); + PREDICT(GET_AWAITABLE); + DISPATCH(); + } + + TARGET(BEFORE_WITH) { + PyObject *mgr = TOP(); + PyObject *res; + PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__enter__)); + if (enter == NULL) { + if (!_PyErr_Occurred(tstate)) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.200s' object does not support the " + "context manager protocol", + Py_TYPE(mgr)->tp_name); + } + goto error; + } + PyObject *exit = _PyObject_LookupSpecial(mgr, &_Py_ID(__exit__)); + if (exit == NULL) { + if (!_PyErr_Occurred(tstate)) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.200s' object does not support the " + "context manager protocol " + "(missed __exit__ method)", + Py_TYPE(mgr)->tp_name); + } + Py_DECREF(enter); + goto error; + } + SET_TOP(exit); + Py_DECREF(mgr); + res = _PyObject_CallNoArgs(enter); + Py_DECREF(enter); + if (res == NULL) { + goto error; + } + PUSH(res); + DISPATCH(); + } + + TARGET(WITH_EXCEPT_START) { + PyObject *val = PEEK(1); + PyObject *lasti = PEEK(3); + PyObject *exit_func = PEEK(4); + PyObject *res; + /* At the top of the stack are 4 values: + - val: TOP = exc_info() + - unused: SECOND = previous exception + - lasti: THIRD = lasti of exception in exc_info() + - exit_func: FOURTH = the context.__exit__ bound method + We call FOURTH(type(TOP), TOP, GetTraceback(TOP)). + Then we push the __exit__ return value. + */ + PyObject *exc, *tb; + + assert(val && PyExceptionInstance_Check(val)); + exc = PyExceptionInstance_Class(val); + tb = PyException_GetTraceback(val); + Py_XDECREF(tb); + assert(PyLong_Check(lasti)); + (void)lasti; // Shut up compiler warning if asserts are off + PyObject *stack[4] = {NULL, exc, val, tb}; + res = PyObject_Vectorcall(exit_func, stack + 1, + 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); + if (res == NULL) goto error; + STACK_GROW(1); + POKE(1, res); + DISPATCH(); + } + + TARGET(PUSH_EXC_INFO) { + PyObject *value = TOP(); + + _PyErr_StackItem *exc_info = tstate->exc_info; + if (exc_info->exc_value != NULL) { + SET_TOP(exc_info->exc_value); + } + else { + SET_TOP(Py_NewRef(Py_None)); + } + + PUSH(Py_NewRef(value)); + assert(PyExceptionInstance_Check(value)); + exc_info->exc_value = value; + DISPATCH(); + } + + TARGET(LOAD_ATTR_METHOD_WITH_VALUES) { + /* Cached method object */ + assert(cframe.use_tracing == 0); + PyObject *self = TOP(); + PyTypeObject *self_cls = Py_TYPE(self); + _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; + uint32_t type_version = read_u32(cache->type_version); + assert(type_version != 0); + DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); + assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); + PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self); + DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR); + PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls; + DEOPT_IF(self_heap_type->ht_cached_keys->dk_version != + read_u32(cache->keys_version), LOAD_ATTR); + STAT_INC(LOAD_ATTR, hit); + PyObject *res = read_obj(cache->descr); + assert(res != NULL); + assert(_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR)); + SET_TOP(Py_NewRef(res)); + PUSH(self); + JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + DISPATCH(); + } + + TARGET(LOAD_ATTR_METHOD_NO_DICT) { + assert(cframe.use_tracing == 0); + PyObject *self = TOP(); + PyTypeObject *self_cls = Py_TYPE(self); + _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; + uint32_t type_version = read_u32(cache->type_version); + DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); + assert(self_cls->tp_dictoffset == 0); + STAT_INC(LOAD_ATTR, hit); + PyObject *res = read_obj(cache->descr); + assert(res != NULL); + assert(_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR)); + SET_TOP(Py_NewRef(res)); + PUSH(self); + JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + DISPATCH(); + } + + TARGET(LOAD_ATTR_METHOD_LAZY_DICT) { + assert(cframe.use_tracing == 0); + PyObject *self = TOP(); + PyTypeObject *self_cls = Py_TYPE(self); + _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; + uint32_t type_version = read_u32(cache->type_version); + DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); + Py_ssize_t dictoffset = self_cls->tp_dictoffset; + assert(dictoffset > 0); + PyObject *dict = *(PyObject **)((char *)self + dictoffset); + /* This object has a __dict__, just not yet created */ + DEOPT_IF(dict != NULL, LOAD_ATTR); + STAT_INC(LOAD_ATTR, hit); + PyObject *res = read_obj(cache->descr); + assert(res != NULL); + assert(_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR)); + SET_TOP(Py_NewRef(res)); + PUSH(self); + JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); + DISPATCH(); + } + + TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { + DEOPT_IF(is_method(stack_pointer, oparg), CALL); + PyObject *function = PEEK(oparg + 1); + DEOPT_IF(Py_TYPE(function) != &PyMethod_Type, CALL); + STAT_INC(CALL, hit); + PyObject *self = ((PyMethodObject *)function)->im_self; + PEEK(oparg + 1) = Py_NewRef(self); + PyObject *meth = ((PyMethodObject *)function)->im_func; + PEEK(oparg + 2) = Py_NewRef(meth); + Py_DECREF(function); + GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); + } + + TARGET(KW_NAMES) { + assert(kwnames == NULL); + assert(oparg < PyTuple_GET_SIZE(consts)); + kwnames = GETITEM(consts, oparg); + DISPATCH(); + } + + TARGET(CALL) { + PREDICTED(CALL); + #if ENABLE_SPECIALIZATION + _PyCallCache *cache = (_PyCallCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + assert(cframe.use_tracing == 0); + int is_meth = is_method(stack_pointer, oparg); + int nargs = oparg + is_meth; + PyObject *callable = PEEK(nargs + 1); + next_instr--; + _Py_Specialize_Call(callable, next_instr, nargs, kwnames); + DISPATCH_SAME_OPARG(); + } + STAT_INC(CALL, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ + int total_args, is_meth; + is_meth = is_method(stack_pointer, oparg); + PyObject *function = PEEK(oparg + 1); + if (!is_meth && Py_TYPE(function) == &PyMethod_Type) { + PyObject *self = ((PyMethodObject *)function)->im_self; + PEEK(oparg+1) = Py_NewRef(self); + PyObject *meth = ((PyMethodObject *)function)->im_func; + PEEK(oparg+2) = Py_NewRef(meth); + Py_DECREF(function); + is_meth = 1; + } + total_args = oparg + is_meth; + function = PEEK(total_args + 1); + int positional_args = total_args - KWNAMES_LEN(); + // Check if the call can be inlined or not + if (Py_TYPE(function) == &PyFunction_Type && + tstate->interp->eval_frame == NULL && + ((PyFunctionObject *)function)->vectorcall == _PyFunction_Vectorcall) + { + int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(function))->co_flags; + PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(function)); + STACK_SHRINK(total_args); + _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( + tstate, (PyFunctionObject *)function, locals, + stack_pointer, positional_args, kwnames + ); + kwnames = NULL; + STACK_SHRINK(2-is_meth); + // The frame has stolen all the arguments from the stack, + // so there is no need to clean them up. + if (new_frame == NULL) { + goto error; + } + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + DISPATCH_INLINED(new_frame); + } + /* Callable is not a normal Python function */ + PyObject *res; + if (cframe.use_tracing) { + res = trace_call_function( + tstate, function, stack_pointer-total_args, + positional_args, kwnames); + } + else { + res = PyObject_Vectorcall( + function, stack_pointer-total_args, + positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, + kwnames); + } + kwnames = NULL; + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + Py_DECREF(function); + /* Clear the stack */ + STACK_SHRINK(total_args); + for (int i = 0; i < total_args; i++) { + Py_DECREF(stack_pointer[i]); + } + STACK_SHRINK(2-is_meth); + PUSH(res); + if (res == NULL) { + goto error; + } + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + CHECK_EVAL_BREAKER(); + DISPATCH(); + } + + TARGET(CALL_PY_EXACT_ARGS) { + PREDICTED(CALL_PY_EXACT_ARGS); + assert(kwnames == NULL); + DEOPT_IF(tstate->interp->eval_frame, CALL); + _PyCallCache *cache = (_PyCallCache *)next_instr; + int is_meth = is_method(stack_pointer, oparg); + int argcount = oparg + is_meth; + PyObject *callable = PEEK(argcount + 1); + DEOPT_IF(!PyFunction_Check(callable), CALL); + PyFunctionObject *func = (PyFunctionObject *)callable; + DEOPT_IF(func->func_version != read_u32(cache->func_version), CALL); + PyCodeObject *code = (PyCodeObject *)func->func_code; + DEOPT_IF(code->co_argcount != argcount, CALL); + DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); + STAT_INC(CALL, hit); + _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, func, argcount); + STACK_SHRINK(argcount); + for (int i = 0; i < argcount; i++) { + new_frame->localsplus[i] = stack_pointer[i]; + } + STACK_SHRINK(2-is_meth); + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + DISPATCH_INLINED(new_frame); + } + + TARGET(CALL_PY_WITH_DEFAULTS) { + assert(kwnames == NULL); + DEOPT_IF(tstate->interp->eval_frame, CALL); + _PyCallCache *cache = (_PyCallCache *)next_instr; + int is_meth = is_method(stack_pointer, oparg); + int argcount = oparg + is_meth; + PyObject *callable = PEEK(argcount + 1); + DEOPT_IF(!PyFunction_Check(callable), CALL); + PyFunctionObject *func = (PyFunctionObject *)callable; + DEOPT_IF(func->func_version != read_u32(cache->func_version), CALL); + PyCodeObject *code = (PyCodeObject *)func->func_code; + DEOPT_IF(argcount > code->co_argcount, CALL); + int minargs = cache->min_args; + DEOPT_IF(argcount < minargs, CALL); + DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); + STAT_INC(CALL, hit); + _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, func, code->co_argcount); + STACK_SHRINK(argcount); + for (int i = 0; i < argcount; i++) { + new_frame->localsplus[i] = stack_pointer[i]; + } + for (int i = argcount; i < code->co_argcount; i++) { + PyObject *def = PyTuple_GET_ITEM(func->func_defaults, + i - minargs); + new_frame->localsplus[i] = Py_NewRef(def); + } + STACK_SHRINK(2-is_meth); + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + DISPATCH_INLINED(new_frame); + } + + TARGET(CALL_NO_KW_TYPE_1) { + assert(kwnames == NULL); + assert(cframe.use_tracing == 0); + assert(oparg == 1); + DEOPT_IF(is_method(stack_pointer, 1), CALL); + PyObject *obj = TOP(); + PyObject *callable = SECOND(); + DEOPT_IF(callable != (PyObject *)&PyType_Type, CALL); + STAT_INC(CALL, hit); + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + PyObject *res = Py_NewRef(Py_TYPE(obj)); + Py_DECREF(callable); + Py_DECREF(obj); + STACK_SHRINK(2); + SET_TOP(res); + DISPATCH(); + } + + TARGET(CALL_NO_KW_STR_1) { + assert(kwnames == NULL); + assert(cframe.use_tracing == 0); + assert(oparg == 1); + DEOPT_IF(is_method(stack_pointer, 1), CALL); + PyObject *callable = PEEK(2); + DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, CALL); + STAT_INC(CALL, hit); + PyObject *arg = TOP(); + PyObject *res = PyObject_Str(arg); + Py_DECREF(arg); + Py_DECREF(&PyUnicode_Type); + STACK_SHRINK(2); + SET_TOP(res); + if (res == NULL) { + goto error; + } + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + CHECK_EVAL_BREAKER(); + DISPATCH(); + } + + TARGET(CALL_NO_KW_TUPLE_1) { + assert(kwnames == NULL); + assert(oparg == 1); + DEOPT_IF(is_method(stack_pointer, 1), CALL); + PyObject *callable = PEEK(2); + DEOPT_IF(callable != (PyObject *)&PyTuple_Type, CALL); + STAT_INC(CALL, hit); + PyObject *arg = TOP(); + PyObject *res = PySequence_Tuple(arg); + Py_DECREF(arg); + Py_DECREF(&PyTuple_Type); + STACK_SHRINK(2); + SET_TOP(res); + if (res == NULL) { + goto error; + } + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + CHECK_EVAL_BREAKER(); + DISPATCH(); + } + + TARGET(CALL_BUILTIN_CLASS) { + int is_meth = is_method(stack_pointer, oparg); + int total_args = oparg + is_meth; + int kwnames_len = KWNAMES_LEN(); + PyObject *callable = PEEK(total_args + 1); + DEOPT_IF(!PyType_Check(callable), CALL); + PyTypeObject *tp = (PyTypeObject *)callable; + DEOPT_IF(tp->tp_vectorcall == NULL, CALL); + STAT_INC(CALL, hit); + STACK_SHRINK(total_args); + PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer, + total_args-kwnames_len, kwnames); + kwnames = NULL; + /* Free the arguments. */ + for (int i = 0; i < total_args; i++) { + Py_DECREF(stack_pointer[i]); + } + Py_DECREF(tp); + STACK_SHRINK(1-is_meth); + SET_TOP(res); + if (res == NULL) { + goto error; + } + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + CHECK_EVAL_BREAKER(); + DISPATCH(); + } + + TARGET(CALL_NO_KW_BUILTIN_O) { + assert(cframe.use_tracing == 0); + /* Builtin METH_O functions */ + assert(kwnames == NULL); + int is_meth = is_method(stack_pointer, oparg); + int total_args = oparg + is_meth; + DEOPT_IF(total_args != 1, CALL); + PyObject *callable = PEEK(total_args + 1); + DEOPT_IF(!PyCFunction_CheckExact(callable), CALL); + DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_O, CALL); + STAT_INC(CALL, hit); + PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable); + // This is slower but CPython promises to check all non-vectorcall + // function calls. + if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) { + goto error; + } + PyObject *arg = TOP(); + PyObject *res = _PyCFunction_TrampolineCall(cfunc, PyCFunction_GET_SELF(callable), arg); + _Py_LeaveRecursiveCallTstate(tstate); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + + Py_DECREF(arg); + Py_DECREF(callable); + STACK_SHRINK(2-is_meth); + SET_TOP(res); + if (res == NULL) { + goto error; + } + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + CHECK_EVAL_BREAKER(); + DISPATCH(); + } + + TARGET(CALL_NO_KW_BUILTIN_FAST) { + assert(cframe.use_tracing == 0); + /* Builtin METH_FASTCALL functions, without keywords */ + assert(kwnames == NULL); + int is_meth = is_method(stack_pointer, oparg); + int total_args = oparg + is_meth; + PyObject *callable = PEEK(total_args + 1); + DEOPT_IF(!PyCFunction_CheckExact(callable), CALL); + DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_FASTCALL, + CALL); + STAT_INC(CALL, hit); + PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable); + STACK_SHRINK(total_args); + /* res = func(self, args, nargs) */ + PyObject *res = ((_PyCFunctionFast)(void(*)(void))cfunc)( + PyCFunction_GET_SELF(callable), + stack_pointer, + total_args); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + + /* Free the arguments. */ + for (int i = 0; i < total_args; i++) { + Py_DECREF(stack_pointer[i]); + } + STACK_SHRINK(2-is_meth); + PUSH(res); + Py_DECREF(callable); + if (res == NULL) { + /* Not deopting because this doesn't mean our optimization was + wrong. `res` can be NULL for valid reasons. Eg. getattr(x, + 'invalid'). In those cases an exception is set, so we must + handle it. + */ + goto error; + } + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + CHECK_EVAL_BREAKER(); + DISPATCH(); + } + + TARGET(CALL_BUILTIN_FAST_WITH_KEYWORDS) { + assert(cframe.use_tracing == 0); + /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ + int is_meth = is_method(stack_pointer, oparg); + int total_args = oparg + is_meth; + PyObject *callable = PEEK(total_args + 1); + DEOPT_IF(!PyCFunction_CheckExact(callable), CALL); + DEOPT_IF(PyCFunction_GET_FLAGS(callable) != + (METH_FASTCALL | METH_KEYWORDS), CALL); + STAT_INC(CALL, hit); + STACK_SHRINK(total_args); + /* res = func(self, args, nargs, kwnames) */ + _PyCFunctionFastWithKeywords cfunc = + (_PyCFunctionFastWithKeywords)(void(*)(void)) + PyCFunction_GET_FUNCTION(callable); + PyObject *res = cfunc( + PyCFunction_GET_SELF(callable), + stack_pointer, + total_args - KWNAMES_LEN(), + kwnames + ); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + kwnames = NULL; + + /* Free the arguments. */ + for (int i = 0; i < total_args; i++) { + Py_DECREF(stack_pointer[i]); + } + STACK_SHRINK(2-is_meth); + PUSH(res); + Py_DECREF(callable); + if (res == NULL) { + goto error; + } + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + CHECK_EVAL_BREAKER(); + DISPATCH(); + } + + TARGET(CALL_NO_KW_LEN) { + assert(cframe.use_tracing == 0); + assert(kwnames == NULL); + /* len(o) */ + int is_meth = is_method(stack_pointer, oparg); + int total_args = oparg + is_meth; + DEOPT_IF(total_args != 1, CALL); + PyObject *callable = PEEK(total_args + 1); + PyInterpreterState *interp = _PyInterpreterState_GET(); + DEOPT_IF(callable != interp->callable_cache.len, CALL); + STAT_INC(CALL, hit); + PyObject *arg = TOP(); + Py_ssize_t len_i = PyObject_Length(arg); + if (len_i < 0) { + goto error; + } + PyObject *res = PyLong_FromSsize_t(len_i); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + + STACK_SHRINK(2-is_meth); + SET_TOP(res); + Py_DECREF(callable); + Py_DECREF(arg); + if (res == NULL) { + goto error; + } + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + DISPATCH(); + } + + TARGET(CALL_NO_KW_ISINSTANCE) { + assert(cframe.use_tracing == 0); + assert(kwnames == NULL); + /* isinstance(o, o2) */ + int is_meth = is_method(stack_pointer, oparg); + int total_args = oparg + is_meth; + PyObject *callable = PEEK(total_args + 1); + DEOPT_IF(total_args != 2, CALL); + PyInterpreterState *interp = _PyInterpreterState_GET(); + DEOPT_IF(callable != interp->callable_cache.isinstance, CALL); + STAT_INC(CALL, hit); + PyObject *cls = POP(); + PyObject *inst = TOP(); + int retval = PyObject_IsInstance(inst, cls); + if (retval < 0) { + Py_DECREF(cls); + goto error; + } + PyObject *res = PyBool_FromLong(retval); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + + STACK_SHRINK(2-is_meth); + SET_TOP(res); + Py_DECREF(inst); + Py_DECREF(cls); + Py_DECREF(callable); + if (res == NULL) { + goto error; + } + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + DISPATCH(); + } + + TARGET(CALL_NO_KW_LIST_APPEND) { + assert(cframe.use_tracing == 0); + assert(kwnames == NULL); + assert(oparg == 1); + PyObject *callable = PEEK(3); + PyInterpreterState *interp = _PyInterpreterState_GET(); + DEOPT_IF(callable != interp->callable_cache.list_append, CALL); + PyObject *list = SECOND(); + DEOPT_IF(!PyList_Check(list), CALL); + STAT_INC(CALL, hit); + PyObject *arg = POP(); + if (_PyList_AppendTakeRef((PyListObject *)list, arg) < 0) { + goto error; + } + STACK_SHRINK(2); + Py_DECREF(list); + Py_DECREF(callable); + // CALL + POP_TOP + JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); + assert(_Py_OPCODE(next_instr[-1]) == POP_TOP); + DISPATCH(); + } + + TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { + assert(kwnames == NULL); + int is_meth = is_method(stack_pointer, oparg); + int total_args = oparg + is_meth; + PyMethodDescrObject *callable = + (PyMethodDescrObject *)PEEK(total_args + 1); + DEOPT_IF(total_args != 2, CALL); + DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); + PyMethodDef *meth = callable->d_method; + DEOPT_IF(meth->ml_flags != METH_O, CALL); + PyObject *arg = TOP(); + PyObject *self = SECOND(); + DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); + STAT_INC(CALL, hit); + PyCFunction cfunc = meth->ml_meth; + // This is slower but CPython promises to check all non-vectorcall + // function calls. + if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) { + goto error; + } + PyObject *res = _PyCFunction_TrampolineCall(cfunc, self, arg); + _Py_LeaveRecursiveCallTstate(tstate); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + Py_DECREF(self); + Py_DECREF(arg); + STACK_SHRINK(oparg + 1); + SET_TOP(res); + Py_DECREF(callable); + if (res == NULL) { + goto error; + } + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + CHECK_EVAL_BREAKER(); + DISPATCH(); + } + + TARGET(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS) { + int is_meth = is_method(stack_pointer, oparg); + int total_args = oparg + is_meth; + PyMethodDescrObject *callable = + (PyMethodDescrObject *)PEEK(total_args + 1); + DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); + PyMethodDef *meth = callable->d_method; + DEOPT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS), CALL); + PyTypeObject *d_type = callable->d_common.d_type; + PyObject *self = PEEK(total_args); + DEOPT_IF(!Py_IS_TYPE(self, d_type), CALL); + STAT_INC(CALL, hit); + int nargs = total_args-1; + STACK_SHRINK(nargs); + _PyCFunctionFastWithKeywords cfunc = + (_PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; + PyObject *res = cfunc(self, stack_pointer, nargs - KWNAMES_LEN(), + kwnames); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + kwnames = NULL; + + /* Free the arguments. */ + for (int i = 0; i < nargs; i++) { + Py_DECREF(stack_pointer[i]); + } + Py_DECREF(self); + STACK_SHRINK(2-is_meth); + SET_TOP(res); + Py_DECREF(callable); + if (res == NULL) { + goto error; + } + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + CHECK_EVAL_BREAKER(); + DISPATCH(); + } + + TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) { + assert(kwnames == NULL); + assert(oparg == 0 || oparg == 1); + int is_meth = is_method(stack_pointer, oparg); + int total_args = oparg + is_meth; + DEOPT_IF(total_args != 1, CALL); + PyMethodDescrObject *callable = (PyMethodDescrObject *)SECOND(); + DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); + PyMethodDef *meth = callable->d_method; + PyObject *self = TOP(); + DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); + DEOPT_IF(meth->ml_flags != METH_NOARGS, CALL); + STAT_INC(CALL, hit); + PyCFunction cfunc = meth->ml_meth; + // This is slower but CPython promises to check all non-vectorcall + // function calls. + if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) { + goto error; + } + PyObject *res = _PyCFunction_TrampolineCall(cfunc, self, NULL); + _Py_LeaveRecursiveCallTstate(tstate); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + Py_DECREF(self); + STACK_SHRINK(oparg + 1); + SET_TOP(res); + Py_DECREF(callable); + if (res == NULL) { + goto error; + } + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + CHECK_EVAL_BREAKER(); + DISPATCH(); + } + + TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_FAST) { + assert(kwnames == NULL); + int is_meth = is_method(stack_pointer, oparg); + int total_args = oparg + is_meth; + PyMethodDescrObject *callable = + (PyMethodDescrObject *)PEEK(total_args + 1); + /* Builtin METH_FASTCALL methods, without keywords */ + DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); + PyMethodDef *meth = callable->d_method; + DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL); + PyObject *self = PEEK(total_args); + DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); + STAT_INC(CALL, hit); + _PyCFunctionFast cfunc = + (_PyCFunctionFast)(void(*)(void))meth->ml_meth; + int nargs = total_args-1; + STACK_SHRINK(nargs); + PyObject *res = cfunc(self, stack_pointer, nargs); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + /* Clear the stack of the arguments. */ + for (int i = 0; i < nargs; i++) { + Py_DECREF(stack_pointer[i]); + } + Py_DECREF(self); + STACK_SHRINK(2-is_meth); + SET_TOP(res); + Py_DECREF(callable); + if (res == NULL) { + goto error; + } + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + CHECK_EVAL_BREAKER(); + DISPATCH(); + } + + TARGET(CALL_FUNCTION_EX) { + PREDICTED(CALL_FUNCTION_EX); + PyObject *func, *callargs, *kwargs = NULL, *result; + if (oparg & 0x01) { + kwargs = POP(); + // DICT_MERGE is called before this opcode if there are kwargs. + // It converts all dict subtypes in kwargs into regular dicts. + assert(PyDict_CheckExact(kwargs)); + } + callargs = POP(); + func = TOP(); + if (!PyTuple_CheckExact(callargs)) { + if (check_args_iterable(tstate, func, callargs) < 0) { + Py_DECREF(callargs); + goto error; + } + Py_SETREF(callargs, PySequence_Tuple(callargs)); + if (callargs == NULL) { + goto error; + } + } + assert(PyTuple_CheckExact(callargs)); + + result = do_call_core(tstate, func, callargs, kwargs, cframe.use_tracing); + Py_DECREF(func); + Py_DECREF(callargs); + Py_XDECREF(kwargs); + + STACK_SHRINK(1); + assert(TOP() == NULL); + SET_TOP(result); + if (result == NULL) { + goto error; + } + CHECK_EVAL_BREAKER(); + DISPATCH(); + } + + TARGET(MAKE_FUNCTION) { + PyObject *codeobj = POP(); + PyFunctionObject *func = (PyFunctionObject *) + PyFunction_New(codeobj, GLOBALS()); + + Py_DECREF(codeobj); + if (func == NULL) { + goto error; + } + + if (oparg & 0x08) { + assert(PyTuple_CheckExact(TOP())); + func->func_closure = POP(); + } + if (oparg & 0x04) { + assert(PyTuple_CheckExact(TOP())); + func->func_annotations = POP(); + } + if (oparg & 0x02) { + assert(PyDict_CheckExact(TOP())); + func->func_kwdefaults = POP(); + } + if (oparg & 0x01) { + assert(PyTuple_CheckExact(TOP())); + func->func_defaults = POP(); + } + + func->func_version = ((PyCodeObject *)codeobj)->co_version; + PUSH((PyObject *)func); + DISPATCH(); + } + + TARGET(RETURN_GENERATOR) { + assert(PyFunction_Check(frame->f_funcobj)); + PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; + PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); + if (gen == NULL) { + goto error; + } + assert(EMPTY()); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; + _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); + assert(frame != &entry_frame); + _PyInterpreterFrame *prev = frame->previous; + _PyThreadState_PopFrame(tstate, frame); + frame = cframe.current_frame = prev; + _PyFrame_StackPush(frame, (PyObject *)gen); + goto resume_frame; + } + + TARGET(BUILD_SLICE) { + PyObject *start, *stop, *step, *slice; + if (oparg == 3) + step = POP(); + else + step = NULL; + stop = POP(); + start = TOP(); + slice = PySlice_New(start, stop, step); + Py_DECREF(start); + Py_DECREF(stop); + Py_XDECREF(step); + SET_TOP(slice); + if (slice == NULL) + goto error; + DISPATCH(); + } + + TARGET(FORMAT_VALUE) { + /* Handles f-string value formatting. */ + PyObject *result; + PyObject *fmt_spec; + PyObject *value; + PyObject *(*conv_fn)(PyObject *); + int which_conversion = oparg & FVC_MASK; + int have_fmt_spec = (oparg & FVS_MASK) == FVS_HAVE_SPEC; + + fmt_spec = have_fmt_spec ? POP() : NULL; + value = POP(); + + /* See if any conversion is specified. */ + switch (which_conversion) { + case FVC_NONE: conv_fn = NULL; break; + case FVC_STR: conv_fn = PyObject_Str; break; + case FVC_REPR: conv_fn = PyObject_Repr; break; + case FVC_ASCII: conv_fn = PyObject_ASCII; break; + default: + _PyErr_Format(tstate, PyExc_SystemError, + "unexpected conversion flag %d", + which_conversion); + goto error; + } + + /* If there's a conversion function, call it and replace + value with that result. Otherwise, just use value, + without conversion. */ + if (conv_fn != NULL) { + result = conv_fn(value); + Py_DECREF(value); + if (result == NULL) { + Py_XDECREF(fmt_spec); + goto error; + } + value = result; + } + + /* If value is a unicode object, and there's no fmt_spec, + then we know the result of format(value) is value + itself. In that case, skip calling format(). I plan to + move this optimization in to PyObject_Format() + itself. */ + if (PyUnicode_CheckExact(value) && fmt_spec == NULL) { + /* Do nothing, just transfer ownership to result. */ + result = value; + } else { + /* Actually call format(). */ + result = PyObject_Format(value, fmt_spec); + Py_DECREF(value); + Py_XDECREF(fmt_spec); + if (result == NULL) { + goto error; + } + } + + PUSH(result); + DISPATCH(); + } + + TARGET(COPY) { + assert(oparg != 0); + PyObject *peek = PEEK(oparg); + PUSH(Py_NewRef(peek)); + DISPATCH(); + } + + TARGET(BINARY_OP) { + PREDICTED(BINARY_OP); + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); + PyObject *rhs = PEEK(1); + PyObject *lhs = PEEK(2); + PyObject *res; + #if ENABLE_SPECIALIZATION + _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + assert(cframe.use_tracing == 0); + next_instr--; + _Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, &GETLOCAL(0)); + DISPATCH_SAME_OPARG(); + } + STAT_INC(BINARY_OP, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ + assert(0 <= oparg); + assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); + assert(binary_ops[oparg]); + res = binary_ops[oparg](lhs, rhs); + Py_DECREF(lhs); + Py_DECREF(rhs); + if (res == NULL) goto pop_2_error; + STACK_SHRINK(1); + POKE(1, res); + JUMPBY(1); + DISPATCH(); + } + + TARGET(SWAP) { + assert(oparg != 0); + PyObject *top = TOP(); + SET_TOP(PEEK(oparg)); + PEEK(oparg) = top; + DISPATCH(); + } + + TARGET(EXTENDED_ARG) { + assert(oparg); + assert(cframe.use_tracing == 0); + opcode = _Py_OPCODE(*next_instr); + oparg = oparg << 8 | _Py_OPARG(*next_instr); + PRE_DISPATCH_GOTO(); + DISPATCH_GOTO(); + } + + TARGET(CACHE) { + Py_UNREACHABLE(); + } diff --git a/Python/opcode_metadata_tier2.h b/Python/opcode_metadata_tier2.h new file mode 100644 index 00000000000000..d7f86246e8f571 --- /dev/null +++ b/Python/opcode_metadata_tier2.h @@ -0,0 +1,883 @@ +// This file is generated by Tools\cases_generator\generate_cases.py --metadata +// from Python\bytecodes.c +// Do not edit! + +#ifndef NDEBUG +static int +_PyOpcode_num_popped(int opcode, int oparg) { + switch(opcode) { + case NOP: + return 0; + case RESUME: + return 0; + case LOAD_CLOSURE: + return 0; + case LOAD_FAST_CHECK: + return 0; + case LOAD_FAST: + return 0; + case LOAD_CONST: + return 0; + case STORE_FAST: + return 1; + case LOAD_FAST__LOAD_FAST: + return 0+0; + case LOAD_FAST__LOAD_CONST: + return 0+0; + case STORE_FAST__LOAD_FAST: + return 1+0; + case STORE_FAST__STORE_FAST: + return 1+1; + case LOAD_CONST__LOAD_FAST: + return 0+0; + case POP_TOP: + return 1; + case PUSH_NULL: + return 0; + case END_FOR: + return 1+1; + case UNARY_NEGATIVE: + return 1; + case UNARY_NOT: + return 1; + case UNARY_INVERT: + return 1; + case BINARY_OP_MULTIPLY_INT: + return 2; + case BINARY_OP_MULTIPLY_FLOAT: + return 2; + case BINARY_OP_SUBTRACT_INT: + return 2; + case BINARY_OP_SUBTRACT_FLOAT: + return 2; + case BINARY_OP_ADD_UNICODE: + return 2; + case BINARY_OP_INPLACE_ADD_UNICODE: + return 2; + case BINARY_OP_ADD_FLOAT: + return 2; + case BINARY_OP_ADD_INT_TYPE_CHECK: + return 2; + case BINARY_OP_ADD_INST_REST: + return 2; + case BINARY_OP_ADD_INT: + return 2; + case BINARY_SUBSCR: + return 2; + case BINARY_SLICE: + return 3; + case STORE_SLICE: + return 4; + case BINARY_SUBSCR_LIST_INT: + return 2; + case BINARY_SUBSCR_TUPLE_INT: + return 2; + case BINARY_SUBSCR_DICT: + return 2; + case BINARY_SUBSCR_GETITEM: + return 2; + case LIST_APPEND: + return (oparg-1) + 2; + case SET_ADD: + return (oparg-1) + 2; + case STORE_SUBSCR: + return 3; + case STORE_SUBSCR_LIST_INT: + return 3; + case STORE_SUBSCR_DICT: + return 3; + case DELETE_SUBSCR: + return 2; + case CALL_INTRINSIC_1: + return 1; + case RAISE_VARARGS: + return oparg; + case INTERPRETER_EXIT: + return 1; + case RETURN_VALUE: + return 1; + case GET_AITER: + return 1; + case GET_ANEXT: + return 1; + case GET_AWAITABLE: + return 1; + case SEND: + return -1; + case YIELD_VALUE: + return 1; + case POP_EXCEPT: + return 1; + case RERAISE: + return -1; + case PREP_RERAISE_STAR: + return 2; + case END_ASYNC_FOR: + return -1; + case CLEANUP_THROW: + return -1; + case LOAD_ASSERTION_ERROR: + return 0; + case LOAD_BUILD_CLASS: + return 0; + case STORE_NAME: + return 1; + case DELETE_NAME: + return 0; + case UNPACK_SEQUENCE: + return -1; + case UNPACK_SEQUENCE_TWO_TUPLE: + return -1; + case UNPACK_SEQUENCE_TUPLE: + return -1; + case UNPACK_SEQUENCE_LIST: + return -1; + case UNPACK_EX: + return -1; + case STORE_ATTR: + return 2; + case DELETE_ATTR: + return 1; + case STORE_GLOBAL: + return 1; + case DELETE_GLOBAL: + return 0; + case LOAD_NAME: + return 0; + case LOAD_GLOBAL: + return -1; + case LOAD_GLOBAL_MODULE: + return -1; + case LOAD_GLOBAL_BUILTIN: + return -1; + case DELETE_FAST: + return 0; + case MAKE_CELL: + return 0; + case DELETE_DEREF: + return 0; + case LOAD_CLASSDEREF: + return 0; + case LOAD_DEREF: + return 0; + case STORE_DEREF: + return 1; + case COPY_FREE_VARS: + return 0; + case BUILD_STRING: + return oparg; + case BUILD_TUPLE: + return oparg; + case BUILD_LIST: + return oparg; + case LIST_EXTEND: + return (oparg-1) + 2; + case SET_UPDATE: + return (oparg-1) + 2; + case BUILD_SET: + return oparg; + case BUILD_MAP: + return oparg*2; + case SETUP_ANNOTATIONS: + return 0; + case BUILD_CONST_KEY_MAP: + return oparg + 1; + case DICT_UPDATE: + return 1; + case DICT_MERGE: + return 1; + case MAP_ADD: + return 2; + case LOAD_ATTR: + return -1; + case LOAD_ATTR_INSTANCE_VALUE: + return -1; + case LOAD_ATTR_MODULE: + return -1; + case LOAD_ATTR_WITH_HINT: + return -1; + case LOAD_ATTR_SLOT: + return -1; + case LOAD_ATTR_CLASS: + return -1; + case LOAD_ATTR_PROPERTY: + return -1; + case LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN: + return -1; + case STORE_ATTR_INSTANCE_VALUE: + return 2; + case STORE_ATTR_WITH_HINT: + return 2; + case STORE_ATTR_SLOT: + return 2; + case COMPARE_OP: + return 2; + case COMPARE_AND_BRANCH: + return 2; + case COMPARE_AND_BRANCH_FLOAT: + return 2; + case COMPARE_AND_BRANCH_INT: + return 2; + case COMPARE_AND_BRANCH_STR: + return 2; + case IS_OP: + return 2; + case CONTAINS_OP: + return 2; + case CHECK_EG_MATCH: + return 2; + case CHECK_EXC_MATCH: + return 2; + case IMPORT_NAME: + return 2; + case IMPORT_FROM: + return 1; + case JUMP_FORWARD: + return 0; + case JUMP_BACKWARD: + return 0; + case POP_JUMP_IF_FALSE: + return -1; + case POP_JUMP_IF_TRUE: + return -1; + case POP_JUMP_IF_NOT_NONE: + return -1; + case POP_JUMP_IF_NONE: + return -1; + case JUMP_IF_FALSE_OR_POP: + return -1; + case JUMP_IF_TRUE_OR_POP: + return -1; + case JUMP_BACKWARD_NO_INTERRUPT: + return -1; + case GET_LEN: + return -1; + case MATCH_CLASS: + return 3; + case MATCH_MAPPING: + return 1; + case MATCH_SEQUENCE: + return 1; + case MATCH_KEYS: + return 2; + case GET_ITER: + return -1; + case GET_YIELD_FROM_ITER: + return -1; + case FOR_ITER: + return -1; + case FOR_ITER_LIST: + return -1; + case FOR_ITER_TUPLE: + return -1; + case FOR_ITER_RANGE: + return -1; + case FOR_ITER_GEN: + return -1; + case BEFORE_ASYNC_WITH: + return -1; + case BEFORE_WITH: + return -1; + case WITH_EXCEPT_START: + return 4; + case PUSH_EXC_INFO: + return -1; + case LOAD_ATTR_METHOD_WITH_VALUES: + return -1; + case LOAD_ATTR_METHOD_NO_DICT: + return -1; + case LOAD_ATTR_METHOD_LAZY_DICT: + return -1; + case CALL_BOUND_METHOD_EXACT_ARGS: + return -1; + case KW_NAMES: + return -1; + case CALL: + return -1; + case CALL_PY_EXACT_ARGS: + return -1; + case CALL_PY_WITH_DEFAULTS: + return -1; + case CALL_NO_KW_TYPE_1: + return -1; + case CALL_NO_KW_STR_1: + return -1; + case CALL_NO_KW_TUPLE_1: + return -1; + case CALL_BUILTIN_CLASS: + return -1; + case CALL_NO_KW_BUILTIN_O: + return -1; + case CALL_NO_KW_BUILTIN_FAST: + return -1; + case CALL_BUILTIN_FAST_WITH_KEYWORDS: + return -1; + case CALL_NO_KW_LEN: + return -1; + case CALL_NO_KW_ISINSTANCE: + return -1; + case CALL_NO_KW_LIST_APPEND: + return -1; + case CALL_NO_KW_METHOD_DESCRIPTOR_O: + return -1; + case CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: + return -1; + case CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS: + return -1; + case CALL_NO_KW_METHOD_DESCRIPTOR_FAST: + return -1; + case CALL_FUNCTION_EX: + return -1; + case MAKE_FUNCTION: + return -1; + case RETURN_GENERATOR: + return -1; + case BUILD_SLICE: + return -1; + case FORMAT_VALUE: + return -1; + case COPY: + return -1; + case BINARY_OP: + return 2; + case SWAP: + return -1; + case EXTENDED_ARG: + return -1; + case CACHE: + return -1; + default: + Py_UNREACHABLE(); + } +} +#endif + +#ifndef NDEBUG +static int +_PyOpcode_num_pushed(int opcode, int oparg) { + switch(opcode) { + case NOP: + return 0; + case RESUME: + return 0; + case LOAD_CLOSURE: + return 1; + case LOAD_FAST_CHECK: + return 1; + case LOAD_FAST: + return 1; + case LOAD_CONST: + return 1; + case STORE_FAST: + return 0; + case LOAD_FAST__LOAD_FAST: + return 1+1; + case LOAD_FAST__LOAD_CONST: + return 1+1; + case STORE_FAST__LOAD_FAST: + return 0+1; + case STORE_FAST__STORE_FAST: + return 0+0; + case LOAD_CONST__LOAD_FAST: + return 1+1; + case POP_TOP: + return 0; + case PUSH_NULL: + return 1; + case END_FOR: + return 0+0; + case UNARY_NEGATIVE: + return 1; + case UNARY_NOT: + return 1; + case UNARY_INVERT: + return 1; + case BINARY_OP_MULTIPLY_INT: + return 1; + case BINARY_OP_MULTIPLY_FLOAT: + return 1; + case BINARY_OP_SUBTRACT_INT: + return 1; + case BINARY_OP_SUBTRACT_FLOAT: + return 1; + case BINARY_OP_ADD_UNICODE: + return 1; + case BINARY_OP_INPLACE_ADD_UNICODE: + return 0; + case BINARY_OP_ADD_FLOAT: + return 1; + case BINARY_OP_ADD_INT_TYPE_CHECK: + return 2; + case BINARY_OP_ADD_INST_REST: + return 1; + case BINARY_OP_ADD_INT: + return 1; + case BINARY_SUBSCR: + return 1; + case BINARY_SLICE: + return 1; + case STORE_SLICE: + return 0; + case BINARY_SUBSCR_LIST_INT: + return 1; + case BINARY_SUBSCR_TUPLE_INT: + return 1; + case BINARY_SUBSCR_DICT: + return 1; + case BINARY_SUBSCR_GETITEM: + return 1; + case LIST_APPEND: + return (oparg-1) + 1; + case SET_ADD: + return (oparg-1) + 1; + case STORE_SUBSCR: + return 0; + case STORE_SUBSCR_LIST_INT: + return 0; + case STORE_SUBSCR_DICT: + return 0; + case DELETE_SUBSCR: + return 0; + case CALL_INTRINSIC_1: + return 1; + case RAISE_VARARGS: + return 0; + case INTERPRETER_EXIT: + return 0; + case RETURN_VALUE: + return 0; + case GET_AITER: + return 1; + case GET_ANEXT: + return 2; + case GET_AWAITABLE: + return 1; + case SEND: + return -1; + case YIELD_VALUE: + return 1; + case POP_EXCEPT: + return 0; + case RERAISE: + return -1; + case PREP_RERAISE_STAR: + return 1; + case END_ASYNC_FOR: + return -1; + case CLEANUP_THROW: + return -1; + case LOAD_ASSERTION_ERROR: + return 1; + case LOAD_BUILD_CLASS: + return 1; + case STORE_NAME: + return 0; + case DELETE_NAME: + return 0; + case UNPACK_SEQUENCE: + return -1; + case UNPACK_SEQUENCE_TWO_TUPLE: + return -1; + case UNPACK_SEQUENCE_TUPLE: + return -1; + case UNPACK_SEQUENCE_LIST: + return -1; + case UNPACK_EX: + return -1; + case STORE_ATTR: + return 0; + case DELETE_ATTR: + return 0; + case STORE_GLOBAL: + return 0; + case DELETE_GLOBAL: + return 0; + case LOAD_NAME: + return 1; + case LOAD_GLOBAL: + return -1; + case LOAD_GLOBAL_MODULE: + return -1; + case LOAD_GLOBAL_BUILTIN: + return -1; + case DELETE_FAST: + return 0; + case MAKE_CELL: + return 0; + case DELETE_DEREF: + return 0; + case LOAD_CLASSDEREF: + return 1; + case LOAD_DEREF: + return 1; + case STORE_DEREF: + return 0; + case COPY_FREE_VARS: + return 0; + case BUILD_STRING: + return 1; + case BUILD_TUPLE: + return 1; + case BUILD_LIST: + return 1; + case LIST_EXTEND: + return (oparg-1) + 1; + case SET_UPDATE: + return (oparg-1) + 1; + case BUILD_SET: + return 1; + case BUILD_MAP: + return 1; + case SETUP_ANNOTATIONS: + return 0; + case BUILD_CONST_KEY_MAP: + return 1; + case DICT_UPDATE: + return 0; + case DICT_MERGE: + return 0; + case MAP_ADD: + return 0; + case LOAD_ATTR: + return -1; + case LOAD_ATTR_INSTANCE_VALUE: + return -1; + case LOAD_ATTR_MODULE: + return -1; + case LOAD_ATTR_WITH_HINT: + return -1; + case LOAD_ATTR_SLOT: + return -1; + case LOAD_ATTR_CLASS: + return -1; + case LOAD_ATTR_PROPERTY: + return -1; + case LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN: + return -1; + case STORE_ATTR_INSTANCE_VALUE: + return 0; + case STORE_ATTR_WITH_HINT: + return 0; + case STORE_ATTR_SLOT: + return 0; + case COMPARE_OP: + return 1; + case COMPARE_AND_BRANCH: + return 0; + case COMPARE_AND_BRANCH_FLOAT: + return 0; + case COMPARE_AND_BRANCH_INT: + return 0; + case COMPARE_AND_BRANCH_STR: + return 0; + case IS_OP: + return 1; + case CONTAINS_OP: + return 1; + case CHECK_EG_MATCH: + return 2; + case CHECK_EXC_MATCH: + return 2; + case IMPORT_NAME: + return 1; + case IMPORT_FROM: + return 2; + case JUMP_FORWARD: + return 0; + case JUMP_BACKWARD: + return 0; + case POP_JUMP_IF_FALSE: + return -1; + case POP_JUMP_IF_TRUE: + return -1; + case POP_JUMP_IF_NOT_NONE: + return -1; + case POP_JUMP_IF_NONE: + return -1; + case JUMP_IF_FALSE_OR_POP: + return -1; + case JUMP_IF_TRUE_OR_POP: + return -1; + case JUMP_BACKWARD_NO_INTERRUPT: + return -1; + case GET_LEN: + return -1; + case MATCH_CLASS: + return 1; + case MATCH_MAPPING: + return 2; + case MATCH_SEQUENCE: + return 2; + case MATCH_KEYS: + return 3; + case GET_ITER: + return -1; + case GET_YIELD_FROM_ITER: + return -1; + case FOR_ITER: + return -1; + case FOR_ITER_LIST: + return -1; + case FOR_ITER_TUPLE: + return -1; + case FOR_ITER_RANGE: + return -1; + case FOR_ITER_GEN: + return -1; + case BEFORE_ASYNC_WITH: + return -1; + case BEFORE_WITH: + return -1; + case WITH_EXCEPT_START: + return 5; + case PUSH_EXC_INFO: + return -1; + case LOAD_ATTR_METHOD_WITH_VALUES: + return -1; + case LOAD_ATTR_METHOD_NO_DICT: + return -1; + case LOAD_ATTR_METHOD_LAZY_DICT: + return -1; + case CALL_BOUND_METHOD_EXACT_ARGS: + return -1; + case KW_NAMES: + return -1; + case CALL: + return -1; + case CALL_PY_EXACT_ARGS: + return -1; + case CALL_PY_WITH_DEFAULTS: + return -1; + case CALL_NO_KW_TYPE_1: + return -1; + case CALL_NO_KW_STR_1: + return -1; + case CALL_NO_KW_TUPLE_1: + return -1; + case CALL_BUILTIN_CLASS: + return -1; + case CALL_NO_KW_BUILTIN_O: + return -1; + case CALL_NO_KW_BUILTIN_FAST: + return -1; + case CALL_BUILTIN_FAST_WITH_KEYWORDS: + return -1; + case CALL_NO_KW_LEN: + return -1; + case CALL_NO_KW_ISINSTANCE: + return -1; + case CALL_NO_KW_LIST_APPEND: + return -1; + case CALL_NO_KW_METHOD_DESCRIPTOR_O: + return -1; + case CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: + return -1; + case CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS: + return -1; + case CALL_NO_KW_METHOD_DESCRIPTOR_FAST: + return -1; + case CALL_FUNCTION_EX: + return -1; + case MAKE_FUNCTION: + return -1; + case RETURN_GENERATOR: + return -1; + case BUILD_SLICE: + return -1; + case FORMAT_VALUE: + return -1; + case COPY: + return -1; + case BINARY_OP: + return 1; + case SWAP: + return -1; + case EXTENDED_ARG: + return -1; + case CACHE: + return -1; + default: + Py_UNREACHABLE(); + } +} +#endif +enum Direction { DIR_NONE, DIR_READ, DIR_WRITE }; +enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC0, INSTR_FMT_IBC000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; +struct opcode_metadata { + enum Direction dir_op1; + enum Direction dir_op2; + enum Direction dir_op3; + bool valid_entry; + enum InstructionFormat instr_format; +} _PyOpcode_opcode_metadata[256] = { + [NOP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [RESUME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_CLOSURE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_FAST_CHECK] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_CONST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [STORE_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_FAST__LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, + [LOAD_FAST__LOAD_CONST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, + [STORE_FAST__LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, + [STORE_FAST__STORE_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, + [LOAD_CONST__LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, + [POP_TOP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [PUSH_NULL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [END_FOR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [UNARY_NEGATIVE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [UNARY_NOT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [UNARY_INVERT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [BINARY_OP_MULTIPLY_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, + [BINARY_OP_MULTIPLY_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, + [BINARY_OP_SUBTRACT_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, + [BINARY_OP_SUBTRACT_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, + [BINARY_OP_ADD_UNICODE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, + [BINARY_OP_INPLACE_ADD_UNICODE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [BINARY_OP_ADD_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, + [BINARY_OP_ADD_INT_TYPE_CHECK] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, + [BINARY_OP_ADD_INST_REST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, + [BINARY_OP_ADD_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, + [BINARY_SUBSCR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, + [BINARY_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [STORE_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [BINARY_SUBSCR_LIST_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, + [BINARY_SUBSCR_TUPLE_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, + [BINARY_SUBSCR_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, + [BINARY_SUBSCR_GETITEM] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, + [LIST_APPEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [SET_ADD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [STORE_SUBSCR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, + [STORE_SUBSCR_LIST_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, + [STORE_SUBSCR_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, + [DELETE_SUBSCR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [CALL_INTRINSIC_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [RAISE_VARARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [INTERPRETER_EXIT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [RETURN_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [GET_AITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [GET_ANEXT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [GET_AWAITABLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [SEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [YIELD_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [POP_EXCEPT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [RERAISE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [PREP_RERAISE_STAR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [END_ASYNC_FOR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [CLEANUP_THROW] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [LOAD_ASSERTION_ERROR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [LOAD_BUILD_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [STORE_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [DELETE_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [UNPACK_SEQUENCE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [UNPACK_SEQUENCE_TWO_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [UNPACK_SEQUENCE_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [UNPACK_SEQUENCE_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [UNPACK_EX] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [STORE_ATTR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, + [DELETE_ATTR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [STORE_GLOBAL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [DELETE_GLOBAL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_GLOBAL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_GLOBAL_MODULE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_GLOBAL_BUILTIN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [DELETE_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [MAKE_CELL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [DELETE_DEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_CLASSDEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_DEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [STORE_DEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [COPY_FREE_VARS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [BUILD_STRING] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [BUILD_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [BUILD_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LIST_EXTEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [SET_UPDATE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [BUILD_SET] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [BUILD_MAP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [SETUP_ANNOTATIONS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [BUILD_CONST_KEY_MAP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [DICT_UPDATE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [DICT_MERGE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [MAP_ADD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_ATTR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_ATTR_INSTANCE_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_ATTR_MODULE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_ATTR_WITH_HINT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_ATTR_SLOT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_ATTR_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_ATTR_PROPERTY] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [STORE_ATTR_INSTANCE_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, + [STORE_ATTR_WITH_HINT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, + [STORE_ATTR_SLOT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, + [COMPARE_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, + [COMPARE_AND_BRANCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, + [COMPARE_AND_BRANCH_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, + [COMPARE_AND_BRANCH_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, + [COMPARE_AND_BRANCH_STR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, + [IS_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CONTAINS_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CHECK_EG_MATCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [CHECK_EXC_MATCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [IMPORT_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [IMPORT_FROM] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [JUMP_FORWARD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [JUMP_BACKWARD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [POP_JUMP_IF_FALSE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [POP_JUMP_IF_TRUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [POP_JUMP_IF_NOT_NONE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [POP_JUMP_IF_NONE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [JUMP_IF_FALSE_OR_POP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [JUMP_IF_TRUE_OR_POP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [JUMP_BACKWARD_NO_INTERRUPT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [GET_LEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [MATCH_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [MATCH_MAPPING] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [MATCH_SEQUENCE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [MATCH_KEYS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [GET_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [GET_YIELD_FROM_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [FOR_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [FOR_ITER_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [FOR_ITER_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [FOR_ITER_RANGE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [FOR_ITER_GEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [BEFORE_ASYNC_WITH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [BEFORE_WITH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [WITH_EXCEPT_START] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [PUSH_EXC_INFO] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [LOAD_ATTR_METHOD_WITH_VALUES] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [LOAD_ATTR_METHOD_NO_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [LOAD_ATTR_METHOD_LAZY_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [CALL_BOUND_METHOD_EXACT_ARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [KW_NAMES] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CALL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CALL_PY_EXACT_ARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CALL_PY_WITH_DEFAULTS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CALL_NO_KW_TYPE_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CALL_NO_KW_STR_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CALL_NO_KW_TUPLE_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CALL_BUILTIN_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CALL_NO_KW_BUILTIN_O] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CALL_NO_KW_BUILTIN_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CALL_NO_KW_LEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CALL_NO_KW_ISINSTANCE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CALL_NO_KW_LIST_APPEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CALL_NO_KW_METHOD_DESCRIPTOR_O] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CALL_FUNCTION_EX] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [MAKE_FUNCTION] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [RETURN_GENERATOR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [BUILD_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [FORMAT_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [COPY] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [BINARY_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, + [SWAP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [EXTENDED_ARG] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [CACHE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, +}; diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 9d894d2ff57455..0487c6ac02839d 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -12,6 +12,8 @@ import sys import typing +from enum import Enum, auto + import parser from parser import StackEffect @@ -20,10 +22,19 @@ THIS = os.path.relpath(__file__, ROOT) DEFAULT_INPUT = os.path.relpath(os.path.join(ROOT, "Python/bytecodes.c")) + +# Tier 1 interpreter DEFAULT_OUTPUT = os.path.relpath(os.path.join(ROOT, "Python/generated_cases.c.h")) DEFAULT_METADATA_OUTPUT = os.path.relpath( os.path.join(ROOT, "Python/opcode_metadata.h") ) + +# Tier 2 interpreter +TIER2_OUTPUT = os.path.relpath(os.path.join(ROOT, "Python/generated_cases_tier2.c.h")) +TIER2_METADATA_OUTPUT = os.path.relpath( + os.path.join(ROOT, "Python/opcode_metadata_tier2.h") +) + BEGIN_MARKER = "// BEGIN BYTECODES //" END_MARKER = "// END BYTECODES //" RE_PREDICTED = r"^\s*(?:PREDICT\(|GO_TO_INSTRUCTION\(|DEOPT_IF\(.*?,\s*)(\w+)\);\s*(?://.*)?$" @@ -48,6 +59,11 @@ ) +class InterpreterTier(Enum): + TIER1 = auto() + TIER2 = auto() + + def effect_size(effect: StackEffect) -> tuple[int, str]: """Return the 'size' impact of a stack effect. @@ -102,17 +118,19 @@ class Formatter: stream: typing.TextIO prefix: str + postfix: str def __init__(self, stream: typing.TextIO, indent: int) -> None: self.stream = stream self.prefix = " " * indent + self.postfix = "" def write_raw(self, s: str) -> None: self.stream.write(s) def emit(self, arg: str) -> None: if arg: - self.write_raw(f"{self.prefix}{arg}\n") + self.write_raw(f"{self.prefix}{arg}{self.postfix}\n") else: self.write_raw("\n") @@ -185,7 +203,7 @@ class Instruction: # Parts of the underlying instruction definition inst: parser.InstDef register: bool - kind: typing.Literal["inst", "op", "legacy"] # Legacy means no (input -- output) + kind: parser.INST_KINDS name: str block: parser.Block block_text: list[str] # Block.text, less curlies, less PREDICT() calls @@ -377,7 +395,7 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None f"{extra}{space}if ({cond}) {{ STACK_SHRINK({symbolic}); goto {label}; }}\n" ) else: - out.write_raw(f"{extra}{space}if ({cond}) goto {label};\n") + out.write_raw(f"{extra}{space}if ({cond}) goto {label};{out.postfix}\n") elif m := re.match(r"(\s*)DECREF_INPUTS\(\);\s*(?://.*)?$", line): if not self.register: space = m.group(1) @@ -385,7 +403,7 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None if ieff.name not in self.unmoved_names: out.write_raw(f"{extra}{space}Py_DECREF({ieff.name});\n") else: - out.write_raw(extra + line) + out.write_raw(extra + line.rstrip("\n") + out.postfix + "\n") InstructionOrCacheEffect = Instruction | parser.CacheEffect @@ -446,13 +464,15 @@ class Analyzer: filename: str output_filename: str + tier: InterpreterTier src: str errors: int = 0 - def __init__(self, filename: str, output_filename: str): + def __init__(self, filename: str, output_filename: str, tier: InterpreterTier): """Read the input file.""" self.filename = filename self.output_filename = output_filename + self.tier = tier with open(filename) as f: self.src = f.read() @@ -897,12 +917,32 @@ def write_instructions(self) -> None: n_instrs = 0 n_supers = 0 n_macros = 0 + + # Single pass to hoist all the u_instructions to the top. + if self.tier == InterpreterTier.TIER1: + for thing in self.everything: + match thing: + case parser.InstDef(): + if thing.kind == "u_inst": + self.write_u_inst_as_c_macro( + self.instrs[thing.name]) + case _: + pass + + # Everything else for thing in self.everything: match thing: case parser.InstDef(): - if thing.kind != "op": - n_instrs += 1 - self.write_instr(self.instrs[thing.name]) + match thing.kind: + case "op": + pass + case "u_inst" if self.tier != InterpreterTier.TIER2: + pass + case "macro_inst" if self.tier != InterpreterTier.TIER1: + pass + case _: + n_instrs += 1 + self.write_instr(self.instrs[thing.name]) case parser.Super(): n_supers += 1 self.write_super(self.super_instrs[thing.name]) @@ -930,6 +970,16 @@ def write_instr(self, instr: Instruction) -> None: self.out.emit(f"PREDICT({prediction});") self.out.emit(f"DISPATCH();") + def write_u_inst_as_c_macro(self, instr: Instruction) -> None: + name = instr.name + self.out.emit("") + self.out.emit(f"#define {name}() \\") + self.out.emit("do { \\") + self.out.postfix = "\\" + instr.write_body(self.out, 0) + self.out.postfix = "" + self.out.emit("} while (0)") + def write_super(self, sup: SuperInstruction) -> None: """Write code for a super-instruction.""" with self.wrap_super_or_macro(sup): @@ -1038,22 +1088,34 @@ def variable_used(node: parser.Node, name: str) -> bool: return any(token.kind == "IDENTIFIER" and token.text == name for token in node.tokens) -def main(): - """Parse command line, parse input, analyze, write output.""" - args = arg_parser.parse_args() # Prints message and sys.exit(2) on error - if args.metadata: - if args.output == DEFAULT_OUTPUT: - args.output = DEFAULT_METADATA_OUTPUT - a = Analyzer(args.input, args.output) # Raises OSError if input unreadable +def generate_interpreter(input_: str, output: str, metadata: bool, + tier: InterpreterTier) -> None: + if metadata: + if output == DEFAULT_OUTPUT: + output = DEFAULT_METADATA_OUTPUT + elif output == TIER2_OUTPUT: + output = TIER2_METADATA_OUTPUT + a = Analyzer(input_, output, tier) # Raises OSError if input unreadable a.parse() # Raises SyntaxError on failure a.analyze() # Prints messages and sets a.errors on failure if a.errors: sys.exit(f"Found {a.errors} errors") - if args.metadata: + if metadata: a.write_metadata() else: a.write_instructions() # Raises OSError if output can't be written +def main(): + """Parse command line, parse input, analyze, write output.""" + args = arg_parser.parse_args() # Prints message and sys.exit(2) on error + + # Tier 1 interpreter + generate_interpreter(args.input, args.output, args.metadata, + InterpreterTier.TIER1) + # Tier 2 interpreter + generate_interpreter(args.input, TIER2_OUTPUT, args.metadata, + InterpreterTier.TIER2) + if __name__ == "__main__": main() diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index c2cebe96ccd6be..b94ef9f24a9eb8 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -1,7 +1,7 @@ """Parser for bytecodes.inst.""" from dataclasses import dataclass, field -from typing import NamedTuple, Callable, TypeVar, Literal +from typing import NamedTuple, Callable, TypeVar, Literal, get_args, TypeAlias import lexer as lx from plexer import PLexer @@ -100,10 +100,30 @@ class OpName(Node): UOp = OpName | CacheEffect +# Note: A mapping of macro_inst -> u_inst+ is created later. +INST_KINDS: TypeAlias = Literal[ + # Legacy means no (inputs -- outputs) + "legacy", + # This generates an instruction definition in the tier 1 and 2 interpreter. + "inst", + # This is a pseudo instruction used only internally by the cases generator. + "op", + # This generates an instruction definition strictly only in the + # tier 1 interpreter. + "macro_inst", + # This generates an instruction definition strictly only in the + # tier 2 interpreter. + "u_inst", +] + +# Remove legacy +INST_LABELS: tuple[INST_KINDS] = get_args(INST_KINDS)[1:] + + @dataclass class InstHeader(Node): register: bool - kind: Literal["inst", "op", "legacy"] # Legacy means no (inputs -- outputs) + kind: INST_KINDS name: str inputs: list[InputEffect] outputs: list[OutputEffect] @@ -112,7 +132,7 @@ class InstHeader(Node): @dataclass class InstDef(Node): register: bool - kind: Literal["inst", "op", "legacy"] + kind: INST_KINDS name: str inputs: list[InputEffect] outputs: list[OutputEffect] @@ -167,7 +187,7 @@ def inst_header(self) -> InstHeader | None: # | [register] op(NAME, (inputs -- outputs)) # TODO: Make INST a keyword in the lexer. register = bool(self.expect(lx.REGISTER)) - if (tkn := self.expect(lx.IDENTIFIER)) and (kind := tkn.text) in ("inst", "op"): + if (tkn := self.expect(lx.IDENTIFIER)) and (kind := tkn.text) in INST_LABELS: if self.expect(lx.LPAREN) and (tkn := self.expect(lx.IDENTIFIER)): name = tkn.text if self.expect(lx.COMMA): From 749dfc491600c69dcd8576c4b7047b5e8fc55335 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 28 Jan 2023 00:47:38 +0800 Subject: [PATCH 002/280] fix typo and formatting --- Python/bytecodes.c | 4 ++-- Python/generated_cases.c.h | 2 +- Python/generated_cases_tier2.c.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index d8532fc0d0c3b4..eb1faa80514e18 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -284,13 +284,13 @@ dummy_func( ERROR_IF(sum == NULL, error); } - u_inst(BINARY_OP_ADD_INT_TYPE_CHECK, (unused / 1, left, right -- left, right)) { + u_inst(BINARY_OP_ADD_INT_TYPE_CHECK, (unused/1, left, right -- left, right)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); } - u_inst(BINARY_OP_ADD_INST_REST, (unused / 1, left, right -- sum)) { + u_inst(BINARY_OP_ADD_INT_REST, (unused/1, left, right -- sum)) { STAT_INC(BINARY_OP, hit); sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index c3b455177e33e3..de49b157b57d6f 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -9,7 +9,7 @@ DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);\ } while (0) - #define BINARY_OP_ADD_INST_REST() \ + #define BINARY_OP_ADD_INT_REST() \ do { \ STAT_INC(BINARY_OP, hit);\ sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right);\ diff --git a/Python/generated_cases_tier2.c.h b/Python/generated_cases_tier2.c.h index 91f4265c139aad..3a7b35f2c89f4b 100644 --- a/Python/generated_cases_tier2.c.h +++ b/Python/generated_cases_tier2.c.h @@ -396,7 +396,7 @@ DISPATCH(); } - TARGET(BINARY_OP_ADD_INST_REST) { + TARGET(BINARY_OP_ADD_INT_REST) { PyObject *right = PEEK(1); PyObject *left = PEEK(2); PyObject *sum; From 069f0f53941dbe72439ab3cef6845d9b885929c1 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 28 Jan 2023 02:23:55 +0800 Subject: [PATCH 003/280] Create a mapping from macroop to uop --- Python/bytecodes.c | 2 + Python/opcode_macro_to_micro.h | 6 +++ Python/opcode_metadata.h | 12 ++++- Python/opcode_metadata_tier2.h | 7 ++- Tools/cases_generator/generate_cases.py | 65 +++++++++++++++++++++++-- Tools/cases_generator/parser.py | 31 +++++++++++- 6 files changed, 111 insertions(+), 12 deletions(-) create mode 100644 Python/opcode_macro_to_micro.h diff --git a/Python/bytecodes.c b/Python/bytecodes.c index eb1faa80514e18..d187e0f24c3416 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -303,6 +303,8 @@ dummy_func( BINARY_OP_ADD_INST_REST(); } + uop_map(BINARY_OP_ADD_INT) = BINARY_OP_ADD_INT_TYPE_CHECK + BINARY_OP_ADD_INT_REST; + family(binary_subscr, INLINE_CACHE_ENTRIES_BINARY_SUBSCR) = { BINARY_SUBSCR, BINARY_SUBSCR_DICT, diff --git a/Python/opcode_macro_to_micro.h b/Python/opcode_macro_to_micro.h new file mode 100644 index 00000000000000..22134e6ab7b91c --- /dev/null +++ b/Python/opcode_macro_to_micro.h @@ -0,0 +1,6 @@ +// This file is generated by Tools\cases_generator\generate_cases.py --uopmap +// from Python\bytecodes.c +// Do not edit! +static int _Py_MacroOp_To_UOp[][2] = { +[BINARY_OP_ADD_INT] = {BINARY_OP_ADD_INT_TYPE_CHECK, BINARY_OP_ADD_INT_REST}, +} diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index cca86629e48d16..3fc45b25de927e 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -1,5 +1,5 @@ -// This file is generated by Tools/cases_generator/generate_cases.py --metadata -// from Python/bytecodes.c +// This file is generated by Tools\cases_generator\generate_cases.py --metadata +// from Python\bytecodes.c // Do not edit! #ifndef NDEBUG @@ -56,6 +56,10 @@ _PyOpcode_num_popped(int opcode, int oparg) { return 2; case BINARY_OP_ADD_FLOAT: return 2; + case BINARY_OP_ADD_INT_TYPE_CHECK: + return 2; + case BINARY_OP_ADD_INT_REST: + return 2; case BINARY_OP_ADD_INT: return 2; case BINARY_SUBSCR: @@ -402,6 +406,10 @@ _PyOpcode_num_pushed(int opcode, int oparg) { return 0; case BINARY_OP_ADD_FLOAT: return 1; + case BINARY_OP_ADD_INT_TYPE_CHECK: + return 2; + case BINARY_OP_ADD_INT_REST: + return 1; case BINARY_OP_ADD_INT: return 1; case BINARY_SUBSCR: diff --git a/Python/opcode_metadata_tier2.h b/Python/opcode_metadata_tier2.h index d7f86246e8f571..bf9170e99cf754 100644 --- a/Python/opcode_metadata_tier2.h +++ b/Python/opcode_metadata_tier2.h @@ -58,7 +58,7 @@ _PyOpcode_num_popped(int opcode, int oparg) { return 2; case BINARY_OP_ADD_INT_TYPE_CHECK: return 2; - case BINARY_OP_ADD_INST_REST: + case BINARY_OP_ADD_INT_REST: return 2; case BINARY_OP_ADD_INT: return 2; @@ -408,7 +408,7 @@ _PyOpcode_num_pushed(int opcode, int oparg) { return 1; case BINARY_OP_ADD_INT_TYPE_CHECK: return 2; - case BINARY_OP_ADD_INST_REST: + case BINARY_OP_ADD_INT_REST: return 1; case BINARY_OP_ADD_INT: return 1; @@ -736,8 +736,7 @@ struct opcode_metadata { [BINARY_OP_INPLACE_ADD_UNICODE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [BINARY_OP_ADD_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, [BINARY_OP_ADD_INT_TYPE_CHECK] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_ADD_INST_REST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_ADD_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, + [BINARY_OP_ADD_INT_REST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, [BINARY_SUBSCR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, [BINARY_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [STORE_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 0487c6ac02839d..d2187fa52105e2 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -34,6 +34,9 @@ TIER2_METADATA_OUTPUT = os.path.relpath( os.path.join(ROOT, "Python/opcode_metadata_tier2.h") ) +TIER2_MACRO_TO_MICRO_MAP_OUTPUT = os.path.relpath( + os.path.join(ROOT, "Python/opcode_macro_to_micro.h") +) BEGIN_MARKER = "// BEGIN BYTECODES //" END_MARKER = "// END BYTECODES //" @@ -58,6 +61,14 @@ help=f"Generate metadata instead, changes output default to {DEFAULT_METADATA_OUTPUT}", ) +arg_parser.add_argument( + "-u", + "--uopmap", + action="store_true", + help=f"Generate macro to micro instruction map instead," + f"changes output default to {TIER2_MACRO_TO_MICRO_MAP_OUTPUT}", +) + class InterpreterTier(Enum): TIER1 = auto() @@ -493,6 +504,7 @@ def error(self, msg: str, node: parser.Node) -> None: super_instrs: dict[str, SuperInstruction] macros: dict[str, parser.Macro] macro_instrs: dict[str, MacroInstruction] + macro_map: dict[str, parser.UOpMap] families: dict[str, parser.Family] def parse(self) -> None: @@ -525,6 +537,7 @@ def parse(self) -> None: self.instrs = {} self.supers = {} self.macros = {} + self.macro_map = {} self.families = {} while thing := psr.definition(): match thing: @@ -537,6 +550,8 @@ def parse(self) -> None: case parser.Macro(name): self.macros[name] = thing self.everything.append(thing) + case parser.UOpMap(name): + self.macro_map[name] = thing case parser.Family(name): self.families[name] = thing case _: @@ -639,6 +654,8 @@ def analyze_supers_and_macros(self) -> None: self.super_instrs[name] = self.analyze_super(super) for name, macro in self.macros.items(): self.macro_instrs[name] = self.analyze_macro(macro) + for name, uopmap in self.macro_map.items(): + self.analyze_uopmap(uopmap) def analyze_super(self, super: parser.Super) -> SuperInstruction: components = self.check_super_components(super) @@ -679,6 +696,15 @@ def analyze_macro(self, macro: parser.Macro) -> MacroInstruction: final_sp = sp return MacroInstruction(macro.name, stack, initial_sp, final_sp, format, macro, parts) + def analyze_uopmap(self, uopmap: parser.UOpMap): + self.check_uopmap_components(uopmap) + + def check_uopmap_components(self, uopmap: parser.UOpMap) -> None: + components: list[InstructionOrCacheEffect] = [] + for uop in uopmap.u_insts: + if uop not in self.instrs: + self.error(f"Unknown instruction {uop!r}", uop) + def analyze_instruction( self, instr: Instruction, stack: list[StackEffect], sp: int ) -> tuple[Component, int]: @@ -814,6 +840,22 @@ def write_function(direction: str, data: list[tuple[Instruction, str]]) -> None: write_function('popped', popped_data) write_function('pushed', pushed_data) + def write_uopmap(self): + """Write the macro instruction to uop mapping to output file.""" + with open(self.output_filename, "w") as f: + # Write provenance header + f.write(f"// This file is generated by {THIS} --uopmap\n") + f.write(f"// from {os.path.relpath(self.filename, ROOT)}\n") + f.write(f"// Do not edit!\n") + + # Create formatter; the rest of the code uses this + self.out = Formatter(f, 0) + self.out.emit("static int _Py_MacroOp_To_UOp[][2] = {") + for name, uopmap in self.macro_map.items(): + u_insts = uopmap.u_insts + self.out.emit(f"[{name}] = {{{u_insts[0]}, {u_insts[1]}}},") + self.out.emit("}") + def write_metadata(self) -> None: """Write instruction metadata to output file.""" @@ -827,6 +869,8 @@ def write_metadata(self) -> None: format = self.super_instrs[thing.name].instr_fmt case parser.Macro(): format = self.macro_instrs[thing.name].instr_fmt + case parser.UOpMap(): + pass case _: typing.assert_never(thing) all_formats.add(format) @@ -860,8 +904,12 @@ def write_metadata(self) -> None: for thing in self.everything: match thing: case parser.InstDef(): - if thing.kind != "op": - self.write_metadata_for_inst(self.instrs[thing.name]) + if thing.kind == "op": + continue + if ((thing.kind == "macro_inst" and self.tier != InterpreterTier.TIER1) + or (thing.kind == "u_inst" and self.tier != InterpreterTier.TIER2)): + continue + self.write_metadata_for_inst(self.instrs[thing.name]) case parser.Super(): self.write_metadata_for_super(self.super_instrs[thing.name]) case parser.Macro(): @@ -949,6 +997,8 @@ def write_instructions(self) -> None: case parser.Macro(): n_macros += 1 self.write_macro(self.macro_instrs[thing.name]) + case parser.UOpMap(): + pass case _: typing.assert_never(thing) @@ -1088,8 +1138,10 @@ def variable_used(node: parser.Node, name: str) -> bool: return any(token.kind == "IDENTIFIER" and token.text == name for token in node.tokens) -def generate_interpreter(input_: str, output: str, metadata: bool, +def generate_interpreter(input_: str, output: str, metadata: bool, uopmap: bool, tier: InterpreterTier) -> None: + if tier == InterpreterTier.TIER2 and uopmap: + output = TIER2_MACRO_TO_MICRO_MAP_OUTPUT if metadata: if output == DEFAULT_OUTPUT: output = DEFAULT_METADATA_OUTPUT @@ -1100,6 +1152,9 @@ def generate_interpreter(input_: str, output: str, metadata: bool, a.analyze() # Prints messages and sets a.errors on failure if a.errors: sys.exit(f"Found {a.errors} errors") + if uopmap: + a.write_uopmap() + return if metadata: a.write_metadata() else: @@ -1110,10 +1165,10 @@ def main(): args = arg_parser.parse_args() # Prints message and sys.exit(2) on error # Tier 1 interpreter - generate_interpreter(args.input, args.output, args.metadata, + generate_interpreter(args.input, args.output, args.metadata, False, InterpreterTier.TIER1) # Tier 2 interpreter - generate_interpreter(args.input, TIER2_OUTPUT, args.metadata, + generate_interpreter(args.input, TIER2_OUTPUT, args.metadata, args.uopmap, InterpreterTier.TIER2) diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index b94ef9f24a9eb8..f4524095075b75 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -150,6 +150,11 @@ class Macro(Node): name: str uops: list[UOp] +@dataclass +class UOpMap(Node): + name: str + u_insts: list[str] + @dataclass class Family(Node): @@ -160,13 +165,15 @@ class Family(Node): class Parser(PLexer): @contextual - def definition(self) -> InstDef | Super | Macro | Family | None: + def definition(self) -> InstDef | Super | Macro | UOpMap | Family | None: if inst := self.inst_def(): return inst if super := self.super_def(): return super if macro := self.macro_def(): return macro + if uopmap := self.uopmap_def(): + return uopmap if family := self.family_def(): return family @@ -349,6 +356,28 @@ def uop(self) -> UOp | None: else: return OpName(tkn.text) + @contextual + def uopmap_def(self) -> UOpMap | None: + if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "uop_map": + if self.expect(lx.LPAREN): + if tkn := self.expect(lx.IDENTIFIER): + if self.expect(lx.RPAREN): + if self.expect(lx.EQUALS): + if u_insts := self.u_insts(): + self.require(lx.SEMI) + res = UOpMap(tkn.text, u_insts) + return res + + def u_insts(self) -> list[str] | None: + if tkn := self.expect(lx.IDENTIFIER): + u_insts = [tkn.text] + while self.expect(lx.PLUS): + if tkn := self.expect(lx.IDENTIFIER): + u_insts.append(tkn.text) + else: + raise self.make_syntax_error("Expected op name") + return u_insts + @contextual def family_def(self) -> Family | None: if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "family": From 688cc5752d0a03f5b8905bc7908905fe0af55db5 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 28 Jan 2023 15:10:33 +0800 Subject: [PATCH 004/280] Auto detect micros without manual definition --- Python/bytecodes.c | 6 +-- Python/generated_cases.c.h | 2 +- Python/opcode_macro_to_micro.h | 4 +- Tools/cases_generator/generate_cases.py | 56 ++++++++++++------------- Tools/cases_generator/parser.py | 32 +++++--------- 5 files changed, 41 insertions(+), 59 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index d187e0f24c3416..07625a5bb17bc6 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -299,12 +299,10 @@ dummy_func( } macro_inst(BINARY_OP_ADD_INT, (unused/1, left, right -- sum)) { - BINARY_OP_ADD_INT_TYPE_CHECK(); - BINARY_OP_ADD_INST_REST(); + U_INST(BINARY_OP_ADD_INT_TYPE_CHECK); + U_INST(BINARY_OP_ADD_INT_REST); } - uop_map(BINARY_OP_ADD_INT) = BINARY_OP_ADD_INT_TYPE_CHECK + BINARY_OP_ADD_INT_REST; - family(binary_subscr, INLINE_CACHE_ENTRIES_BINARY_SUBSCR) = { BINARY_SUBSCR, BINARY_SUBSCR_DICT, diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index de49b157b57d6f..85d44e9dc1b9ca 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -407,7 +407,7 @@ PyObject *left = PEEK(2); PyObject *sum; BINARY_OP_ADD_INT_TYPE_CHECK(); - BINARY_OP_ADD_INST_REST(); + BINARY_OP_ADD_INT_REST(); STACK_SHRINK(1); POKE(1, sum); JUMPBY(1); diff --git a/Python/opcode_macro_to_micro.h b/Python/opcode_macro_to_micro.h index 22134e6ab7b91c..4029b5d261b129 100644 --- a/Python/opcode_macro_to_micro.h +++ b/Python/opcode_macro_to_micro.h @@ -1,6 +1,6 @@ -// This file is generated by Tools\cases_generator\generate_cases.py --uopmap +// This file is generated by Tools\cases_generator\generate_cases.py --macromap // from Python\bytecodes.c // Do not edit! -static int _Py_MacroOp_To_UOp[][2] = { +static int _Py_MacroOpToUOp[][2] = { [BINARY_OP_ADD_INT] = {BINARY_OP_ADD_INT_TYPE_CHECK, BINARY_OP_ADD_INT_REST}, } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index d2187fa52105e2..aa0a7ddb3b5fdf 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -63,7 +63,7 @@ arg_parser.add_argument( "-u", - "--uopmap", + "--macromap", action="store_true", help=f"Generate macro to micro instruction map instead," f"changes output default to {TIER2_MACRO_TO_MICRO_MAP_OUTPUT}", @@ -383,7 +383,10 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None assert dedent <= 0 extra = " " * -dedent for line in self.block_text: - if m := re.match(r"(\s*)ERROR_IF\((.+), (\w+)\);\s*(?://.*)?$", line): + if m := re.match(r"(\s*)U_INST\((.+)\);\s*$", line): + space, label = m.groups() + out.emit(f"{label}();") + elif m := re.match(r"(\s*)ERROR_IF\((.+), (\w+)\);\s*(?://.*)?$", line): space, cond, label = m.groups() # ERROR_IF() must pop the inputs from the stack. # The code block is responsible for DECREF()ing them. @@ -504,7 +507,7 @@ def error(self, msg: str, node: parser.Node) -> None: super_instrs: dict[str, SuperInstruction] macros: dict[str, parser.Macro] macro_instrs: dict[str, MacroInstruction] - macro_map: dict[str, parser.UOpMap] + macro_instdefs: list[parser.InstDef] families: dict[str, parser.Family] def parse(self) -> None: @@ -537,21 +540,22 @@ def parse(self) -> None: self.instrs = {} self.supers = {} self.macros = {} - self.macro_map = {} + self.macro_instrs = {} + self.macro_instdefs = [] self.families = {} while thing := psr.definition(): match thing: case parser.InstDef(name=name): self.instrs[name] = Instruction(thing) self.everything.append(thing) + if thing.kind == "macro_inst": + self.macro_instdefs.append(thing) case parser.Super(name): self.supers[name] = thing self.everything.append(thing) case parser.Macro(name): self.macros[name] = thing self.everything.append(thing) - case parser.UOpMap(name): - self.macro_map[name] = thing case parser.Family(name): self.families[name] = thing case _: @@ -654,8 +658,8 @@ def analyze_supers_and_macros(self) -> None: self.super_instrs[name] = self.analyze_super(super) for name, macro in self.macros.items(): self.macro_instrs[name] = self.analyze_macro(macro) - for name, uopmap in self.macro_map.items(): - self.analyze_uopmap(uopmap) + for macro_instdef in self.macro_instdefs: + self.analyze_macro_instdefs(macro_instdef) def analyze_super(self, super: parser.Super) -> SuperInstruction: components = self.check_super_components(super) @@ -696,14 +700,10 @@ def analyze_macro(self, macro: parser.Macro) -> MacroInstruction: final_sp = sp return MacroInstruction(macro.name, stack, initial_sp, final_sp, format, macro, parts) - def analyze_uopmap(self, uopmap: parser.UOpMap): - self.check_uopmap_components(uopmap) - - def check_uopmap_components(self, uopmap: parser.UOpMap) -> None: - components: list[InstructionOrCacheEffect] = [] - for uop in uopmap.u_insts: + def analyze_macro_instdefs(self, macro_def: parser.InstDef): + for uop in macro_def.u_insts: if uop not in self.instrs: - self.error(f"Unknown instruction {uop!r}", uop) + self.error(f"Unknown instruction {uop} in {macro_def!r}", macro_def) def analyze_instruction( self, instr: Instruction, stack: list[StackEffect], sp: int @@ -840,20 +840,20 @@ def write_function(direction: str, data: list[tuple[Instruction, str]]) -> None: write_function('popped', popped_data) write_function('pushed', pushed_data) - def write_uopmap(self): + def write_macromap(self): """Write the macro instruction to uop mapping to output file.""" with open(self.output_filename, "w") as f: # Write provenance header - f.write(f"// This file is generated by {THIS} --uopmap\n") + f.write(f"// This file is generated by {THIS} --macromap\n") f.write(f"// from {os.path.relpath(self.filename, ROOT)}\n") f.write(f"// Do not edit!\n") # Create formatter; the rest of the code uses this self.out = Formatter(f, 0) - self.out.emit("static int _Py_MacroOp_To_UOp[][2] = {") - for name, uopmap in self.macro_map.items(): - u_insts = uopmap.u_insts - self.out.emit(f"[{name}] = {{{u_insts[0]}, {u_insts[1]}}},") + self.out.emit("static int _Py_MacroOpToUOp[][2] = {") + for macro_def in self.macro_instdefs: + u_insts = macro_def.u_insts + self.out.emit(f"[{macro_def.name}] = {{{u_insts[0]}, {u_insts[1]}}},") self.out.emit("}") def write_metadata(self) -> None: @@ -869,8 +869,6 @@ def write_metadata(self) -> None: format = self.super_instrs[thing.name].instr_fmt case parser.Macro(): format = self.macro_instrs[thing.name].instr_fmt - case parser.UOpMap(): - pass case _: typing.assert_never(thing) all_formats.add(format) @@ -997,8 +995,6 @@ def write_instructions(self) -> None: case parser.Macro(): n_macros += 1 self.write_macro(self.macro_instrs[thing.name]) - case parser.UOpMap(): - pass case _: typing.assert_never(thing) @@ -1138,9 +1134,9 @@ def variable_used(node: parser.Node, name: str) -> bool: return any(token.kind == "IDENTIFIER" and token.text == name for token in node.tokens) -def generate_interpreter(input_: str, output: str, metadata: bool, uopmap: bool, +def generate_interpreter(input_: str, output: str, metadata: bool, macromap: bool, tier: InterpreterTier) -> None: - if tier == InterpreterTier.TIER2 and uopmap: + if tier == InterpreterTier.TIER2 and macromap: output = TIER2_MACRO_TO_MICRO_MAP_OUTPUT if metadata: if output == DEFAULT_OUTPUT: @@ -1152,8 +1148,8 @@ def generate_interpreter(input_: str, output: str, metadata: bool, uopmap: bool, a.analyze() # Prints messages and sets a.errors on failure if a.errors: sys.exit(f"Found {a.errors} errors") - if uopmap: - a.write_uopmap() + if macromap: + a.write_macromap() return if metadata: a.write_metadata() @@ -1168,7 +1164,7 @@ def main(): generate_interpreter(args.input, args.output, args.metadata, False, InterpreterTier.TIER1) # Tier 2 interpreter - generate_interpreter(args.input, TIER2_OUTPUT, args.metadata, args.uopmap, + generate_interpreter(args.input, TIER2_OUTPUT, args.metadata, args.macromap, InterpreterTier.TIER2) diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index f4524095075b75..fd0c0e4c2527db 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -3,6 +3,7 @@ from dataclasses import dataclass, field from typing import NamedTuple, Callable, TypeVar, Literal, get_args, TypeAlias +import re import lexer as lx from plexer import PLexer @@ -137,6 +138,7 @@ class InstDef(Node): inputs: list[InputEffect] outputs: list[OutputEffect] block: Block + u_insts: list[str] @dataclass @@ -150,12 +152,6 @@ class Macro(Node): name: str uops: list[UOp] -@dataclass -class UOpMap(Node): - name: str - u_insts: list[str] - - @dataclass class Family(Node): name: str @@ -165,15 +161,13 @@ class Family(Node): class Parser(PLexer): @contextual - def definition(self) -> InstDef | Super | Macro | UOpMap | Family | None: + def definition(self) -> InstDef | Super | Macro | Family | None: if inst := self.inst_def(): return inst if super := self.super_def(): return super if macro := self.macro_def(): return macro - if uopmap := self.uopmap_def(): - return uopmap if family := self.family_def(): return family @@ -181,8 +175,14 @@ def definition(self) -> InstDef | Super | Macro | UOpMap | Family | None: def inst_def(self) -> InstDef | None: if hdr := self.inst_header(): if block := self.block(): + u_insts = [] + if hdr.kind == "macro_inst": + for line in block.text.splitlines(): + if m := re.match(r"(\s*)U_INST\((.+)\);\s*$", line): + space, label = m.groups() + u_insts.append(label) return InstDef( - hdr.register, hdr.kind, hdr.name, hdr.inputs, hdr.outputs, block + hdr.register, hdr.kind, hdr.name, hdr.inputs, hdr.outputs, block, u_insts ) raise self.make_syntax_error("Expected block") return None @@ -356,18 +356,6 @@ def uop(self) -> UOp | None: else: return OpName(tkn.text) - @contextual - def uopmap_def(self) -> UOpMap | None: - if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "uop_map": - if self.expect(lx.LPAREN): - if tkn := self.expect(lx.IDENTIFIER): - if self.expect(lx.RPAREN): - if self.expect(lx.EQUALS): - if u_insts := self.u_insts(): - self.require(lx.SEMI) - res = UOpMap(tkn.text, u_insts) - return res - def u_insts(self) -> list[str] | None: if tkn := self.expect(lx.IDENTIFIER): u_insts = [tkn.text] From cc8e56a3adad64d077d06bff469079277d6c8095 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 28 Jan 2023 16:50:42 +0800 Subject: [PATCH 005/280] Move the macro to micro map to an internal header --- .../internal/pycore_opcode_macro_to_micro.h | 188 ++++++++++++++++++ Python/bytecodes.c | 10 +- Python/opcode_macro_to_micro.h | 6 - Tools/cases_generator/generate_cases.py | 40 +++- 4 files changed, 230 insertions(+), 14 deletions(-) create mode 100644 Include/internal/pycore_opcode_macro_to_micro.h delete mode 100644 Python/opcode_macro_to_micro.h diff --git a/Include/internal/pycore_opcode_macro_to_micro.h b/Include/internal/pycore_opcode_macro_to_micro.h new file mode 100644 index 00000000000000..def9dd5781e5a0 --- /dev/null +++ b/Include/internal/pycore_opcode_macro_to_micro.h @@ -0,0 +1,188 @@ +// This file is generated by Tools\cases_generator\generate_cases.py --macromap +// from Python\bytecodes.c +// Do not edit! +#ifndef Py_INTERNAL_OPCODE_MACRO_TO_MICRO +#define Py_INTERNAL_OPCODE_MACRO_TO_MICRO +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif +#include "opcode.h" + +static int _Py_MacroOpUOpCount[] = { +[NOP] = 1, +[RESUME] = 1, +[LOAD_CLOSURE] = 1, +[LOAD_FAST_CHECK] = 1, +[LOAD_FAST] = 1, +[LOAD_CONST] = 1, +[STORE_FAST] = 1, +[POP_TOP] = 1, +[PUSH_NULL] = 1, +[UNARY_NEGATIVE] = 1, +[UNARY_NOT] = 1, +[UNARY_INVERT] = 1, +[BINARY_OP_MULTIPLY_INT] = 1, +[BINARY_OP_MULTIPLY_FLOAT] = 1, +[BINARY_OP_SUBTRACT_INT] = 1, +[BINARY_OP_SUBTRACT_FLOAT] = 1, +[BINARY_OP_ADD_UNICODE] = 1, +[BINARY_OP_INPLACE_ADD_UNICODE] = 1, +[BINARY_OP_ADD_FLOAT] = 1, +[BINARY_OP_ADD_INT] = 2, +[BINARY_OP_ADD_INT_TYPE_CHECK] = 1, +[BINARY_OP_ADD_INT_REST] = 1, +[BINARY_SUBSCR] = 1, +[BINARY_SLICE] = 1, +[STORE_SLICE] = 1, +[BINARY_SUBSCR_LIST_INT] = 1, +[BINARY_SUBSCR_TUPLE_INT] = 1, +[BINARY_SUBSCR_DICT] = 1, +[BINARY_SUBSCR_GETITEM] = 1, +[LIST_APPEND] = 1, +[SET_ADD] = 1, +[STORE_SUBSCR] = 1, +[STORE_SUBSCR_LIST_INT] = 1, +[STORE_SUBSCR_DICT] = 1, +[DELETE_SUBSCR] = 1, +[CALL_INTRINSIC_1] = 1, +[RAISE_VARARGS] = 1, +[INTERPRETER_EXIT] = 1, +[RETURN_VALUE] = 1, +[GET_AITER] = 1, +[GET_ANEXT] = 1, +[GET_AWAITABLE] = 1, +[SEND] = 1, +[YIELD_VALUE] = 1, +[POP_EXCEPT] = 1, +[RERAISE] = 1, +[PREP_RERAISE_STAR] = 1, +[END_ASYNC_FOR] = 1, +[CLEANUP_THROW] = 1, +[LOAD_ASSERTION_ERROR] = 1, +[LOAD_BUILD_CLASS] = 1, +[STORE_NAME] = 1, +[DELETE_NAME] = 1, +[UNPACK_SEQUENCE] = 1, +[UNPACK_SEQUENCE_TWO_TUPLE] = 1, +[UNPACK_SEQUENCE_TUPLE] = 1, +[UNPACK_SEQUENCE_LIST] = 1, +[UNPACK_EX] = 1, +[STORE_ATTR] = 1, +[DELETE_ATTR] = 1, +[STORE_GLOBAL] = 1, +[DELETE_GLOBAL] = 1, +[LOAD_NAME] = 1, +[LOAD_GLOBAL] = 1, +[LOAD_GLOBAL_MODULE] = 1, +[LOAD_GLOBAL_BUILTIN] = 1, +[DELETE_FAST] = 1, +[MAKE_CELL] = 1, +[DELETE_DEREF] = 1, +[LOAD_CLASSDEREF] = 1, +[LOAD_DEREF] = 1, +[STORE_DEREF] = 1, +[COPY_FREE_VARS] = 1, +[BUILD_STRING] = 1, +[BUILD_TUPLE] = 1, +[BUILD_LIST] = 1, +[LIST_EXTEND] = 1, +[SET_UPDATE] = 1, +[BUILD_SET] = 1, +[BUILD_MAP] = 1, +[SETUP_ANNOTATIONS] = 1, +[BUILD_CONST_KEY_MAP] = 1, +[DICT_UPDATE] = 1, +[DICT_MERGE] = 1, +[MAP_ADD] = 1, +[LOAD_ATTR] = 1, +[LOAD_ATTR_INSTANCE_VALUE] = 1, +[LOAD_ATTR_MODULE] = 1, +[LOAD_ATTR_WITH_HINT] = 1, +[LOAD_ATTR_SLOT] = 1, +[LOAD_ATTR_CLASS] = 1, +[LOAD_ATTR_PROPERTY] = 1, +[LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = 1, +[STORE_ATTR_INSTANCE_VALUE] = 1, +[STORE_ATTR_WITH_HINT] = 1, +[STORE_ATTR_SLOT] = 1, +[COMPARE_OP] = 1, +[COMPARE_AND_BRANCH] = 1, +[COMPARE_AND_BRANCH_FLOAT] = 1, +[COMPARE_AND_BRANCH_INT] = 1, +[COMPARE_AND_BRANCH_STR] = 1, +[IS_OP] = 1, +[CONTAINS_OP] = 1, +[CHECK_EG_MATCH] = 1, +[CHECK_EXC_MATCH] = 1, +[IMPORT_NAME] = 1, +[IMPORT_FROM] = 1, +[JUMP_FORWARD] = 1, +[JUMP_BACKWARD] = 1, +[POP_JUMP_IF_FALSE] = 1, +[POP_JUMP_IF_TRUE] = 1, +[POP_JUMP_IF_NOT_NONE] = 1, +[POP_JUMP_IF_NONE] = 1, +[JUMP_IF_FALSE_OR_POP] = 1, +[JUMP_IF_TRUE_OR_POP] = 1, +[JUMP_BACKWARD_NO_INTERRUPT] = 1, +[GET_LEN] = 1, +[MATCH_CLASS] = 1, +[MATCH_MAPPING] = 1, +[MATCH_SEQUENCE] = 1, +[MATCH_KEYS] = 1, +[GET_ITER] = 1, +[GET_YIELD_FROM_ITER] = 1, +[FOR_ITER] = 1, +[FOR_ITER_LIST] = 1, +[FOR_ITER_TUPLE] = 1, +[FOR_ITER_RANGE] = 1, +[FOR_ITER_GEN] = 1, +[BEFORE_ASYNC_WITH] = 1, +[BEFORE_WITH] = 1, +[WITH_EXCEPT_START] = 1, +[PUSH_EXC_INFO] = 1, +[LOAD_ATTR_METHOD_WITH_VALUES] = 1, +[LOAD_ATTR_METHOD_NO_DICT] = 1, +[LOAD_ATTR_METHOD_LAZY_DICT] = 1, +[CALL_BOUND_METHOD_EXACT_ARGS] = 1, +[KW_NAMES] = 1, +[CALL] = 1, +[CALL_PY_EXACT_ARGS] = 1, +[CALL_PY_WITH_DEFAULTS] = 1, +[CALL_NO_KW_TYPE_1] = 1, +[CALL_NO_KW_STR_1] = 1, +[CALL_NO_KW_TUPLE_1] = 1, +[CALL_BUILTIN_CLASS] = 1, +[CALL_NO_KW_BUILTIN_O] = 1, +[CALL_NO_KW_BUILTIN_FAST] = 1, +[CALL_BUILTIN_FAST_WITH_KEYWORDS] = 1, +[CALL_NO_KW_LEN] = 1, +[CALL_NO_KW_ISINSTANCE] = 1, +[CALL_NO_KW_LIST_APPEND] = 1, +[CALL_NO_KW_METHOD_DESCRIPTOR_O] = 1, +[CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = 1, +[CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = 1, +[CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = 1, +[CALL_FUNCTION_EX] = 1, +[MAKE_FUNCTION] = 1, +[RETURN_GENERATOR] = 1, +[BUILD_SLICE] = 1, +[FORMAT_VALUE] = 1, +[COPY] = 1, +[BINARY_OP] = 1, +[SWAP] = 1, +[EXTENDED_ARG] = 1, +[CACHE] = 1, +} + +static int _Py_MacroOpToUOp[][2] = { +[BINARY_OP_ADD_INT] = {BINARY_OP_ADD_INT_TYPE_CHECK, BINARY_OP_ADD_INT_REST}, +} +#ifdef __cplusplus +} +#endif +#endif // Py_INTERNAL_OPCODE_MACRO_TO_MICRO diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 07625a5bb17bc6..1d3735d61d0430 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -284,6 +284,11 @@ dummy_func( ERROR_IF(sum == NULL, error); } + macro_inst(BINARY_OP_ADD_INT, (unused / 1, left, right -- sum)) { + U_INST(BINARY_OP_ADD_INT_TYPE_CHECK); + U_INST(BINARY_OP_ADD_INT_REST); + } + u_inst(BINARY_OP_ADD_INT_TYPE_CHECK, (unused/1, left, right -- left, right)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); @@ -298,11 +303,6 @@ dummy_func( ERROR_IF(sum == NULL, error); } - macro_inst(BINARY_OP_ADD_INT, (unused/1, left, right -- sum)) { - U_INST(BINARY_OP_ADD_INT_TYPE_CHECK); - U_INST(BINARY_OP_ADD_INT_REST); - } - family(binary_subscr, INLINE_CACHE_ENTRIES_BINARY_SUBSCR) = { BINARY_SUBSCR, BINARY_SUBSCR_DICT, diff --git a/Python/opcode_macro_to_micro.h b/Python/opcode_macro_to_micro.h deleted file mode 100644 index 4029b5d261b129..00000000000000 --- a/Python/opcode_macro_to_micro.h +++ /dev/null @@ -1,6 +0,0 @@ -// This file is generated by Tools\cases_generator\generate_cases.py --macromap -// from Python\bytecodes.c -// Do not edit! -static int _Py_MacroOpToUOp[][2] = { -[BINARY_OP_ADD_INT] = {BINARY_OP_ADD_INT_TYPE_CHECK, BINARY_OP_ADD_INT_REST}, -} diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index aa0a7ddb3b5fdf..890d304def8098 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -35,7 +35,7 @@ os.path.join(ROOT, "Python/opcode_metadata_tier2.h") ) TIER2_MACRO_TO_MICRO_MAP_OUTPUT = os.path.relpath( - os.path.join(ROOT, "Python/opcode_macro_to_micro.h") + os.path.join(ROOT, "Include/internal/pycore_opcode_macro_to_micro.h") ) BEGIN_MARKER = "// BEGIN BYTECODES //" @@ -850,11 +850,45 @@ def write_macromap(self): # Create formatter; the rest of the code uses this self.out = Formatter(f, 0) - self.out.emit("static int _Py_MacroOpToUOp[][2] = {") + # Header guard + self.out.emit("") + self.out.emit("#ifndef Py_INTERNAL_OPCODE_MACRO_TO_MICRO") + self.out.emit("#define Py_INTERNAL_OPCODE_MACRO_TO_MICRO") + self.out.emit("#ifdef __cplusplus") + self.out.emit('extern "C" {') + self.out.emit("#endif") + self.out.emit("") + self.out.emit("#ifndef Py_BUILD_CORE") + self.out.emit('# error "this header requires Py_BUILD_CORE define"') + self.out.emit("#endif") + self.out.emit('#include "opcode.h"') + self.out.emit("") + + self.out.emit("extern const int _Py_MacroOpUOpCount[] = {") + macro_instrdef_names = set() + max_instr_len = 0 + for name, instr_def in self.instrs.items(): + if (macro_def := instr_def.inst) in self.macro_instdefs: + u_insts = macro_def.u_insts + instr_len = len(u_insts) + max_instr_len = max(instr_len, max_instr_len) + self.out.emit(f"[{macro_def.name}] = {instr_len},") + macro_instrdef_names.add(macro_def.name) + else: + self.out.emit(f"[{name}] = 1,") + self.out.emit("}") + self.out.emit("") + self.out.emit(f"extern const int _Py_MacroOpToUOp[][{max_instr_len}] = {{") for macro_def in self.macro_instdefs: u_insts = macro_def.u_insts - self.out.emit(f"[{macro_def.name}] = {{{u_insts[0]}, {u_insts[1]}}},") + self.out.emit(f"[{macro_def.name}] = {{{', '.join(u_insts)}}},") + self.out.emit("}") + + # Header guard end + self.out.emit("#ifdef __cplusplus") self.out.emit("}") + self.out.emit("#endif") + self.out.emit("#endif // Py_INTERNAL_OPCODE_MACRO_TO_MICRO") def write_metadata(self) -> None: """Write instruction metadata to output file.""" From 081eb3247675b6debded07569c085c578509307f Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 28 Jan 2023 18:13:14 +0800 Subject: [PATCH 006/280] Generate tier2 instructions separate from tier1 --- Include/internal/pycore_opcode.h | 270 ++++++++++++++++++++++++++++++- Include/opcode.h | 70 ++++++++ Lib/opcode.py | 8 + Tools/build/generate_opcode_h.py | 47 +++++- 4 files changed, 391 insertions(+), 4 deletions(-) diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 05c0485b0641d8..7a6c6f6158a3c4 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -226,7 +226,7 @@ const uint8_t _PyOpcode_Deopt[256] = { }; #endif // NEED_OPCODE_TABLES -#ifdef Py_DEBUG +#if defined(Py_DEBUG) && !defined(Py_TIER2_INTERPRETER) static const char *const _PyOpcode_OpName[263] = { [CACHE] = "CACHE", [POP_TOP] = "POP_TOP", @@ -494,8 +494,274 @@ static const char *const _PyOpcode_OpName[263] = { }; #endif +#if defined(Py_DEBUG) && defined(Py_TIER2_INTERPRETER) +static const char *const _PyOpcode_OpName[263] = { + [CACHE] = "CACHE", + [POP_TOP] = "POP_TOP", + [PUSH_NULL] = "PUSH_NULL", + [INTERPRETER_EXIT] = "INTERPRETER_EXIT", + [END_FOR] = "END_FOR", + [BINARY_OP_ADD_FLOAT] = "BINARY_OP_ADD_FLOAT", + [BINARY_OP_ADD_INT_TYPE_CHECK] = "BINARY_OP_ADD_INT_TYPE_CHECK", + [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", + [NOP] = "NOP", + [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT", + [UNARY_NEGATIVE] = "UNARY_NEGATIVE", + [UNARY_NOT] = "UNARY_NOT", + [BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT", + [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT", + [UNARY_INVERT] = "UNARY_INVERT", + [BINARY_OP_SUBTRACT_INT] = "BINARY_OP_SUBTRACT_INT", + [BINARY_SUBSCR_DICT] = "BINARY_SUBSCR_DICT", + [BINARY_SUBSCR_GETITEM] = "BINARY_SUBSCR_GETITEM", + [BINARY_SUBSCR_LIST_INT] = "BINARY_SUBSCR_LIST_INT", + [BINARY_SUBSCR_TUPLE_INT] = "BINARY_SUBSCR_TUPLE_INT", + [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS", + [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", + [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", + [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", + [BINARY_SUBSCR] = "BINARY_SUBSCR", + [BINARY_SLICE] = "BINARY_SLICE", + [STORE_SLICE] = "STORE_SLICE", + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", + [GET_LEN] = "GET_LEN", + [MATCH_MAPPING] = "MATCH_MAPPING", + [MATCH_SEQUENCE] = "MATCH_SEQUENCE", + [MATCH_KEYS] = "MATCH_KEYS", + [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", + [PUSH_EXC_INFO] = "PUSH_EXC_INFO", + [CHECK_EXC_MATCH] = "CHECK_EXC_MATCH", + [CHECK_EG_MATCH] = "CHECK_EG_MATCH", + [CALL_NO_KW_BUILTIN_O] = "CALL_NO_KW_BUILTIN_O", + [CALL_NO_KW_ISINSTANCE] = "CALL_NO_KW_ISINSTANCE", + [CALL_NO_KW_LEN] = "CALL_NO_KW_LEN", + [CALL_NO_KW_LIST_APPEND] = "CALL_NO_KW_LIST_APPEND", + [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", + [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", + [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", + [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", + [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", + [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", + [COMPARE_AND_BRANCH_FLOAT] = "COMPARE_AND_BRANCH_FLOAT", + [WITH_EXCEPT_START] = "WITH_EXCEPT_START", + [GET_AITER] = "GET_AITER", + [GET_ANEXT] = "GET_ANEXT", + [BEFORE_ASYNC_WITH] = "BEFORE_ASYNC_WITH", + [BEFORE_WITH] = "BEFORE_WITH", + [END_ASYNC_FOR] = "END_ASYNC_FOR", + [CLEANUP_THROW] = "CLEANUP_THROW", + [COMPARE_AND_BRANCH_INT] = "COMPARE_AND_BRANCH_INT", + [COMPARE_AND_BRANCH_STR] = "COMPARE_AND_BRANCH_STR", + [FOR_ITER_LIST] = "FOR_ITER_LIST", + [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", + [STORE_SUBSCR] = "STORE_SUBSCR", + [DELETE_SUBSCR] = "DELETE_SUBSCR", + [FOR_ITER_RANGE] = "FOR_ITER_RANGE", + [FOR_ITER_GEN] = "FOR_ITER_GEN", + [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", + [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", + [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", + [GET_ITER] = "GET_ITER", + [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", + [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", + [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", + [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", + [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", + [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", + [RETURN_GENERATOR] = "RETURN_GENERATOR", + [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", + [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", + [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", + [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", + [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", + [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", + [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", + [RETURN_VALUE] = "RETURN_VALUE", + [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", + [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", + [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", + [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", + [PREP_RERAISE_STAR] = "PREP_RERAISE_STAR", + [POP_EXCEPT] = "POP_EXCEPT", + [STORE_NAME] = "STORE_NAME", + [DELETE_NAME] = "DELETE_NAME", + [UNPACK_SEQUENCE] = "UNPACK_SEQUENCE", + [FOR_ITER] = "FOR_ITER", + [UNPACK_EX] = "UNPACK_EX", + [STORE_ATTR] = "STORE_ATTR", + [DELETE_ATTR] = "DELETE_ATTR", + [STORE_GLOBAL] = "STORE_GLOBAL", + [DELETE_GLOBAL] = "DELETE_GLOBAL", + [SWAP] = "SWAP", + [LOAD_CONST] = "LOAD_CONST", + [LOAD_NAME] = "LOAD_NAME", + [BUILD_TUPLE] = "BUILD_TUPLE", + [BUILD_LIST] = "BUILD_LIST", + [BUILD_SET] = "BUILD_SET", + [BUILD_MAP] = "BUILD_MAP", + [LOAD_ATTR] = "LOAD_ATTR", + [COMPARE_OP] = "COMPARE_OP", + [IMPORT_NAME] = "IMPORT_NAME", + [IMPORT_FROM] = "IMPORT_FROM", + [JUMP_FORWARD] = "JUMP_FORWARD", + [JUMP_IF_FALSE_OR_POP] = "JUMP_IF_FALSE_OR_POP", + [JUMP_IF_TRUE_OR_POP] = "JUMP_IF_TRUE_OR_POP", + [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", + [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", + [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", + [LOAD_GLOBAL] = "LOAD_GLOBAL", + [IS_OP] = "IS_OP", + [CONTAINS_OP] = "CONTAINS_OP", + [RERAISE] = "RERAISE", + [COPY] = "COPY", + [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", + [BINARY_OP] = "BINARY_OP", + [SEND] = "SEND", + [LOAD_FAST] = "LOAD_FAST", + [STORE_FAST] = "STORE_FAST", + [DELETE_FAST] = "DELETE_FAST", + [LOAD_FAST_CHECK] = "LOAD_FAST_CHECK", + [POP_JUMP_IF_NOT_NONE] = "POP_JUMP_IF_NOT_NONE", + [POP_JUMP_IF_NONE] = "POP_JUMP_IF_NONE", + [RAISE_VARARGS] = "RAISE_VARARGS", + [GET_AWAITABLE] = "GET_AWAITABLE", + [MAKE_FUNCTION] = "MAKE_FUNCTION", + [BUILD_SLICE] = "BUILD_SLICE", + [JUMP_BACKWARD_NO_INTERRUPT] = "JUMP_BACKWARD_NO_INTERRUPT", + [MAKE_CELL] = "MAKE_CELL", + [LOAD_CLOSURE] = "LOAD_CLOSURE", + [LOAD_DEREF] = "LOAD_DEREF", + [STORE_DEREF] = "STORE_DEREF", + [DELETE_DEREF] = "DELETE_DEREF", + [JUMP_BACKWARD] = "JUMP_BACKWARD", + [COMPARE_AND_BRANCH] = "COMPARE_AND_BRANCH", + [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", + [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", + [EXTENDED_ARG] = "EXTENDED_ARG", + [LIST_APPEND] = "LIST_APPEND", + [SET_ADD] = "SET_ADD", + [MAP_ADD] = "MAP_ADD", + [LOAD_CLASSDEREF] = "LOAD_CLASSDEREF", + [COPY_FREE_VARS] = "COPY_FREE_VARS", + [YIELD_VALUE] = "YIELD_VALUE", + [RESUME] = "RESUME", + [MATCH_CLASS] = "MATCH_CLASS", + [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", + [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", + [FORMAT_VALUE] = "FORMAT_VALUE", + [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", + [BUILD_STRING] = "BUILD_STRING", + [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", + [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", + [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", + [160] = "<161>", + [BINARY_OP_ADD_INT_REST] = "BINARY_OP_ADD_INT_REST", + [SET_UPDATE] = "SET_UPDATE", + [DICT_MERGE] = "DICT_MERGE", + [DICT_UPDATE] = "DICT_UPDATE", + [165] = "<166>", + [166] = "<167>", + [167] = "<168>", + [168] = "<169>", + [169] = "<170>", + [CALL] = "CALL", + [KW_NAMES] = "KW_NAMES", + [CALL_INTRINSIC_1] = "CALL_INTRINSIC_1", + [173] = "<174>", + [174] = "<175>", + [175] = "<176>", + [176] = "<177>", + [177] = "<178>", + [178] = "<179>", + [179] = "<180>", + [180] = "<181>", + [181] = "<182>", + [182] = "<183>", + [183] = "<184>", + [184] = "<185>", + [185] = "<186>", + [186] = "<187>", + [187] = "<188>", + [188] = "<189>", + [189] = "<190>", + [190] = "<191>", + [191] = "<192>", + [192] = "<193>", + [193] = "<194>", + [194] = "<195>", + [195] = "<196>", + [196] = "<197>", + [197] = "<198>", + [198] = "<199>", + [199] = "<200>", + [200] = "<201>", + [201] = "<202>", + [202] = "<203>", + [203] = "<204>", + [204] = "<205>", + [205] = "<206>", + [206] = "<207>", + [207] = "<208>", + [208] = "<209>", + [209] = "<210>", + [210] = "<211>", + [211] = "<212>", + [212] = "<213>", + [213] = "<214>", + [214] = "<215>", + [215] = "<216>", + [216] = "<217>", + [217] = "<218>", + [218] = "<219>", + [219] = "<220>", + [220] = "<221>", + [221] = "<222>", + [222] = "<223>", + [223] = "<224>", + [224] = "<225>", + [225] = "<226>", + [226] = "<227>", + [227] = "<228>", + [228] = "<229>", + [229] = "<230>", + [230] = "<231>", + [231] = "<232>", + [232] = "<233>", + [233] = "<234>", + [234] = "<235>", + [235] = "<236>", + [236] = "<237>", + [237] = "<238>", + [238] = "<239>", + [239] = "<240>", + [240] = "<241>", + [241] = "<242>", + [242] = "<243>", + [243] = "<244>", + [244] = "<245>", + [245] = "<246>", + [246] = "<247>", + [247] = "<248>", + [248] = "<249>", + [249] = "<250>", + [250] = "<251>", + [251] = "<252>", + [252] = "<253>", + [253] = "<254>", + [DO_TRACING] = "DO_TRACING", + [SETUP_FINALLY] = "SETUP_FINALLY", + [SETUP_CLEANUP] = "SETUP_CLEANUP", + [SETUP_WITH] = "SETUP_WITH", + [POP_BLOCK] = "POP_BLOCK", + [JUMP] = "JUMP", + [JUMP_NO_INTERRUPT] = "JUMP_NO_INTERRUPT", + [LOAD_METHOD] = "LOAD_METHOD", +}; +#endif + #define EXTRA_CASES \ - case 161: \ case 166: \ case 167: \ case 168: \ diff --git a/Include/opcode.h b/Include/opcode.h index 827f9931beb3e6..63e5a4329b27db 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -125,6 +125,8 @@ extern "C" { #define JUMP_NO_INTERRUPT 261 #define LOAD_METHOD 262 #define MAX_PSEUDO_OPCODE 262 + +#ifndef Py_TIER2_INTERPRETER #define BINARY_OP_ADD_FLOAT 5 #define BINARY_OP_ADD_INT 6 #define BINARY_OP_ADD_UNICODE 7 @@ -187,6 +189,74 @@ extern "C" { #define UNPACK_SEQUENCE_TUPLE 159 #define UNPACK_SEQUENCE_TWO_TUPLE 160 #define DO_TRACING 255 +#endif + +#ifdef Py_TIER2_INTERPRETER +#define BINARY_OP_ADD_FLOAT 5 +#define BINARY_OP_ADD_UNICODE 7 +#define BINARY_OP_INPLACE_ADD_UNICODE 8 +#define BINARY_OP_MULTIPLY_FLOAT 10 +#define BINARY_OP_MULTIPLY_INT 13 +#define BINARY_OP_SUBTRACT_FLOAT 14 +#define BINARY_OP_SUBTRACT_INT 16 +#define BINARY_SUBSCR_DICT 17 +#define BINARY_SUBSCR_GETITEM 18 +#define BINARY_SUBSCR_LIST_INT 19 +#define BINARY_SUBSCR_TUPLE_INT 20 +#define CALL_PY_EXACT_ARGS 21 +#define CALL_PY_WITH_DEFAULTS 22 +#define CALL_BOUND_METHOD_EXACT_ARGS 23 +#define CALL_BUILTIN_CLASS 24 +#define CALL_BUILTIN_FAST_WITH_KEYWORDS 28 +#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 29 +#define CALL_NO_KW_BUILTIN_FAST 34 +#define CALL_NO_KW_BUILTIN_O 38 +#define CALL_NO_KW_ISINSTANCE 39 +#define CALL_NO_KW_LEN 40 +#define CALL_NO_KW_LIST_APPEND 41 +#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 42 +#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 43 +#define CALL_NO_KW_METHOD_DESCRIPTOR_O 44 +#define CALL_NO_KW_STR_1 45 +#define CALL_NO_KW_TUPLE_1 46 +#define CALL_NO_KW_TYPE_1 47 +#define COMPARE_AND_BRANCH_FLOAT 48 +#define COMPARE_AND_BRANCH_INT 56 +#define COMPARE_AND_BRANCH_STR 57 +#define FOR_ITER_LIST 58 +#define FOR_ITER_TUPLE 59 +#define FOR_ITER_RANGE 62 +#define FOR_ITER_GEN 63 +#define LOAD_ATTR_CLASS 64 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 65 +#define LOAD_ATTR_INSTANCE_VALUE 66 +#define LOAD_ATTR_MODULE 67 +#define LOAD_ATTR_PROPERTY 70 +#define LOAD_ATTR_SLOT 72 +#define LOAD_ATTR_WITH_HINT 73 +#define LOAD_ATTR_METHOD_LAZY_DICT 76 +#define LOAD_ATTR_METHOD_NO_DICT 77 +#define LOAD_ATTR_METHOD_WITH_VALUES 78 +#define LOAD_CONST__LOAD_FAST 79 +#define LOAD_FAST__LOAD_CONST 80 +#define LOAD_FAST__LOAD_FAST 81 +#define LOAD_GLOBAL_BUILTIN 82 +#define LOAD_GLOBAL_MODULE 84 +#define STORE_ATTR_INSTANCE_VALUE 86 +#define STORE_ATTR_SLOT 87 +#define STORE_ATTR_WITH_HINT 113 +#define STORE_FAST__LOAD_FAST 121 +#define STORE_FAST__STORE_FAST 143 +#define STORE_SUBSCR_DICT 153 +#define STORE_SUBSCR_LIST_INT 154 +#define UNPACK_SEQUENCE_LIST 158 +#define UNPACK_SEQUENCE_TUPLE 159 +#define UNPACK_SEQUENCE_TWO_TUPLE 160 +#define DO_TRACING 255 +#define BINARY_OP_ADD_INT_TYPE_CHECK 6 +#define BINARY_OP_ADD_INT_REST 161 +#endif + #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/opcode.py b/Lib/opcode.py index c317e23beae62b..9c1402e316d395 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -432,3 +432,11 @@ def pseudo_op(name, op, real_ops): _inline_cache_entries = [ sum(_cache_format.get(opname[opcode], {}).values()) for opcode in range(256) ] + +_macro_ops = [ + 'BINARY_OP_ADD_INT', +] +_uops = [ + 'BINARY_OP_ADD_INT_TYPE_CHECK', + 'BINARY_OP_ADD_INT_REST', +] diff --git a/Tools/build/generate_opcode_h.py b/Tools/build/generate_opcode_h.py index 9b2112f7f5f31d..3ff94a324a0803 100644 --- a/Tools/build/generate_opcode_h.py +++ b/Tools/build/generate_opcode_h.py @@ -105,14 +105,35 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna specialized_opmap[name] = next_op opname_including_specialized[next_op] = name used[next_op] = True + specialized_opmap['DO_TRACING'] = 255 opname_including_specialized[255] = 'DO_TRACING' used[255] = True + # The Tier 2 ops + next_op = 1 + uop_opmap = specialized_opmap.copy() + uop_opname = opname_including_specialized.copy() + # Remove macroops + for name in opcode['_macro_ops']: + op = uop_opmap[name] + del uop_opmap[name] + del uop_opname[op] + used[op] = False + # Add microops + for name in opcode['_uops']: + while used[next_op]: + next_op += 1 + uop_opmap[name] = next_op + uop_opname[next_op] = name + used[next_op] = True + with open(outfile, 'w') as fobj, open(internaloutfile, 'w') as iobj: fobj.write(header) iobj.write(internal_header) + # Tier 1 opcodes + for name in opname: if name in opmap: op = opmap[name] @@ -126,9 +147,19 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna if op == MAX_PSEUDO_OPCODE: fobj.write(DEFINE.format("MAX_PSEUDO_OPCODE", MAX_PSEUDO_OPCODE)) - + fobj.write("\n") + fobj.write("#ifndef Py_TIER2_INTERPRETER\n") for name, op in specialized_opmap.items(): fobj.write(DEFINE.format(name, op)) + fobj.write("#endif\n") + fobj.write("\n") + + # Tier 2 opcodes + fobj.write("#ifdef Py_TIER2_INTERPRETER\n") + for name, op in uop_opmap.items(): + fobj.write(DEFINE.format(name, op)) + fobj.write("#endif\n") + fobj.write("\n") iobj.write("\nextern const uint8_t _PyOpcode_Caches[256];\n") iobj.write("\nextern const uint8_t _PyOpcode_Deopt[256];\n") @@ -177,7 +208,8 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna fobj.write(f"#define ENABLE_SPECIALIZATION {int(ENABLE_SPECIALIZATION)}") iobj.write("\n") - iobj.write("#ifdef Py_DEBUG\n") + # Tier 1 opnames + iobj.write("#if defined(Py_DEBUG) && !defined(Py_TIER2_INTERPRETER)\n") iobj.write(f"static const char *const _PyOpcode_OpName[{NUM_OPCODES}] = {{\n") for op, name in enumerate(opname_including_specialized): if name[0] != "<": @@ -186,6 +218,17 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna iobj.write("};\n") iobj.write("#endif\n") + iobj.write("\n") + # Tier 2 opnames + iobj.write("#if defined(Py_DEBUG) && defined(Py_TIER2_INTERPRETER)\n") + iobj.write(f"static const char *const _PyOpcode_OpName[{NUM_OPCODES}] = {{\n") + for op, name in enumerate(uop_opname): + if name[0] != "<": + op = name + iobj.write(f''' [{op}] = "{name}",\n''') + iobj.write("};\n") + iobj.write("#endif\n") + iobj.write("\n") iobj.write("#define EXTRA_CASES \\\n") for i, flag in enumerate(used): From 056dc12c20d6d9d18d1474afd565bafce771d45e Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sun, 29 Jan 2023 01:16:37 +0800 Subject: [PATCH 007/280] Combine the interpreters --- Include/internal/pycore_opcode.h | 273 +- .../internal/pycore_opcode_macro_to_micro.h | 5 +- Include/opcode.h | 13 +- Python/bytecodes.c | 6 +- Python/generated_cases.c.h | 31 +- Python/generated_cases_tier2.c.h | 3713 ----------------- Python/opcode_metadata_tier2.h | 882 ---- Tools/build/generate_opcode_h.py | 28 +- Tools/cases_generator/generate_cases.py | 74 +- 9 files changed, 65 insertions(+), 4960 deletions(-) delete mode 100644 Python/generated_cases_tier2.c.h delete mode 100644 Python/opcode_metadata_tier2.h diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 7a6c6f6158a3c4..92ce888e0c322f 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -226,7 +226,7 @@ const uint8_t _PyOpcode_Deopt[256] = { }; #endif // NEED_OPCODE_TABLES -#if defined(Py_DEBUG) && !defined(Py_TIER2_INTERPRETER) +#ifdef Py_DEBUG static const char *const _PyOpcode_OpName[263] = { [CACHE] = "CACHE", [POP_TOP] = "POP_TOP", @@ -389,12 +389,12 @@ static const char *const _PyOpcode_OpName[263] = { [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", - [161] = "<161>", + [BINARY_OP_ADD_INT_TYPE_CHECK] = "BINARY_OP_ADD_INT_TYPE_CHECK", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", - [166] = "<166>", + [BINARY_OP_ADD_INT_REST] = "BINARY_OP_ADD_INT_REST", [167] = "<167>", [168] = "<168>", [169] = "<169>", @@ -494,275 +494,8 @@ static const char *const _PyOpcode_OpName[263] = { }; #endif -#if defined(Py_DEBUG) && defined(Py_TIER2_INTERPRETER) -static const char *const _PyOpcode_OpName[263] = { - [CACHE] = "CACHE", - [POP_TOP] = "POP_TOP", - [PUSH_NULL] = "PUSH_NULL", - [INTERPRETER_EXIT] = "INTERPRETER_EXIT", - [END_FOR] = "END_FOR", - [BINARY_OP_ADD_FLOAT] = "BINARY_OP_ADD_FLOAT", - [BINARY_OP_ADD_INT_TYPE_CHECK] = "BINARY_OP_ADD_INT_TYPE_CHECK", - [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", - [NOP] = "NOP", - [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT", - [UNARY_NEGATIVE] = "UNARY_NEGATIVE", - [UNARY_NOT] = "UNARY_NOT", - [BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT", - [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT", - [UNARY_INVERT] = "UNARY_INVERT", - [BINARY_OP_SUBTRACT_INT] = "BINARY_OP_SUBTRACT_INT", - [BINARY_SUBSCR_DICT] = "BINARY_SUBSCR_DICT", - [BINARY_SUBSCR_GETITEM] = "BINARY_SUBSCR_GETITEM", - [BINARY_SUBSCR_LIST_INT] = "BINARY_SUBSCR_LIST_INT", - [BINARY_SUBSCR_TUPLE_INT] = "BINARY_SUBSCR_TUPLE_INT", - [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS", - [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", - [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", - [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", - [BINARY_SUBSCR] = "BINARY_SUBSCR", - [BINARY_SLICE] = "BINARY_SLICE", - [STORE_SLICE] = "STORE_SLICE", - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", - [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", - [GET_LEN] = "GET_LEN", - [MATCH_MAPPING] = "MATCH_MAPPING", - [MATCH_SEQUENCE] = "MATCH_SEQUENCE", - [MATCH_KEYS] = "MATCH_KEYS", - [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", - [PUSH_EXC_INFO] = "PUSH_EXC_INFO", - [CHECK_EXC_MATCH] = "CHECK_EXC_MATCH", - [CHECK_EG_MATCH] = "CHECK_EG_MATCH", - [CALL_NO_KW_BUILTIN_O] = "CALL_NO_KW_BUILTIN_O", - [CALL_NO_KW_ISINSTANCE] = "CALL_NO_KW_ISINSTANCE", - [CALL_NO_KW_LEN] = "CALL_NO_KW_LEN", - [CALL_NO_KW_LIST_APPEND] = "CALL_NO_KW_LIST_APPEND", - [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", - [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = "CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS", - [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", - [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", - [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", - [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", - [COMPARE_AND_BRANCH_FLOAT] = "COMPARE_AND_BRANCH_FLOAT", - [WITH_EXCEPT_START] = "WITH_EXCEPT_START", - [GET_AITER] = "GET_AITER", - [GET_ANEXT] = "GET_ANEXT", - [BEFORE_ASYNC_WITH] = "BEFORE_ASYNC_WITH", - [BEFORE_WITH] = "BEFORE_WITH", - [END_ASYNC_FOR] = "END_ASYNC_FOR", - [CLEANUP_THROW] = "CLEANUP_THROW", - [COMPARE_AND_BRANCH_INT] = "COMPARE_AND_BRANCH_INT", - [COMPARE_AND_BRANCH_STR] = "COMPARE_AND_BRANCH_STR", - [FOR_ITER_LIST] = "FOR_ITER_LIST", - [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", - [STORE_SUBSCR] = "STORE_SUBSCR", - [DELETE_SUBSCR] = "DELETE_SUBSCR", - [FOR_ITER_RANGE] = "FOR_ITER_RANGE", - [FOR_ITER_GEN] = "FOR_ITER_GEN", - [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", - [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", - [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", - [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", - [GET_ITER] = "GET_ITER", - [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", - [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", - [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", - [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", - [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", - [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", - [RETURN_GENERATOR] = "RETURN_GENERATOR", - [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", - [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", - [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", - [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", - [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", - [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", - [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", - [RETURN_VALUE] = "RETURN_VALUE", - [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", - [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", - [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", - [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", - [PREP_RERAISE_STAR] = "PREP_RERAISE_STAR", - [POP_EXCEPT] = "POP_EXCEPT", - [STORE_NAME] = "STORE_NAME", - [DELETE_NAME] = "DELETE_NAME", - [UNPACK_SEQUENCE] = "UNPACK_SEQUENCE", - [FOR_ITER] = "FOR_ITER", - [UNPACK_EX] = "UNPACK_EX", - [STORE_ATTR] = "STORE_ATTR", - [DELETE_ATTR] = "DELETE_ATTR", - [STORE_GLOBAL] = "STORE_GLOBAL", - [DELETE_GLOBAL] = "DELETE_GLOBAL", - [SWAP] = "SWAP", - [LOAD_CONST] = "LOAD_CONST", - [LOAD_NAME] = "LOAD_NAME", - [BUILD_TUPLE] = "BUILD_TUPLE", - [BUILD_LIST] = "BUILD_LIST", - [BUILD_SET] = "BUILD_SET", - [BUILD_MAP] = "BUILD_MAP", - [LOAD_ATTR] = "LOAD_ATTR", - [COMPARE_OP] = "COMPARE_OP", - [IMPORT_NAME] = "IMPORT_NAME", - [IMPORT_FROM] = "IMPORT_FROM", - [JUMP_FORWARD] = "JUMP_FORWARD", - [JUMP_IF_FALSE_OR_POP] = "JUMP_IF_FALSE_OR_POP", - [JUMP_IF_TRUE_OR_POP] = "JUMP_IF_TRUE_OR_POP", - [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", - [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", - [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", - [LOAD_GLOBAL] = "LOAD_GLOBAL", - [IS_OP] = "IS_OP", - [CONTAINS_OP] = "CONTAINS_OP", - [RERAISE] = "RERAISE", - [COPY] = "COPY", - [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", - [BINARY_OP] = "BINARY_OP", - [SEND] = "SEND", - [LOAD_FAST] = "LOAD_FAST", - [STORE_FAST] = "STORE_FAST", - [DELETE_FAST] = "DELETE_FAST", - [LOAD_FAST_CHECK] = "LOAD_FAST_CHECK", - [POP_JUMP_IF_NOT_NONE] = "POP_JUMP_IF_NOT_NONE", - [POP_JUMP_IF_NONE] = "POP_JUMP_IF_NONE", - [RAISE_VARARGS] = "RAISE_VARARGS", - [GET_AWAITABLE] = "GET_AWAITABLE", - [MAKE_FUNCTION] = "MAKE_FUNCTION", - [BUILD_SLICE] = "BUILD_SLICE", - [JUMP_BACKWARD_NO_INTERRUPT] = "JUMP_BACKWARD_NO_INTERRUPT", - [MAKE_CELL] = "MAKE_CELL", - [LOAD_CLOSURE] = "LOAD_CLOSURE", - [LOAD_DEREF] = "LOAD_DEREF", - [STORE_DEREF] = "STORE_DEREF", - [DELETE_DEREF] = "DELETE_DEREF", - [JUMP_BACKWARD] = "JUMP_BACKWARD", - [COMPARE_AND_BRANCH] = "COMPARE_AND_BRANCH", - [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", - [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", - [EXTENDED_ARG] = "EXTENDED_ARG", - [LIST_APPEND] = "LIST_APPEND", - [SET_ADD] = "SET_ADD", - [MAP_ADD] = "MAP_ADD", - [LOAD_CLASSDEREF] = "LOAD_CLASSDEREF", - [COPY_FREE_VARS] = "COPY_FREE_VARS", - [YIELD_VALUE] = "YIELD_VALUE", - [RESUME] = "RESUME", - [MATCH_CLASS] = "MATCH_CLASS", - [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", - [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", - [FORMAT_VALUE] = "FORMAT_VALUE", - [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", - [BUILD_STRING] = "BUILD_STRING", - [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", - [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", - [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", - [160] = "<161>", - [BINARY_OP_ADD_INT_REST] = "BINARY_OP_ADD_INT_REST", - [SET_UPDATE] = "SET_UPDATE", - [DICT_MERGE] = "DICT_MERGE", - [DICT_UPDATE] = "DICT_UPDATE", - [165] = "<166>", - [166] = "<167>", - [167] = "<168>", - [168] = "<169>", - [169] = "<170>", - [CALL] = "CALL", - [KW_NAMES] = "KW_NAMES", - [CALL_INTRINSIC_1] = "CALL_INTRINSIC_1", - [173] = "<174>", - [174] = "<175>", - [175] = "<176>", - [176] = "<177>", - [177] = "<178>", - [178] = "<179>", - [179] = "<180>", - [180] = "<181>", - [181] = "<182>", - [182] = "<183>", - [183] = "<184>", - [184] = "<185>", - [185] = "<186>", - [186] = "<187>", - [187] = "<188>", - [188] = "<189>", - [189] = "<190>", - [190] = "<191>", - [191] = "<192>", - [192] = "<193>", - [193] = "<194>", - [194] = "<195>", - [195] = "<196>", - [196] = "<197>", - [197] = "<198>", - [198] = "<199>", - [199] = "<200>", - [200] = "<201>", - [201] = "<202>", - [202] = "<203>", - [203] = "<204>", - [204] = "<205>", - [205] = "<206>", - [206] = "<207>", - [207] = "<208>", - [208] = "<209>", - [209] = "<210>", - [210] = "<211>", - [211] = "<212>", - [212] = "<213>", - [213] = "<214>", - [214] = "<215>", - [215] = "<216>", - [216] = "<217>", - [217] = "<218>", - [218] = "<219>", - [219] = "<220>", - [220] = "<221>", - [221] = "<222>", - [222] = "<223>", - [223] = "<224>", - [224] = "<225>", - [225] = "<226>", - [226] = "<227>", - [227] = "<228>", - [228] = "<229>", - [229] = "<230>", - [230] = "<231>", - [231] = "<232>", - [232] = "<233>", - [233] = "<234>", - [234] = "<235>", - [235] = "<236>", - [236] = "<237>", - [237] = "<238>", - [238] = "<239>", - [239] = "<240>", - [240] = "<241>", - [241] = "<242>", - [242] = "<243>", - [243] = "<244>", - [244] = "<245>", - [245] = "<246>", - [246] = "<247>", - [247] = "<248>", - [248] = "<249>", - [249] = "<250>", - [250] = "<251>", - [251] = "<252>", - [252] = "<253>", - [253] = "<254>", - [DO_TRACING] = "DO_TRACING", - [SETUP_FINALLY] = "SETUP_FINALLY", - [SETUP_CLEANUP] = "SETUP_CLEANUP", - [SETUP_WITH] = "SETUP_WITH", - [POP_BLOCK] = "POP_BLOCK", - [JUMP] = "JUMP", - [JUMP_NO_INTERRUPT] = "JUMP_NO_INTERRUPT", - [LOAD_METHOD] = "LOAD_METHOD", -}; -#endif #define EXTRA_CASES \ - case 166: \ case 167: \ case 168: \ case 169: \ diff --git a/Include/internal/pycore_opcode_macro_to_micro.h b/Include/internal/pycore_opcode_macro_to_micro.h index def9dd5781e5a0..aa9049ee5b9518 100644 --- a/Include/internal/pycore_opcode_macro_to_micro.h +++ b/Include/internal/pycore_opcode_macro_to_micro.h @@ -1,6 +1,7 @@ // This file is generated by Tools\cases_generator\generate_cases.py --macromap // from Python\bytecodes.c // Do not edit! + #ifndef Py_INTERNAL_OPCODE_MACRO_TO_MICRO #define Py_INTERNAL_OPCODE_MACRO_TO_MICRO #ifdef __cplusplus @@ -12,7 +13,7 @@ extern "C" { #endif #include "opcode.h" -static int _Py_MacroOpUOpCount[] = { +extern const int _Py_MacroOpUOpCount[] = { [NOP] = 1, [RESUME] = 1, [LOAD_CLOSURE] = 1, @@ -179,7 +180,7 @@ static int _Py_MacroOpUOpCount[] = { [CACHE] = 1, } -static int _Py_MacroOpToUOp[][2] = { +extern const int _Py_MacroOpToUOp[][2] = { [BINARY_OP_ADD_INT] = {BINARY_OP_ADD_INT_TYPE_CHECK, BINARY_OP_ADD_INT_REST}, } #ifdef __cplusplus diff --git a/Include/opcode.h b/Include/opcode.h index 63e5a4329b27db..93635c89da2626 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -125,8 +125,6 @@ extern "C" { #define JUMP_NO_INTERRUPT 261 #define LOAD_METHOD 262 #define MAX_PSEUDO_OPCODE 262 - -#ifndef Py_TIER2_INTERPRETER #define BINARY_OP_ADD_FLOAT 5 #define BINARY_OP_ADD_INT 6 #define BINARY_OP_ADD_UNICODE 7 @@ -189,10 +187,9 @@ extern "C" { #define UNPACK_SEQUENCE_TUPLE 159 #define UNPACK_SEQUENCE_TWO_TUPLE 160 #define DO_TRACING 255 -#endif - -#ifdef Py_TIER2_INTERPRETER +// Tier 2 interpreter ops #define BINARY_OP_ADD_FLOAT 5 +#define BINARY_OP_ADD_INT 6 #define BINARY_OP_ADD_UNICODE 7 #define BINARY_OP_INPLACE_ADD_UNICODE 8 #define BINARY_OP_MULTIPLY_FLOAT 10 @@ -253,10 +250,8 @@ extern "C" { #define UNPACK_SEQUENCE_TUPLE 159 #define UNPACK_SEQUENCE_TWO_TUPLE 160 #define DO_TRACING 255 -#define BINARY_OP_ADD_INT_TYPE_CHECK 6 -#define BINARY_OP_ADD_INT_REST 161 -#endif - +#define BINARY_OP_ADD_INT_TYPE_CHECK 161 +#define BINARY_OP_ADD_INT_REST 166 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 1d3735d61d0430..94f4b7ec15567c 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -284,18 +284,18 @@ dummy_func( ERROR_IF(sum == NULL, error); } - macro_inst(BINARY_OP_ADD_INT, (unused / 1, left, right -- sum)) { + macro_inst(BINARY_OP_ADD_INT, (unused/1, left, right -- sum)) { U_INST(BINARY_OP_ADD_INT_TYPE_CHECK); U_INST(BINARY_OP_ADD_INT_REST); } - u_inst(BINARY_OP_ADD_INT_TYPE_CHECK, (unused/1, left, right -- left, right)) { + u_inst(BINARY_OP_ADD_INT_TYPE_CHECK, (left, right -- left, right)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); } - u_inst(BINARY_OP_ADD_INT_REST, (unused/1, left, right -- sum)) { + u_inst(BINARY_OP_ADD_INT_REST, (left, right -- sum)) { STAT_INC(BINARY_OP, hit); sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 85d44e9dc1b9ca..da28e41dbc7f70 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2,14 +2,14 @@ // from Python\bytecodes.c // Do not edit! - #define BINARY_OP_ADD_INT_TYPE_CHECK() \ + #define UOP_BINARY_OP_ADD_INT_TYPE_CHECK() \ do { \ assert(cframe.use_tracing == 0);\ DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);\ DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);\ } while (0) - #define BINARY_OP_ADD_INT_REST() \ + #define UOP_BINARY_OP_ADD_INT_REST() \ do { \ STAT_INC(BINARY_OP, hit);\ sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right);\ @@ -406,14 +406,37 @@ PyObject *right = PEEK(1); PyObject *left = PEEK(2); PyObject *sum; - BINARY_OP_ADD_INT_TYPE_CHECK(); - BINARY_OP_ADD_INT_REST(); + UOP_BINARY_OP_ADD_INT_TYPE_CHECK(); + UOP_BINARY_OP_ADD_INT_REST(); STACK_SHRINK(1); POKE(1, sum); JUMPBY(1); DISPATCH(); } + TARGET(BINARY_OP_ADD_INT_TYPE_CHECK) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); + DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); + DISPATCH(); + } + + TARGET(BINARY_OP_ADD_INT_REST) { + PyObject *right = PEEK(1); + PyObject *left = PEEK(2); + PyObject *sum; + STAT_INC(BINARY_OP, hit); + sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); + _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); + _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); + if (sum == NULL) goto pop_2_error; + STACK_SHRINK(1); + POKE(1, sum); + DISPATCH(); + } + TARGET(BINARY_SUBSCR) { PREDICTED(BINARY_SUBSCR); static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 4, "incorrect cache size"); diff --git a/Python/generated_cases_tier2.c.h b/Python/generated_cases_tier2.c.h deleted file mode 100644 index 3a7b35f2c89f4b..00000000000000 --- a/Python/generated_cases_tier2.c.h +++ /dev/null @@ -1,3713 +0,0 @@ -// This file is generated by Tools\cases_generator\generate_cases.py -// from Python\bytecodes.c -// Do not edit! - - TARGET(NOP) { - DISPATCH(); - } - - TARGET(RESUME) { - assert(tstate->cframe == &cframe); - assert(frame == cframe.current_frame); - if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { - goto handle_eval_breaker; - } - DISPATCH(); - } - - TARGET(LOAD_CLOSURE) { - PyObject *value; - /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ - value = GETLOCAL(oparg); - if (value == NULL) goto unbound_local_error; - Py_INCREF(value); - STACK_GROW(1); - POKE(1, value); - DISPATCH(); - } - - TARGET(LOAD_FAST_CHECK) { - PyObject *value; - value = GETLOCAL(oparg); - if (value == NULL) goto unbound_local_error; - Py_INCREF(value); - STACK_GROW(1); - POKE(1, value); - DISPATCH(); - } - - TARGET(LOAD_FAST) { - PyObject *value; - value = GETLOCAL(oparg); - assert(value != NULL); - Py_INCREF(value); - STACK_GROW(1); - POKE(1, value); - DISPATCH(); - } - - TARGET(LOAD_CONST) { - PREDICTED(LOAD_CONST); - PyObject *value; - value = GETITEM(consts, oparg); - Py_INCREF(value); - STACK_GROW(1); - POKE(1, value); - DISPATCH(); - } - - TARGET(STORE_FAST) { - PyObject *value = PEEK(1); - SETLOCAL(oparg, value); - STACK_SHRINK(1); - DISPATCH(); - } - - TARGET(LOAD_FAST__LOAD_FAST) { - PyObject *_tmp_1; - PyObject *_tmp_2; - { - PyObject *value; - value = GETLOCAL(oparg); - assert(value != NULL); - Py_INCREF(value); - _tmp_2 = value; - } - NEXTOPARG(); - JUMPBY(1); - { - PyObject *value; - value = GETLOCAL(oparg); - assert(value != NULL); - Py_INCREF(value); - _tmp_1 = value; - } - STACK_GROW(2); - POKE(1, _tmp_1); - POKE(2, _tmp_2); - DISPATCH(); - } - - TARGET(LOAD_FAST__LOAD_CONST) { - PyObject *_tmp_1; - PyObject *_tmp_2; - { - PyObject *value; - value = GETLOCAL(oparg); - assert(value != NULL); - Py_INCREF(value); - _tmp_2 = value; - } - NEXTOPARG(); - JUMPBY(1); - { - PyObject *value; - value = GETITEM(consts, oparg); - Py_INCREF(value); - _tmp_1 = value; - } - STACK_GROW(2); - POKE(1, _tmp_1); - POKE(2, _tmp_2); - DISPATCH(); - } - - TARGET(STORE_FAST__LOAD_FAST) { - PyObject *_tmp_1 = PEEK(1); - { - PyObject *value = _tmp_1; - SETLOCAL(oparg, value); - } - NEXTOPARG(); - JUMPBY(1); - { - PyObject *value; - value = GETLOCAL(oparg); - assert(value != NULL); - Py_INCREF(value); - _tmp_1 = value; - } - POKE(1, _tmp_1); - DISPATCH(); - } - - TARGET(STORE_FAST__STORE_FAST) { - PyObject *_tmp_1 = PEEK(1); - PyObject *_tmp_2 = PEEK(2); - { - PyObject *value = _tmp_1; - SETLOCAL(oparg, value); - } - NEXTOPARG(); - JUMPBY(1); - { - PyObject *value = _tmp_2; - SETLOCAL(oparg, value); - } - STACK_SHRINK(2); - DISPATCH(); - } - - TARGET(LOAD_CONST__LOAD_FAST) { - PyObject *_tmp_1; - PyObject *_tmp_2; - { - PyObject *value; - value = GETITEM(consts, oparg); - Py_INCREF(value); - _tmp_2 = value; - } - NEXTOPARG(); - JUMPBY(1); - { - PyObject *value; - value = GETLOCAL(oparg); - assert(value != NULL); - Py_INCREF(value); - _tmp_1 = value; - } - STACK_GROW(2); - POKE(1, _tmp_1); - POKE(2, _tmp_2); - DISPATCH(); - } - - TARGET(POP_TOP) { - PyObject *value = PEEK(1); - Py_DECREF(value); - STACK_SHRINK(1); - DISPATCH(); - } - - TARGET(PUSH_NULL) { - PyObject *res; - res = NULL; - STACK_GROW(1); - POKE(1, res); - DISPATCH(); - } - - TARGET(END_FOR) { - PyObject *_tmp_1 = PEEK(1); - PyObject *_tmp_2 = PEEK(2); - { - PyObject *value = _tmp_1; - Py_DECREF(value); - } - { - PyObject *value = _tmp_2; - Py_DECREF(value); - } - STACK_SHRINK(2); - DISPATCH(); - } - - TARGET(UNARY_NEGATIVE) { - PyObject *value = PEEK(1); - PyObject *res; - res = PyNumber_Negative(value); - Py_DECREF(value); - if (res == NULL) goto pop_1_error; - POKE(1, res); - DISPATCH(); - } - - TARGET(UNARY_NOT) { - PyObject *value = PEEK(1); - PyObject *res; - int err = PyObject_IsTrue(value); - Py_DECREF(value); - if (err < 0) goto pop_1_error; - if (err == 0) { - res = Py_True; - } - else { - res = Py_False; - } - Py_INCREF(res); - POKE(1, res); - DISPATCH(); - } - - TARGET(UNARY_INVERT) { - PyObject *value = PEEK(1); - PyObject *res; - res = PyNumber_Invert(value); - Py_DECREF(value); - if (res == NULL) goto pop_1_error; - POKE(1, res); - DISPATCH(); - } - - TARGET(BINARY_OP_MULTIPLY_INT) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); - PyObject *prod; - assert(cframe.use_tracing == 0); - DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); - DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); - STAT_INC(BINARY_OP, hit); - prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); - _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - if (prod == NULL) goto pop_2_error; - STACK_SHRINK(1); - POKE(1, prod); - JUMPBY(1); - DISPATCH(); - } - - TARGET(BINARY_OP_MULTIPLY_FLOAT) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); - PyObject *prod; - assert(cframe.use_tracing == 0); - DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); - DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); - STAT_INC(BINARY_OP, hit); - double dprod = ((PyFloatObject *)left)->ob_fval * - ((PyFloatObject *)right)->ob_fval; - prod = PyFloat_FromDouble(dprod); - _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); - _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - if (prod == NULL) goto pop_2_error; - STACK_SHRINK(1); - POKE(1, prod); - JUMPBY(1); - DISPATCH(); - } - - TARGET(BINARY_OP_SUBTRACT_INT) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); - PyObject *sub; - assert(cframe.use_tracing == 0); - DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); - DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); - STAT_INC(BINARY_OP, hit); - sub = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); - _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - if (sub == NULL) goto pop_2_error; - STACK_SHRINK(1); - POKE(1, sub); - JUMPBY(1); - DISPATCH(); - } - - TARGET(BINARY_OP_SUBTRACT_FLOAT) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); - PyObject *sub; - assert(cframe.use_tracing == 0); - DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); - DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); - STAT_INC(BINARY_OP, hit); - double dsub = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; - sub = PyFloat_FromDouble(dsub); - _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); - _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - if (sub == NULL) goto pop_2_error; - STACK_SHRINK(1); - POKE(1, sub); - JUMPBY(1); - DISPATCH(); - } - - TARGET(BINARY_OP_ADD_UNICODE) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); - PyObject *res; - assert(cframe.use_tracing == 0); - DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); - DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); - STAT_INC(BINARY_OP, hit); - res = PyUnicode_Concat(left, right); - _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); - _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - if (res == NULL) goto pop_2_error; - STACK_SHRINK(1); - POKE(1, res); - JUMPBY(1); - DISPATCH(); - } - - TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); - assert(cframe.use_tracing == 0); - DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); - DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); - _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP]; - assert(_Py_OPCODE(true_next) == STORE_FAST || - _Py_OPCODE(true_next) == STORE_FAST__LOAD_FAST); - PyObject **target_local = &GETLOCAL(_Py_OPARG(true_next)); - DEOPT_IF(*target_local != left, BINARY_OP); - STAT_INC(BINARY_OP, hit); - /* Handle `left = left + right` or `left += right` for str. - * - * When possible, extend `left` in place rather than - * allocating a new PyUnicodeObject. This attempts to avoid - * quadratic behavior when one neglects to use str.join(). - * - * If `left` has only two references remaining (one from - * the stack, one in the locals), DECREFing `left` leaves - * only the locals reference, so PyUnicode_Append knows - * that the string is safe to mutate. - */ - assert(Py_REFCNT(left) >= 2); - _Py_DECREF_NO_DEALLOC(left); - PyUnicode_Append(target_local, right); - _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - if (*target_local == NULL) goto pop_2_error; - // The STORE_FAST is already done. - JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); - STACK_SHRINK(2); - DISPATCH(); - } - - TARGET(BINARY_OP_ADD_FLOAT) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); - PyObject *sum; - assert(cframe.use_tracing == 0); - DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); - DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); - STAT_INC(BINARY_OP, hit); - double dsum = ((PyFloatObject *)left)->ob_fval + - ((PyFloatObject *)right)->ob_fval; - sum = PyFloat_FromDouble(dsum); - _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); - _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - if (sum == NULL) goto pop_2_error; - STACK_SHRINK(1); - POKE(1, sum); - JUMPBY(1); - DISPATCH(); - } - - TARGET(BINARY_OP_ADD_INT_TYPE_CHECK) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); - assert(cframe.use_tracing == 0); - DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); - DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); - JUMPBY(1); - DISPATCH(); - } - - TARGET(BINARY_OP_ADD_INT_REST) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); - PyObject *sum; - STAT_INC(BINARY_OP, hit); - sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); - _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - if (sum == NULL) goto pop_2_error; - STACK_SHRINK(1); - POKE(1, sum); - JUMPBY(1); - DISPATCH(); - } - - TARGET(BINARY_SUBSCR) { - PREDICTED(BINARY_SUBSCR); - static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 4, "incorrect cache size"); - PyObject *sub = PEEK(1); - PyObject *container = PEEK(2); - PyObject *res; - #if ENABLE_SPECIALIZATION - _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; - if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); - next_instr--; - _Py_Specialize_BinarySubscr(container, sub, next_instr); - DISPATCH_SAME_OPARG(); - } - STAT_INC(BINARY_SUBSCR, deferred); - DECREMENT_ADAPTIVE_COUNTER(cache->counter); - #endif /* ENABLE_SPECIALIZATION */ - res = PyObject_GetItem(container, sub); - Py_DECREF(container); - Py_DECREF(sub); - if (res == NULL) goto pop_2_error; - STACK_SHRINK(1); - POKE(1, res); - JUMPBY(4); - DISPATCH(); - } - - TARGET(BINARY_SLICE) { - PyObject *stop = PEEK(1); - PyObject *start = PEEK(2); - PyObject *container = PEEK(3); - PyObject *res; - PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); - // Can't use ERROR_IF() here, because we haven't - // DECREF'ed container yet, and we still own slice. - if (slice == NULL) { - res = NULL; - } - else { - res = PyObject_GetItem(container, slice); - Py_DECREF(slice); - } - Py_DECREF(container); - if (res == NULL) goto pop_3_error; - STACK_SHRINK(2); - POKE(1, res); - DISPATCH(); - } - - TARGET(STORE_SLICE) { - PyObject *stop = PEEK(1); - PyObject *start = PEEK(2); - PyObject *container = PEEK(3); - PyObject *v = PEEK(4); - PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop); - int err; - if (slice == NULL) { - err = 1; - } - else { - err = PyObject_SetItem(container, slice, v); - Py_DECREF(slice); - } - Py_DECREF(v); - Py_DECREF(container); - if (err) goto pop_4_error; - STACK_SHRINK(4); - DISPATCH(); - } - - TARGET(BINARY_SUBSCR_LIST_INT) { - PyObject *sub = PEEK(1); - PyObject *list = PEEK(2); - PyObject *res; - assert(cframe.use_tracing == 0); - DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); - DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); - - // Deopt unless 0 <= sub < PyList_Size(list) - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); - assert(((PyLongObject *)_PyLong_GetZero())->ob_digit[0] == 0); - Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0]; - DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); - STAT_INC(BINARY_SUBSCR, hit); - res = PyList_GET_ITEM(list, index); - assert(res != NULL); - Py_INCREF(res); - _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); - Py_DECREF(list); - STACK_SHRINK(1); - POKE(1, res); - JUMPBY(4); - DISPATCH(); - } - - TARGET(BINARY_SUBSCR_TUPLE_INT) { - PyObject *sub = PEEK(1); - PyObject *tuple = PEEK(2); - PyObject *res; - assert(cframe.use_tracing == 0); - DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); - DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); - - // Deopt unless 0 <= sub < PyTuple_Size(list) - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); - assert(((PyLongObject *)_PyLong_GetZero())->ob_digit[0] == 0); - Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0]; - DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); - STAT_INC(BINARY_SUBSCR, hit); - res = PyTuple_GET_ITEM(tuple, index); - assert(res != NULL); - Py_INCREF(res); - _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); - Py_DECREF(tuple); - STACK_SHRINK(1); - POKE(1, res); - JUMPBY(4); - DISPATCH(); - } - - TARGET(BINARY_SUBSCR_DICT) { - PyObject *sub = PEEK(1); - PyObject *dict = PEEK(2); - PyObject *res; - assert(cframe.use_tracing == 0); - DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR); - STAT_INC(BINARY_SUBSCR, hit); - res = PyDict_GetItemWithError(dict, sub); - if (res == NULL) { - if (!_PyErr_Occurred(tstate)) { - _PyErr_SetKeyError(sub); - } - Py_DECREF(dict); - Py_DECREF(sub); - if (true) goto pop_2_error; - } - Py_INCREF(res); // Do this before DECREF'ing dict, sub - Py_DECREF(dict); - Py_DECREF(sub); - STACK_SHRINK(1); - POKE(1, res); - JUMPBY(4); - DISPATCH(); - } - - TARGET(BINARY_SUBSCR_GETITEM) { - PyObject *sub = PEEK(1); - PyObject *container = PEEK(2); - uint32_t type_version = read_u32(&next_instr[1].cache); - uint16_t func_version = read_u16(&next_instr[3].cache); - PyTypeObject *tp = Py_TYPE(container); - DEOPT_IF(tp->tp_version_tag != type_version, BINARY_SUBSCR); - assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE); - PyObject *cached = ((PyHeapTypeObject *)tp)->_spec_cache.getitem; - assert(PyFunction_Check(cached)); - PyFunctionObject *getitem = (PyFunctionObject *)cached; - DEOPT_IF(getitem->func_version != func_version, BINARY_SUBSCR); - PyCodeObject *code = (PyCodeObject *)getitem->func_code; - assert(code->co_argcount == 2); - DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), BINARY_SUBSCR); - STAT_INC(BINARY_SUBSCR, hit); - Py_INCREF(getitem); - _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, getitem, 2); - STACK_SHRINK(2); - new_frame->localsplus[0] = container; - new_frame->localsplus[1] = sub; - JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); - DISPATCH_INLINED(new_frame); - } - - TARGET(LIST_APPEND) { - PyObject *v = PEEK(1); - PyObject *list = PEEK(2 + (oparg-1)); - if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; - STACK_SHRINK(1); - PREDICT(JUMP_BACKWARD); - DISPATCH(); - } - - TARGET(SET_ADD) { - PyObject *v = PEEK(1); - PyObject *set = PEEK(2 + (oparg-1)); - int err = PySet_Add(set, v); - Py_DECREF(v); - if (err) goto pop_1_error; - STACK_SHRINK(1); - PREDICT(JUMP_BACKWARD); - DISPATCH(); - } - - TARGET(STORE_SUBSCR) { - PREDICTED(STORE_SUBSCR); - PyObject *sub = PEEK(1); - PyObject *container = PEEK(2); - PyObject *v = PEEK(3); - uint16_t counter = read_u16(&next_instr[0].cache); - #if ENABLE_SPECIALIZATION - if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { - assert(cframe.use_tracing == 0); - next_instr--; - _Py_Specialize_StoreSubscr(container, sub, next_instr); - DISPATCH_SAME_OPARG(); - } - STAT_INC(STORE_SUBSCR, deferred); - _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr; - DECREMENT_ADAPTIVE_COUNTER(cache->counter); - #else - (void)counter; // Unused. - #endif /* ENABLE_SPECIALIZATION */ - /* container[sub] = v */ - int err = PyObject_SetItem(container, sub, v); - Py_DECREF(v); - Py_DECREF(container); - Py_DECREF(sub); - if (err) goto pop_3_error; - STACK_SHRINK(3); - JUMPBY(1); - DISPATCH(); - } - - TARGET(STORE_SUBSCR_LIST_INT) { - PyObject *sub = PEEK(1); - PyObject *list = PEEK(2); - PyObject *value = PEEK(3); - assert(cframe.use_tracing == 0); - DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); - DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); - - // Ensure nonnegative, zero-or-one-digit ints. - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), STORE_SUBSCR); - Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0]; - // Ensure index < len(list) - DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); - STAT_INC(STORE_SUBSCR, hit); - - PyObject *old_value = PyList_GET_ITEM(list, index); - PyList_SET_ITEM(list, index, value); - assert(old_value != NULL); - Py_DECREF(old_value); - _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); - Py_DECREF(list); - STACK_SHRINK(3); - JUMPBY(1); - DISPATCH(); - } - - TARGET(STORE_SUBSCR_DICT) { - PyObject *sub = PEEK(1); - PyObject *dict = PEEK(2); - PyObject *value = PEEK(3); - assert(cframe.use_tracing == 0); - DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR); - STAT_INC(STORE_SUBSCR, hit); - int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); - Py_DECREF(dict); - if (err) goto pop_3_error; - STACK_SHRINK(3); - JUMPBY(1); - DISPATCH(); - } - - TARGET(DELETE_SUBSCR) { - PyObject *sub = PEEK(1); - PyObject *container = PEEK(2); - /* del container[sub] */ - int err = PyObject_DelItem(container, sub); - Py_DECREF(container); - Py_DECREF(sub); - if (err) goto pop_2_error; - STACK_SHRINK(2); - DISPATCH(); - } - - TARGET(CALL_INTRINSIC_1) { - PyObject *value = PEEK(1); - PyObject *res; - assert(oparg <= MAX_INTRINSIC_1); - res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); - Py_DECREF(value); - if (res == NULL) goto pop_1_error; - POKE(1, res); - DISPATCH(); - } - - TARGET(RAISE_VARARGS) { - PyObject **args = &PEEK(oparg); - PyObject *cause = NULL, *exc = NULL; - switch (oparg) { - case 2: - cause = args[1]; - /* fall through */ - case 1: - exc = args[0]; - /* fall through */ - case 0: - if (do_raise(tstate, exc, cause)) { STACK_SHRINK(oparg); goto exception_unwind; } - break; - default: - _PyErr_SetString(tstate, PyExc_SystemError, - "bad RAISE_VARARGS oparg"); - break; - } - if (true) { STACK_SHRINK(oparg); goto error; } - } - - TARGET(INTERPRETER_EXIT) { - PyObject *retval = PEEK(1); - assert(frame == &entry_frame); - assert(_PyFrame_IsIncomplete(frame)); - STACK_SHRINK(1); // Since we're not going to DISPATCH() - assert(EMPTY()); - /* Restore previous cframe and return. */ - tstate->cframe = cframe.previous; - tstate->cframe->use_tracing = cframe.use_tracing; - assert(tstate->cframe->current_frame == frame->previous); - assert(!_PyErr_Occurred(tstate)); - _Py_LeaveRecursiveCallTstate(tstate); - return retval; - } - - TARGET(RETURN_VALUE) { - PyObject *retval = PEEK(1); - STACK_SHRINK(1); - assert(EMPTY()); - _PyFrame_SetStackPointer(frame, stack_pointer); - TRACE_FUNCTION_EXIT(); - DTRACE_FUNCTION_EXIT(); - _Py_LeaveRecursiveCallPy(tstate); - assert(frame != &entry_frame); - // GH-99729: We need to unlink the frame *before* clearing it: - _PyInterpreterFrame *dying = frame; - frame = cframe.current_frame = dying->previous; - _PyEvalFrameClearAndPop(tstate, dying); - _PyFrame_StackPush(frame, retval); - goto resume_frame; - } - - TARGET(GET_AITER) { - PyObject *obj = PEEK(1); - PyObject *iter; - unaryfunc getter = NULL; - PyTypeObject *type = Py_TYPE(obj); - - if (type->tp_as_async != NULL) { - getter = type->tp_as_async->am_aiter; - } - - if (getter == NULL) { - _PyErr_Format(tstate, PyExc_TypeError, - "'async for' requires an object with " - "__aiter__ method, got %.100s", - type->tp_name); - Py_DECREF(obj); - if (true) goto pop_1_error; - } - - iter = (*getter)(obj); - Py_DECREF(obj); - if (iter == NULL) goto pop_1_error; - - if (Py_TYPE(iter)->tp_as_async == NULL || - Py_TYPE(iter)->tp_as_async->am_anext == NULL) { - - _PyErr_Format(tstate, PyExc_TypeError, - "'async for' received an object from __aiter__ " - "that does not implement __anext__: %.100s", - Py_TYPE(iter)->tp_name); - Py_DECREF(iter); - if (true) goto pop_1_error; - } - POKE(1, iter); - DISPATCH(); - } - - TARGET(GET_ANEXT) { - PyObject *aiter = PEEK(1); - PyObject *awaitable; - unaryfunc getter = NULL; - PyObject *next_iter = NULL; - PyTypeObject *type = Py_TYPE(aiter); - - if (PyAsyncGen_CheckExact(aiter)) { - awaitable = type->tp_as_async->am_anext(aiter); - if (awaitable == NULL) { - goto error; - } - } else { - if (type->tp_as_async != NULL){ - getter = type->tp_as_async->am_anext; - } - - if (getter != NULL) { - next_iter = (*getter)(aiter); - if (next_iter == NULL) { - goto error; - } - } - else { - _PyErr_Format(tstate, PyExc_TypeError, - "'async for' requires an iterator with " - "__anext__ method, got %.100s", - type->tp_name); - goto error; - } - - awaitable = _PyCoro_GetAwaitableIter(next_iter); - if (awaitable == NULL) { - _PyErr_FormatFromCause( - PyExc_TypeError, - "'async for' received an invalid object " - "from __anext__: %.100s", - Py_TYPE(next_iter)->tp_name); - - Py_DECREF(next_iter); - goto error; - } else { - Py_DECREF(next_iter); - } - } - - STACK_GROW(1); - POKE(1, awaitable); - PREDICT(LOAD_CONST); - DISPATCH(); - } - - TARGET(GET_AWAITABLE) { - PREDICTED(GET_AWAITABLE); - PyObject *iterable = PEEK(1); - PyObject *iter; - iter = _PyCoro_GetAwaitableIter(iterable); - - if (iter == NULL) { - format_awaitable_error(tstate, Py_TYPE(iterable), oparg); - } - - Py_DECREF(iterable); - - if (iter != NULL && PyCoro_CheckExact(iter)) { - PyObject *yf = _PyGen_yf((PyGenObject*)iter); - if (yf != NULL) { - /* `iter` is a coroutine object that is being - awaited, `yf` is a pointer to the current awaitable - being awaited on. */ - Py_DECREF(yf); - Py_CLEAR(iter); - _PyErr_SetString(tstate, PyExc_RuntimeError, - "coroutine is being awaited already"); - /* The code below jumps to `error` if `iter` is NULL. */ - } - } - - if (iter == NULL) goto pop_1_error; - - POKE(1, iter); - PREDICT(LOAD_CONST); - DISPATCH(); - } - - TARGET(SEND) { - assert(frame != &entry_frame); - assert(STACK_LEVEL() >= 2); - PyObject *v = POP(); - PyObject *receiver = TOP(); - PySendResult gen_status; - PyObject *retval; - if (tstate->c_tracefunc == NULL) { - gen_status = PyIter_Send(receiver, v, &retval); - } else { - if (Py_IsNone(v) && PyIter_Check(receiver)) { - retval = Py_TYPE(receiver)->tp_iternext(receiver); - } - else { - retval = PyObject_CallMethodOneArg(receiver, &_Py_ID(send), v); - } - if (retval == NULL) { - if (tstate->c_tracefunc != NULL - && _PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) - call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame); - if (_PyGen_FetchStopIterationValue(&retval) == 0) { - gen_status = PYGEN_RETURN; - } - else { - gen_status = PYGEN_ERROR; - } - } - else { - gen_status = PYGEN_NEXT; - } - } - Py_DECREF(v); - if (gen_status == PYGEN_ERROR) { - assert(retval == NULL); - goto error; - } - if (gen_status == PYGEN_RETURN) { - assert(retval != NULL); - Py_DECREF(receiver); - SET_TOP(retval); - JUMPBY(oparg); - } - else { - assert(gen_status == PYGEN_NEXT); - assert(retval != NULL); - PUSH(retval); - } - DISPATCH(); - } - - TARGET(YIELD_VALUE) { - PyObject *retval = PEEK(1); - // 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. - assert(frame != &entry_frame); - PyGenObject *gen = _PyFrame_GetGenerator(frame); - gen->gi_frame_state = FRAME_SUSPENDED; - _PyFrame_SetStackPointer(frame, stack_pointer - 1); - TRACE_FUNCTION_EXIT(); - DTRACE_FUNCTION_EXIT(); - tstate->exc_info = gen->gi_exc_state.previous_item; - gen->gi_exc_state.previous_item = NULL; - _Py_LeaveRecursiveCallPy(tstate); - _PyInterpreterFrame *gen_frame = frame; - frame = cframe.current_frame = frame->previous; - gen_frame->previous = NULL; - frame->prev_instr -= frame->yield_offset; - _PyFrame_StackPush(frame, retval); - goto resume_frame; - } - - TARGET(POP_EXCEPT) { - PyObject *exc_value = PEEK(1); - _PyErr_StackItem *exc_info = tstate->exc_info; - Py_XSETREF(exc_info->exc_value, exc_value); - STACK_SHRINK(1); - DISPATCH(); - } - - TARGET(RERAISE) { - if (oparg) { - PyObject *lasti = PEEK(oparg + 1); - if (PyLong_Check(lasti)) { - frame->prev_instr = _PyCode_CODE(frame->f_code) + PyLong_AsLong(lasti); - assert(!_PyErr_Occurred(tstate)); - } - else { - assert(PyLong_Check(lasti)); - _PyErr_SetString(tstate, PyExc_SystemError, "lasti is not an int"); - goto error; - } - } - PyObject *val = POP(); - assert(val && PyExceptionInstance_Check(val)); - PyObject *exc = Py_NewRef(PyExceptionInstance_Class(val)); - PyObject *tb = PyException_GetTraceback(val); - _PyErr_Restore(tstate, exc, val, tb); - goto exception_unwind; - } - - TARGET(PREP_RERAISE_STAR) { - PyObject *excs = PEEK(1); - PyObject *orig = PEEK(2); - PyObject *val; - assert(PyList_Check(excs)); - - val = _PyExc_PrepReraiseStar(orig, excs); - Py_DECREF(orig); - Py_DECREF(excs); - - if (val == NULL) goto pop_2_error; - STACK_SHRINK(1); - POKE(1, val); - DISPATCH(); - } - - TARGET(END_ASYNC_FOR) { - PyObject *val = POP(); - assert(val && PyExceptionInstance_Check(val)); - if (PyErr_GivenExceptionMatches(val, PyExc_StopAsyncIteration)) { - Py_DECREF(val); - Py_DECREF(POP()); - } - else { - PyObject *exc = Py_NewRef(PyExceptionInstance_Class(val)); - PyObject *tb = PyException_GetTraceback(val); - _PyErr_Restore(tstate, exc, val, tb); - goto exception_unwind; - } - DISPATCH(); - } - - TARGET(CLEANUP_THROW) { - assert(throwflag); - PyObject *exc_value = TOP(); - assert(exc_value && PyExceptionInstance_Check(exc_value)); - if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) { - PyObject *value = ((PyStopIterationObject *)exc_value)->value; - Py_INCREF(value); - Py_DECREF(POP()); // The StopIteration. - Py_DECREF(POP()); // The last sent value. - Py_DECREF(POP()); // The delegated sub-iterator. - PUSH(value); - } - else { - PyObject *exc_type = Py_NewRef(Py_TYPE(exc_value)); - PyObject *exc_traceback = PyException_GetTraceback(exc_value); - _PyErr_Restore(tstate, exc_type, Py_NewRef(exc_value), exc_traceback); - goto exception_unwind; - } - DISPATCH(); - } - - TARGET(LOAD_ASSERTION_ERROR) { - PyObject *value; - value = Py_NewRef(PyExc_AssertionError); - STACK_GROW(1); - POKE(1, value); - DISPATCH(); - } - - TARGET(LOAD_BUILD_CLASS) { - PyObject *bc; - if (PyDict_CheckExact(BUILTINS())) { - bc = _PyDict_GetItemWithError(BUILTINS(), - &_Py_ID(__build_class__)); - if (bc == NULL) { - if (!_PyErr_Occurred(tstate)) { - _PyErr_SetString(tstate, PyExc_NameError, - "__build_class__ not found"); - } - if (true) goto error; - } - Py_INCREF(bc); - } - else { - bc = PyObject_GetItem(BUILTINS(), &_Py_ID(__build_class__)); - if (bc == NULL) { - if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) - _PyErr_SetString(tstate, PyExc_NameError, - "__build_class__ not found"); - if (true) goto error; - } - } - STACK_GROW(1); - POKE(1, bc); - DISPATCH(); - } - - TARGET(STORE_NAME) { - PyObject *v = PEEK(1); - PyObject *name = GETITEM(names, oparg); - PyObject *ns = LOCALS(); - int err; - if (ns == NULL) { - _PyErr_Format(tstate, PyExc_SystemError, - "no locals found when storing %R", name); - Py_DECREF(v); - if (true) goto pop_1_error; - } - if (PyDict_CheckExact(ns)) - err = PyDict_SetItem(ns, name, v); - else - err = PyObject_SetItem(ns, name, v); - Py_DECREF(v); - if (err) goto pop_1_error; - STACK_SHRINK(1); - DISPATCH(); - } - - TARGET(DELETE_NAME) { - PyObject *name = GETITEM(names, oparg); - PyObject *ns = LOCALS(); - int err; - if (ns == NULL) { - _PyErr_Format(tstate, PyExc_SystemError, - "no locals when deleting %R", name); - goto error; - } - err = PyObject_DelItem(ns, name); - // Can't use ERROR_IF here. - if (err != 0) { - format_exc_check_arg(tstate, PyExc_NameError, - NAME_ERROR_MSG, - name); - goto error; - } - DISPATCH(); - } - - TARGET(UNPACK_SEQUENCE) { - PREDICTED(UNPACK_SEQUENCE); - #if ENABLE_SPECIALIZATION - _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; - if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); - PyObject *seq = TOP(); - next_instr--; - _Py_Specialize_UnpackSequence(seq, next_instr, oparg); - DISPATCH_SAME_OPARG(); - } - STAT_INC(UNPACK_SEQUENCE, deferred); - DECREMENT_ADAPTIVE_COUNTER(cache->counter); - #endif /* ENABLE_SPECIALIZATION */ - PyObject *seq = POP(); - PyObject **top = stack_pointer + oparg; - if (!unpack_iterable(tstate, seq, oparg, -1, top)) { - Py_DECREF(seq); - goto error; - } - STACK_GROW(oparg); - Py_DECREF(seq); - JUMPBY(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE); - DISPATCH(); - } - - TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { - PyObject *seq = TOP(); - DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); - DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); - STAT_INC(UNPACK_SEQUENCE, hit); - SET_TOP(Py_NewRef(PyTuple_GET_ITEM(seq, 1))); - PUSH(Py_NewRef(PyTuple_GET_ITEM(seq, 0))); - Py_DECREF(seq); - JUMPBY(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE); - DISPATCH(); - } - - TARGET(UNPACK_SEQUENCE_TUPLE) { - PyObject *seq = TOP(); - DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); - DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); - STAT_INC(UNPACK_SEQUENCE, hit); - STACK_SHRINK(1); - PyObject **items = _PyTuple_ITEMS(seq); - while (oparg--) { - PUSH(Py_NewRef(items[oparg])); - } - Py_DECREF(seq); - JUMPBY(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE); - DISPATCH(); - } - - TARGET(UNPACK_SEQUENCE_LIST) { - PyObject *seq = TOP(); - DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE); - DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE); - STAT_INC(UNPACK_SEQUENCE, hit); - STACK_SHRINK(1); - PyObject **items = _PyList_ITEMS(seq); - while (oparg--) { - PUSH(Py_NewRef(items[oparg])); - } - Py_DECREF(seq); - JUMPBY(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE); - DISPATCH(); - } - - TARGET(UNPACK_EX) { - int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); - PyObject *seq = POP(); - PyObject **top = stack_pointer + totalargs; - if (!unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top)) { - Py_DECREF(seq); - goto error; - } - STACK_GROW(totalargs); - Py_DECREF(seq); - DISPATCH(); - } - - TARGET(STORE_ATTR) { - PREDICTED(STORE_ATTR); - PyObject *owner = PEEK(1); - PyObject *v = PEEK(2); - uint16_t counter = read_u16(&next_instr[0].cache); - #if ENABLE_SPECIALIZATION - if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { - assert(cframe.use_tracing == 0); - PyObject *name = GETITEM(names, oparg); - next_instr--; - _Py_Specialize_StoreAttr(owner, next_instr, name); - DISPATCH_SAME_OPARG(); - } - STAT_INC(STORE_ATTR, deferred); - _PyAttrCache *cache = (_PyAttrCache *)next_instr; - DECREMENT_ADAPTIVE_COUNTER(cache->counter); - #else - (void)counter; // Unused. - #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(names, oparg); - int err = PyObject_SetAttr(owner, name, v); - Py_DECREF(v); - Py_DECREF(owner); - if (err) goto pop_2_error; - STACK_SHRINK(2); - JUMPBY(4); - DISPATCH(); - } - - TARGET(DELETE_ATTR) { - PyObject *owner = PEEK(1); - PyObject *name = GETITEM(names, oparg); - int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - Py_DECREF(owner); - if (err) goto pop_1_error; - STACK_SHRINK(1); - DISPATCH(); - } - - TARGET(STORE_GLOBAL) { - PyObject *v = PEEK(1); - PyObject *name = GETITEM(names, oparg); - int err = PyDict_SetItem(GLOBALS(), name, v); - Py_DECREF(v); - if (err) goto pop_1_error; - STACK_SHRINK(1); - DISPATCH(); - } - - TARGET(DELETE_GLOBAL) { - PyObject *name = GETITEM(names, oparg); - int err; - err = PyDict_DelItem(GLOBALS(), name); - // Can't use ERROR_IF here. - if (err != 0) { - if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - format_exc_check_arg(tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } - goto error; - } - DISPATCH(); - } - - TARGET(LOAD_NAME) { - PyObject *v; - PyObject *name = GETITEM(names, oparg); - PyObject *locals = LOCALS(); - if (locals == NULL) { - _PyErr_Format(tstate, PyExc_SystemError, - "no locals when loading %R", name); - goto error; - } - if (PyDict_CheckExact(locals)) { - v = PyDict_GetItemWithError(locals, name); - if (v != NULL) { - Py_INCREF(v); - } - else if (_PyErr_Occurred(tstate)) { - goto error; - } - } - else { - v = PyObject_GetItem(locals, name); - if (v == NULL) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) - goto error; - _PyErr_Clear(tstate); - } - } - if (v == NULL) { - v = PyDict_GetItemWithError(GLOBALS(), name); - if (v != NULL) { - Py_INCREF(v); - } - else if (_PyErr_Occurred(tstate)) { - goto error; - } - else { - if (PyDict_CheckExact(BUILTINS())) { - v = PyDict_GetItemWithError(BUILTINS(), name); - if (v == NULL) { - if (!_PyErr_Occurred(tstate)) { - format_exc_check_arg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } - goto error; - } - Py_INCREF(v); - } - else { - v = PyObject_GetItem(BUILTINS(), name); - if (v == NULL) { - if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - format_exc_check_arg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } - goto error; - } - } - } - } - STACK_GROW(1); - POKE(1, v); - DISPATCH(); - } - - TARGET(LOAD_GLOBAL) { - PREDICTED(LOAD_GLOBAL); - #if ENABLE_SPECIALIZATION - _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; - if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); - PyObject *name = GETITEM(names, oparg>>1); - next_instr--; - _Py_Specialize_LoadGlobal(GLOBALS(), BUILTINS(), next_instr, name); - DISPATCH_SAME_OPARG(); - } - STAT_INC(LOAD_GLOBAL, deferred); - DECREMENT_ADAPTIVE_COUNTER(cache->counter); - #endif /* ENABLE_SPECIALIZATION */ - int push_null = oparg & 1; - PEEK(0) = NULL; - PyObject *name = GETITEM(names, oparg>>1); - PyObject *v; - if (PyDict_CheckExact(GLOBALS()) - && PyDict_CheckExact(BUILTINS())) - { - v = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(), - (PyDictObject *)BUILTINS(), - name); - if (v == NULL) { - if (!_PyErr_Occurred(tstate)) { - /* _PyDict_LoadGlobal() returns NULL without raising - * an exception if the key doesn't exist */ - format_exc_check_arg(tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } - goto error; - } - Py_INCREF(v); - } - else { - /* Slow-path if globals or builtins is not a dict */ - - /* namespace 1: globals */ - v = PyObject_GetItem(GLOBALS(), name); - if (v == NULL) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - goto error; - } - _PyErr_Clear(tstate); - - /* namespace 2: builtins */ - v = PyObject_GetItem(BUILTINS(), name); - if (v == NULL) { - if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - format_exc_check_arg( - tstate, PyExc_NameError, - NAME_ERROR_MSG, name); - } - goto error; - } - } - } - /* Skip over inline cache */ - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_GLOBAL); - STACK_GROW(push_null); - PUSH(v); - DISPATCH(); - } - - TARGET(LOAD_GLOBAL_MODULE) { - assert(cframe.use_tracing == 0); - DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); - PyDictObject *dict = (PyDictObject *)GLOBALS(); - _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; - uint32_t version = read_u32(cache->module_keys_version); - DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL); - assert(DK_IS_UNICODE(dict->ma_keys)); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys); - PyObject *res = entries[cache->index].me_value; - DEOPT_IF(res == NULL, LOAD_GLOBAL); - int push_null = oparg & 1; - PEEK(0) = NULL; - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_GLOBAL); - STAT_INC(LOAD_GLOBAL, hit); - STACK_GROW(push_null+1); - SET_TOP(Py_NewRef(res)); - DISPATCH(); - } - - TARGET(LOAD_GLOBAL_BUILTIN) { - assert(cframe.use_tracing == 0); - DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL); - DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL); - PyDictObject *mdict = (PyDictObject *)GLOBALS(); - PyDictObject *bdict = (PyDictObject *)BUILTINS(); - _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; - uint32_t mod_version = read_u32(cache->module_keys_version); - uint16_t bltn_version = cache->builtin_keys_version; - DEOPT_IF(mdict->ma_keys->dk_version != mod_version, LOAD_GLOBAL); - DEOPT_IF(bdict->ma_keys->dk_version != bltn_version, LOAD_GLOBAL); - assert(DK_IS_UNICODE(bdict->ma_keys)); - PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys); - PyObject *res = entries[cache->index].me_value; - DEOPT_IF(res == NULL, LOAD_GLOBAL); - int push_null = oparg & 1; - PEEK(0) = NULL; - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_GLOBAL); - STAT_INC(LOAD_GLOBAL, hit); - STACK_GROW(push_null+1); - SET_TOP(Py_NewRef(res)); - DISPATCH(); - } - - TARGET(DELETE_FAST) { - PyObject *v = GETLOCAL(oparg); - if (v == NULL) goto unbound_local_error; - SETLOCAL(oparg, NULL); - DISPATCH(); - } - - TARGET(MAKE_CELL) { - // "initial" is probably NULL but not if it's an arg (or set - // via PyFrame_LocalsToFast() before MAKE_CELL has run). - PyObject *initial = GETLOCAL(oparg); - PyObject *cell = PyCell_New(initial); - if (cell == NULL) { - goto resume_with_error; - } - SETLOCAL(oparg, cell); - DISPATCH(); - } - - TARGET(DELETE_DEREF) { - PyObject *cell = GETLOCAL(oparg); - PyObject *oldobj = PyCell_GET(cell); - // Can't use ERROR_IF here. - // Fortunately we don't need its superpower. - if (oldobj == NULL) { - format_exc_unbound(tstate, frame->f_code, oparg); - goto error; - } - PyCell_SET(cell, NULL); - Py_DECREF(oldobj); - DISPATCH(); - } - - TARGET(LOAD_CLASSDEREF) { - PyObject *value; - PyObject *name, *locals = LOCALS(); - assert(locals); - assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus); - name = PyTuple_GET_ITEM(frame->f_code->co_localsplusnames, oparg); - if (PyDict_CheckExact(locals)) { - value = PyDict_GetItemWithError(locals, name); - if (value != NULL) { - Py_INCREF(value); - } - else if (_PyErr_Occurred(tstate)) { - goto error; - } - } - else { - value = PyObject_GetItem(locals, name); - if (value == NULL) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) { - goto error; - } - _PyErr_Clear(tstate); - } - } - if (!value) { - PyObject *cell = GETLOCAL(oparg); - value = PyCell_GET(cell); - if (value == NULL) { - format_exc_unbound(tstate, frame->f_code, oparg); - goto error; - } - Py_INCREF(value); - } - STACK_GROW(1); - POKE(1, value); - DISPATCH(); - } - - TARGET(LOAD_DEREF) { - PyObject *value; - PyObject *cell = GETLOCAL(oparg); - value = PyCell_GET(cell); - if (value == NULL) { - format_exc_unbound(tstate, frame->f_code, oparg); - if (true) goto error; - } - Py_INCREF(value); - STACK_GROW(1); - POKE(1, value); - DISPATCH(); - } - - TARGET(STORE_DEREF) { - PyObject *v = PEEK(1); - PyObject *cell = GETLOCAL(oparg); - PyObject *oldobj = PyCell_GET(cell); - PyCell_SET(cell, v); - Py_XDECREF(oldobj); - STACK_SHRINK(1); - DISPATCH(); - } - - TARGET(COPY_FREE_VARS) { - /* Copy closure variables to free variables */ - PyCodeObject *co = frame->f_code; - assert(PyFunction_Check(frame->f_funcobj)); - PyObject *closure = ((PyFunctionObject *)frame->f_funcobj)->func_closure; - assert(oparg == co->co_nfreevars); - int offset = co->co_nlocalsplus - oparg; - for (int i = 0; i < oparg; ++i) { - PyObject *o = PyTuple_GET_ITEM(closure, i); - frame->localsplus[offset + i] = Py_NewRef(o); - } - DISPATCH(); - } - - TARGET(BUILD_STRING) { - PyObject **pieces = &PEEK(oparg); - PyObject *str; - str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - for (int i = 0; i < oparg; i++) { - Py_DECREF(pieces[i]); - } - if (str == NULL) { STACK_SHRINK(oparg); goto error; } - STACK_SHRINK(oparg); - STACK_GROW(1); - POKE(1, str); - DISPATCH(); - } - - TARGET(BUILD_TUPLE) { - PyObject **values = &PEEK(oparg); - PyObject *tup; - tup = _PyTuple_FromArraySteal(values, oparg); - if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - STACK_SHRINK(oparg); - STACK_GROW(1); - POKE(1, tup); - DISPATCH(); - } - - TARGET(BUILD_LIST) { - PyObject **values = &PEEK(oparg); - PyObject *list; - list = _PyList_FromArraySteal(values, oparg); - if (list == NULL) { STACK_SHRINK(oparg); goto error; } - STACK_SHRINK(oparg); - STACK_GROW(1); - POKE(1, list); - DISPATCH(); - } - - TARGET(LIST_EXTEND) { - PyObject *iterable = PEEK(1); - PyObject *list = PEEK(2 + (oparg-1)); - PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); - if (none_val == NULL) { - if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && - (Py_TYPE(iterable)->tp_iter == NULL && !PySequence_Check(iterable))) - { - _PyErr_Clear(tstate); - _PyErr_Format(tstate, PyExc_TypeError, - "Value after * must be an iterable, not %.200s", - Py_TYPE(iterable)->tp_name); - } - Py_DECREF(iterable); - if (true) goto pop_1_error; - } - Py_DECREF(none_val); - Py_DECREF(iterable); - STACK_SHRINK(1); - DISPATCH(); - } - - TARGET(SET_UPDATE) { - PyObject *iterable = PEEK(1); - PyObject *set = PEEK(2 + (oparg-1)); - int err = _PySet_Update(set, iterable); - Py_DECREF(iterable); - if (err < 0) goto pop_1_error; - STACK_SHRINK(1); - DISPATCH(); - } - - TARGET(BUILD_SET) { - PyObject **values = &PEEK(oparg); - PyObject *set; - set = PySet_New(NULL); - int err = 0; - for (int i = 0; i < oparg; i++) { - PyObject *item = values[i]; - if (err == 0) - err = PySet_Add(set, item); - Py_DECREF(item); - } - if (err != 0) { - Py_DECREF(set); - if (true) { STACK_SHRINK(oparg); goto error; } - } - STACK_SHRINK(oparg); - STACK_GROW(1); - POKE(1, set); - DISPATCH(); - } - - TARGET(BUILD_MAP) { - PyObject **values = &PEEK(oparg*2); - PyObject *map; - map = _PyDict_FromItems( - values, 2, - values+1, 2, - oparg); - if (map == NULL) - goto error; - - for (int i = 0; i < oparg; i++) { - Py_DECREF(values[i*2]); - Py_DECREF(values[i*2+1]); - } - if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - STACK_SHRINK(oparg*2); - STACK_GROW(1); - POKE(1, map); - DISPATCH(); - } - - TARGET(SETUP_ANNOTATIONS) { - int err; - PyObject *ann_dict; - if (LOCALS() == NULL) { - _PyErr_Format(tstate, PyExc_SystemError, - "no locals found when setting up annotations"); - if (true) goto error; - } - /* check if __annotations__ in locals()... */ - if (PyDict_CheckExact(LOCALS())) { - ann_dict = _PyDict_GetItemWithError(LOCALS(), - &_Py_ID(__annotations__)); - if (ann_dict == NULL) { - if (_PyErr_Occurred(tstate)) goto error; - /* ...if not, create a new one */ - ann_dict = PyDict_New(); - if (ann_dict == NULL) goto error; - err = PyDict_SetItem(LOCALS(), &_Py_ID(__annotations__), - ann_dict); - Py_DECREF(ann_dict); - if (err) goto error; - } - } - else { - /* do the same if locals() is not a dict */ - ann_dict = PyObject_GetItem(LOCALS(), &_Py_ID(__annotations__)); - if (ann_dict == NULL) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) goto error; - _PyErr_Clear(tstate); - ann_dict = PyDict_New(); - if (ann_dict == NULL) goto error; - err = PyObject_SetItem(LOCALS(), &_Py_ID(__annotations__), - ann_dict); - Py_DECREF(ann_dict); - if (err) goto error; - } - else { - Py_DECREF(ann_dict); - } - } - DISPATCH(); - } - - TARGET(BUILD_CONST_KEY_MAP) { - PyObject *keys = PEEK(1); - PyObject **values = &PEEK(1 + oparg); - PyObject *map; - if (!PyTuple_CheckExact(keys) || - PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { - _PyErr_SetString(tstate, PyExc_SystemError, - "bad BUILD_CONST_KEY_MAP keys argument"); - goto error; // Pop the keys and values. - } - map = _PyDict_FromItems( - &PyTuple_GET_ITEM(keys, 0), 1, - values, 1, oparg); - Py_DECREF(keys); - for (int i = 0; i < oparg; i++) { - Py_DECREF(values[i]); - } - if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - STACK_SHRINK(oparg); - POKE(1, map); - DISPATCH(); - } - - TARGET(DICT_UPDATE) { - PyObject *update = PEEK(1); - PyObject *dict = PEEK(oparg + 1); // update is still on the stack - if (PyDict_Update(dict, update) < 0) { - if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) { - _PyErr_Format(tstate, PyExc_TypeError, - "'%.200s' object is not a mapping", - Py_TYPE(update)->tp_name); - } - Py_DECREF(update); - if (true) goto pop_1_error; - } - Py_DECREF(update); - STACK_SHRINK(1); - DISPATCH(); - } - - TARGET(DICT_MERGE) { - PyObject *update = PEEK(1); - PyObject *dict = PEEK(oparg + 1); // update is still on the stack - - if (_PyDict_MergeEx(dict, update, 2) < 0) { - format_kwargs_error(tstate, PEEK(3 + oparg), update); - Py_DECREF(update); - if (true) goto pop_1_error; - } - Py_DECREF(update); - STACK_SHRINK(1); - PREDICT(CALL_FUNCTION_EX); - DISPATCH(); - } - - TARGET(MAP_ADD) { - PyObject *value = PEEK(1); - PyObject *key = PEEK(2); - PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack - assert(PyDict_CheckExact(dict)); - /* dict[key] = value */ - // Do not DECREF INPUTS because the function steals the references - if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error; - STACK_SHRINK(2); - PREDICT(JUMP_BACKWARD); - DISPATCH(); - } - - TARGET(LOAD_ATTR) { - PREDICTED(LOAD_ATTR); - #if ENABLE_SPECIALIZATION - _PyAttrCache *cache = (_PyAttrCache *)next_instr; - if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); - PyObject *owner = TOP(); - PyObject *name = GETITEM(names, oparg>>1); - next_instr--; - _Py_Specialize_LoadAttr(owner, next_instr, name); - DISPATCH_SAME_OPARG(); - } - STAT_INC(LOAD_ATTR, deferred); - DECREMENT_ADAPTIVE_COUNTER(cache->counter); - #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(names, oparg >> 1); - PyObject *owner = TOP(); - if (oparg & 1) { - /* Designed to work in tandem with CALL. */ - PyObject* meth = NULL; - - int meth_found = _PyObject_GetMethod(owner, name, &meth); - - if (meth == NULL) { - /* Most likely attribute wasn't found. */ - goto error; - } - - if (meth_found) { - /* We can bypass temporary bound method object. - meth is unbound method and obj is self. - - meth | self | arg1 | ... | argN - */ - SET_TOP(meth); - PUSH(owner); // self - } - else { - /* meth is not an unbound method (but a regular attr, or - something was returned by a descriptor protocol). Set - the second element of the stack to NULL, to signal - CALL that it's not a method call. - - NULL | meth | arg1 | ... | argN - */ - SET_TOP(NULL); - Py_DECREF(owner); - PUSH(meth); - } - } - else { - PyObject *res = PyObject_GetAttr(owner, name); - if (res == NULL) { - goto error; - } - Py_DECREF(owner); - SET_TOP(res); - } - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); - DISPATCH(); - } - - TARGET(LOAD_ATTR_INSTANCE_VALUE) { - assert(cframe.use_tracing == 0); - PyObject *owner = TOP(); - PyObject *res; - PyTypeObject *tp = Py_TYPE(owner); - _PyAttrCache *cache = (_PyAttrCache *)next_instr; - uint32_t type_version = read_u32(cache->version); - assert(type_version != 0); - DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); - assert(tp->tp_dictoffset < 0); - assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); - PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); - DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR); - res = _PyDictOrValues_GetValues(dorv)->values[cache->index]; - DEOPT_IF(res == NULL, LOAD_ATTR); - STAT_INC(LOAD_ATTR, hit); - Py_INCREF(res); - SET_TOP(NULL); - STACK_GROW((oparg & 1)); - SET_TOP(res); - Py_DECREF(owner); - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); - DISPATCH(); - } - - TARGET(LOAD_ATTR_MODULE) { - assert(cframe.use_tracing == 0); - PyObject *owner = TOP(); - PyObject *res; - _PyAttrCache *cache = (_PyAttrCache *)next_instr; - DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); - PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; - assert(dict != NULL); - DEOPT_IF(dict->ma_keys->dk_version != read_u32(cache->version), - LOAD_ATTR); - assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE); - assert(cache->index < dict->ma_keys->dk_nentries); - PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + cache->index; - res = ep->me_value; - DEOPT_IF(res == NULL, LOAD_ATTR); - STAT_INC(LOAD_ATTR, hit); - Py_INCREF(res); - SET_TOP(NULL); - STACK_GROW((oparg & 1)); - SET_TOP(res); - Py_DECREF(owner); - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); - DISPATCH(); - } - - TARGET(LOAD_ATTR_WITH_HINT) { - assert(cframe.use_tracing == 0); - PyObject *owner = TOP(); - PyObject *res; - PyTypeObject *tp = Py_TYPE(owner); - _PyAttrCache *cache = (_PyAttrCache *)next_instr; - uint32_t type_version = read_u32(cache->version); - assert(type_version != 0); - DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); - assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); - PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); - DEOPT_IF(_PyDictOrValues_IsValues(dorv), LOAD_ATTR); - PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); - DEOPT_IF(dict == NULL, LOAD_ATTR); - assert(PyDict_CheckExact((PyObject *)dict)); - PyObject *name = GETITEM(names, oparg>>1); - uint16_t hint = cache->index; - DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, LOAD_ATTR); - if (DK_IS_UNICODE(dict->ma_keys)) { - PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; - DEOPT_IF(ep->me_key != name, LOAD_ATTR); - res = ep->me_value; - } - else { - PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint; - DEOPT_IF(ep->me_key != name, LOAD_ATTR); - res = ep->me_value; - } - DEOPT_IF(res == NULL, LOAD_ATTR); - STAT_INC(LOAD_ATTR, hit); - Py_INCREF(res); - SET_TOP(NULL); - STACK_GROW((oparg & 1)); - SET_TOP(res); - Py_DECREF(owner); - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); - DISPATCH(); - } - - TARGET(LOAD_ATTR_SLOT) { - assert(cframe.use_tracing == 0); - PyObject *owner = TOP(); - PyObject *res; - PyTypeObject *tp = Py_TYPE(owner); - _PyAttrCache *cache = (_PyAttrCache *)next_instr; - uint32_t type_version = read_u32(cache->version); - assert(type_version != 0); - DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); - char *addr = (char *)owner + cache->index; - res = *(PyObject **)addr; - DEOPT_IF(res == NULL, LOAD_ATTR); - STAT_INC(LOAD_ATTR, hit); - Py_INCREF(res); - SET_TOP(NULL); - STACK_GROW((oparg & 1)); - SET_TOP(res); - Py_DECREF(owner); - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); - DISPATCH(); - } - - TARGET(LOAD_ATTR_CLASS) { - assert(cframe.use_tracing == 0); - _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; - - PyObject *cls = TOP(); - DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); - uint32_t type_version = read_u32(cache->type_version); - DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, - LOAD_ATTR); - assert(type_version != 0); - - STAT_INC(LOAD_ATTR, hit); - PyObject *res = read_obj(cache->descr); - assert(res != NULL); - Py_INCREF(res); - SET_TOP(NULL); - STACK_GROW((oparg & 1)); - SET_TOP(res); - Py_DECREF(cls); - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); - DISPATCH(); - } - - TARGET(LOAD_ATTR_PROPERTY) { - assert(cframe.use_tracing == 0); - DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); - _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; - - PyObject *owner = TOP(); - PyTypeObject *cls = Py_TYPE(owner); - uint32_t type_version = read_u32(cache->type_version); - DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); - assert(type_version != 0); - PyObject *fget = read_obj(cache->descr); - assert(Py_IS_TYPE(fget, &PyFunction_Type)); - PyFunctionObject *f = (PyFunctionObject *)fget; - uint32_t func_version = read_u32(cache->keys_version); - assert(func_version != 0); - DEOPT_IF(f->func_version != func_version, LOAD_ATTR); - PyCodeObject *code = (PyCodeObject *)f->func_code; - assert(code->co_argcount == 1); - DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR); - STAT_INC(LOAD_ATTR, hit); - Py_INCREF(fget); - _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 1); - SET_TOP(NULL); - int shrink_stack = !(oparg & 1); - STACK_SHRINK(shrink_stack); - new_frame->localsplus[0] = owner; - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); - DISPATCH_INLINED(new_frame); - } - - TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { - assert(cframe.use_tracing == 0); - DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); - _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; - PyObject *owner = TOP(); - PyTypeObject *cls = Py_TYPE(owner); - uint32_t type_version = read_u32(cache->type_version); - DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); - assert(type_version != 0); - PyObject *getattribute = read_obj(cache->descr); - assert(Py_IS_TYPE(getattribute, &PyFunction_Type)); - PyFunctionObject *f = (PyFunctionObject *)getattribute; - uint32_t func_version = read_u32(cache->keys_version); - assert(func_version != 0); - DEOPT_IF(f->func_version != func_version, LOAD_ATTR); - PyCodeObject *code = (PyCodeObject *)f->func_code; - assert(code->co_argcount == 2); - DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR); - STAT_INC(LOAD_ATTR, hit); - - PyObject *name = GETITEM(names, oparg >> 1); - Py_INCREF(f); - _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2); - SET_TOP(NULL); - int shrink_stack = !(oparg & 1); - STACK_SHRINK(shrink_stack); - new_frame->localsplus[0] = owner; - new_frame->localsplus[1] = Py_NewRef(name); - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); - DISPATCH_INLINED(new_frame); - } - - TARGET(STORE_ATTR_INSTANCE_VALUE) { - PyObject *owner = PEEK(1); - PyObject *value = PEEK(2); - uint32_t type_version = read_u32(&next_instr[1].cache); - uint16_t index = read_u16(&next_instr[3].cache); - assert(cframe.use_tracing == 0); - PyTypeObject *tp = Py_TYPE(owner); - assert(type_version != 0); - DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); - assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); - PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); - DEOPT_IF(!_PyDictOrValues_IsValues(dorv), STORE_ATTR); - STAT_INC(STORE_ATTR, hit); - PyDictValues *values = _PyDictOrValues_GetValues(dorv); - PyObject *old_value = values->values[index]; - values->values[index] = value; - if (old_value == NULL) { - _PyDictValues_AddToInsertionOrder(values, index); - } - else { - Py_DECREF(old_value); - } - Py_DECREF(owner); - STACK_SHRINK(2); - JUMPBY(4); - DISPATCH(); - } - - TARGET(STORE_ATTR_WITH_HINT) { - PyObject *owner = PEEK(1); - PyObject *value = PEEK(2); - uint32_t type_version = read_u32(&next_instr[1].cache); - uint16_t hint = read_u16(&next_instr[3].cache); - assert(cframe.use_tracing == 0); - PyTypeObject *tp = Py_TYPE(owner); - assert(type_version != 0); - DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); - assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT); - PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); - DEOPT_IF(_PyDictOrValues_IsValues(dorv), STORE_ATTR); - PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); - DEOPT_IF(dict == NULL, STORE_ATTR); - assert(PyDict_CheckExact((PyObject *)dict)); - PyObject *name = GETITEM(names, oparg); - DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, STORE_ATTR); - PyObject *old_value; - uint64_t new_version; - if (DK_IS_UNICODE(dict->ma_keys)) { - PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint; - DEOPT_IF(ep->me_key != name, STORE_ATTR); - old_value = ep->me_value; - DEOPT_IF(old_value == NULL, STORE_ATTR); - new_version = _PyDict_NotifyEvent(PyDict_EVENT_MODIFIED, dict, name, value); - ep->me_value = value; - } - else { - PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint; - DEOPT_IF(ep->me_key != name, STORE_ATTR); - old_value = ep->me_value; - DEOPT_IF(old_value == NULL, STORE_ATTR); - new_version = _PyDict_NotifyEvent(PyDict_EVENT_MODIFIED, dict, name, value); - ep->me_value = value; - } - Py_DECREF(old_value); - STAT_INC(STORE_ATTR, hit); - /* Ensure dict is GC tracked if it needs to be */ - if (!_PyObject_GC_IS_TRACKED(dict) && _PyObject_GC_MAY_BE_TRACKED(value)) { - _PyObject_GC_TRACK(dict); - } - /* PEP 509 */ - dict->ma_version_tag = new_version; - Py_DECREF(owner); - STACK_SHRINK(2); - JUMPBY(4); - DISPATCH(); - } - - TARGET(STORE_ATTR_SLOT) { - PyObject *owner = PEEK(1); - PyObject *value = PEEK(2); - uint32_t type_version = read_u32(&next_instr[1].cache); - uint16_t index = read_u16(&next_instr[3].cache); - assert(cframe.use_tracing == 0); - PyTypeObject *tp = Py_TYPE(owner); - assert(type_version != 0); - DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); - char *addr = (char *)owner + index; - STAT_INC(STORE_ATTR, hit); - PyObject *old_value = *(PyObject **)addr; - *(PyObject **)addr = value; - Py_XDECREF(old_value); - Py_DECREF(owner); - STACK_SHRINK(2); - JUMPBY(4); - DISPATCH(); - } - - TARGET(COMPARE_OP) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); - PyObject *res; - STAT_INC(COMPARE_OP, deferred); - assert((oparg >> 4) <= Py_GE); - res = PyObject_RichCompare(left, right, oparg>>4); - Py_DECREF(left); - Py_DECREF(right); - if (res == NULL) goto pop_2_error; - STACK_SHRINK(1); - POKE(1, res); - JUMPBY(1); - DISPATCH(); - } - - TARGET(COMPARE_AND_BRANCH) { - PREDICTED(COMPARE_AND_BRANCH); - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); - #if ENABLE_SPECIALIZATION - _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; - if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); - next_instr--; - _Py_Specialize_CompareAndBranch(left, right, next_instr, oparg); - DISPATCH_SAME_OPARG(); - } - STAT_INC(COMPARE_AND_BRANCH, deferred); - DECREMENT_ADAPTIVE_COUNTER(cache->counter); - #endif /* ENABLE_SPECIALIZATION */ - assert((oparg >> 4) <= Py_GE); - PyObject *cond = PyObject_RichCompare(left, right, oparg>>4); - Py_DECREF(left); - Py_DECREF(right); - if (cond == NULL) goto pop_2_error; - assert(_Py_OPCODE(next_instr[1]) == POP_JUMP_IF_FALSE || - _Py_OPCODE(next_instr[1]) == POP_JUMP_IF_TRUE); - bool jump_on_true = _Py_OPCODE(next_instr[1]) == POP_JUMP_IF_TRUE; - int offset = _Py_OPARG(next_instr[1]); - int err = PyObject_IsTrue(cond); - Py_DECREF(cond); - if (err < 0) { - goto error; - } - if (jump_on_true == (err != 0)) { - JUMPBY(offset); - } - STACK_SHRINK(2); - JUMPBY(2); - DISPATCH(); - } - - TARGET(COMPARE_AND_BRANCH_FLOAT) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); - assert(cframe.use_tracing == 0); - DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); - double dleft = PyFloat_AS_DOUBLE(left); - double dright = PyFloat_AS_DOUBLE(right); - // 1 if NaN, 2 if <, 4 if >, 8 if ==; this matches low four bits of the oparg - int sign_ish = COMPARISON_BIT(dleft, dright); - _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); - _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); - if (sign_ish & oparg) { - int offset = _Py_OPARG(next_instr[1]); - JUMPBY(offset); - } - STACK_SHRINK(2); - JUMPBY(2); - DISPATCH(); - } - - TARGET(COMPARE_AND_BRANCH_INT) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); - assert(cframe.use_tracing == 0); - DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); - DEOPT_IF((size_t)(Py_SIZE(left) + 1) > 2, COMPARE_AND_BRANCH); - DEOPT_IF((size_t)(Py_SIZE(right) + 1) > 2, COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); - assert(Py_ABS(Py_SIZE(left)) <= 1 && Py_ABS(Py_SIZE(right)) <= 1); - Py_ssize_t ileft = Py_SIZE(left) * ((PyLongObject *)left)->ob_digit[0]; - Py_ssize_t iright = Py_SIZE(right) * ((PyLongObject *)right)->ob_digit[0]; - // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg - int sign_ish = COMPARISON_BIT(ileft, iright); - _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); - _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - if (sign_ish & oparg) { - int offset = _Py_OPARG(next_instr[1]); - JUMPBY(offset); - } - STACK_SHRINK(2); - JUMPBY(2); - DISPATCH(); - } - - TARGET(COMPARE_AND_BRANCH_STR) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); - assert(cframe.use_tracing == 0); - DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); - int res = _PyUnicode_Equal(left, right); - assert((oparg >>4) == Py_EQ || (oparg >>4) == Py_NE); - _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); - _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - assert(res == 0 || res == 1); - assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); - assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); - if ((res + COMPARISON_NOT_EQUALS) & oparg) { - int offset = _Py_OPARG(next_instr[1]); - JUMPBY(offset); - } - STACK_SHRINK(2); - JUMPBY(2); - DISPATCH(); - } - - TARGET(IS_OP) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); - PyObject *b; - int res = Py_Is(left, right) ^ oparg; - Py_DECREF(left); - Py_DECREF(right); - b = Py_NewRef(res ? Py_True : Py_False); - STACK_SHRINK(1); - POKE(1, b); - DISPATCH(); - } - - TARGET(CONTAINS_OP) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); - PyObject *b; - int res = PySequence_Contains(right, left); - Py_DECREF(left); - Py_DECREF(right); - if (res < 0) goto pop_2_error; - b = Py_NewRef((res^oparg) ? Py_True : Py_False); - STACK_SHRINK(1); - POKE(1, b); - DISPATCH(); - } - - TARGET(CHECK_EG_MATCH) { - PyObject *match_type = PEEK(1); - PyObject *exc_value = PEEK(2); - PyObject *rest; - PyObject *match; - if (check_except_star_type_valid(tstate, match_type) < 0) { - Py_DECREF(exc_value); - Py_DECREF(match_type); - if (true) goto pop_2_error; - } - - match = NULL; - rest = NULL; - int res = exception_group_match(exc_value, match_type, - &match, &rest); - Py_DECREF(exc_value); - Py_DECREF(match_type); - if (res < 0) goto pop_2_error; - - assert((match == NULL) == (rest == NULL)); - if (match == NULL) goto pop_2_error; - - if (!Py_IsNone(match)) { - PyErr_SetExcInfo(NULL, Py_NewRef(match), NULL); - } - POKE(1, match); - POKE(2, rest); - DISPATCH(); - } - - TARGET(CHECK_EXC_MATCH) { - PyObject *right = PEEK(1); - PyObject *left = PEEK(2); - PyObject *b; - assert(PyExceptionInstance_Check(left)); - if (check_except_type_valid(tstate, right) < 0) { - Py_DECREF(right); - if (true) goto pop_1_error; - } - - int res = PyErr_GivenExceptionMatches(left, right); - Py_DECREF(right); - b = Py_NewRef(res ? Py_True : Py_False); - POKE(1, b); - DISPATCH(); - } - - TARGET(IMPORT_NAME) { - PyObject *fromlist = PEEK(1); - PyObject *level = PEEK(2); - PyObject *res; - PyObject *name = GETITEM(names, oparg); - res = import_name(tstate, frame, name, fromlist, level); - Py_DECREF(level); - Py_DECREF(fromlist); - if (res == NULL) goto pop_2_error; - STACK_SHRINK(1); - POKE(1, res); - DISPATCH(); - } - - TARGET(IMPORT_FROM) { - PyObject *from = PEEK(1); - PyObject *res; - PyObject *name = GETITEM(names, oparg); - res = import_from(tstate, from, name); - if (res == NULL) goto error; - STACK_GROW(1); - POKE(1, res); - DISPATCH(); - } - - TARGET(JUMP_FORWARD) { - JUMPBY(oparg); - DISPATCH(); - } - - TARGET(JUMP_BACKWARD) { - PREDICTED(JUMP_BACKWARD); - assert(oparg < INSTR_OFFSET()); - JUMPBY(-oparg); - CHECK_EVAL_BREAKER(); - DISPATCH(); - } - - TARGET(POP_JUMP_IF_FALSE) { - PREDICTED(POP_JUMP_IF_FALSE); - PyObject *cond = POP(); - if (Py_IsTrue(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - } - else if (Py_IsFalse(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - JUMPBY(oparg); - } - else { - int err = PyObject_IsTrue(cond); - Py_DECREF(cond); - if (err > 0) - ; - else if (err == 0) { - JUMPBY(oparg); - } - else - goto error; - } - DISPATCH(); - } - - TARGET(POP_JUMP_IF_TRUE) { - PyObject *cond = POP(); - if (Py_IsFalse(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - } - else if (Py_IsTrue(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - JUMPBY(oparg); - } - else { - int err = PyObject_IsTrue(cond); - Py_DECREF(cond); - if (err > 0) { - JUMPBY(oparg); - } - else if (err == 0) - ; - else - goto error; - } - DISPATCH(); - } - - TARGET(POP_JUMP_IF_NOT_NONE) { - PyObject *value = POP(); - if (!Py_IsNone(value)) { - JUMPBY(oparg); - } - Py_DECREF(value); - DISPATCH(); - } - - TARGET(POP_JUMP_IF_NONE) { - PyObject *value = POP(); - if (Py_IsNone(value)) { - _Py_DECREF_NO_DEALLOC(value); - JUMPBY(oparg); - } - else { - Py_DECREF(value); - } - DISPATCH(); - } - - TARGET(JUMP_IF_FALSE_OR_POP) { - PyObject *cond = TOP(); - int err; - if (Py_IsTrue(cond)) { - STACK_SHRINK(1); - _Py_DECREF_NO_DEALLOC(cond); - } - else if (Py_IsFalse(cond)) { - JUMPBY(oparg); - } - else { - err = PyObject_IsTrue(cond); - if (err > 0) { - STACK_SHRINK(1); - Py_DECREF(cond); - } - else if (err == 0) { - JUMPBY(oparg); - } - else { - goto error; - } - } - DISPATCH(); - } - - TARGET(JUMP_IF_TRUE_OR_POP) { - PyObject *cond = TOP(); - int err; - if (Py_IsFalse(cond)) { - STACK_SHRINK(1); - _Py_DECREF_NO_DEALLOC(cond); - } - else if (Py_IsTrue(cond)) { - JUMPBY(oparg); - } - else { - err = PyObject_IsTrue(cond); - if (err > 0) { - JUMPBY(oparg); - } - else if (err == 0) { - STACK_SHRINK(1); - Py_DECREF(cond); - } - else { - goto error; - } - } - DISPATCH(); - } - - TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - /* This bytecode is used in the `yield from` or `await` loop. - * If there is an interrupt, we want it handled in the innermost - * generator or coroutine, so we deliberately do not check it here. - * (see bpo-30039). - */ - JUMPBY(-oparg); - DISPATCH(); - } - - TARGET(GET_LEN) { - // PUSH(len(TOS)) - Py_ssize_t len_i = PyObject_Length(TOP()); - if (len_i < 0) { - goto error; - } - PyObject *len_o = PyLong_FromSsize_t(len_i); - if (len_o == NULL) { - goto error; - } - PUSH(len_o); - DISPATCH(); - } - - TARGET(MATCH_CLASS) { - PyObject *names = PEEK(1); - PyObject *type = PEEK(2); - PyObject *subject = PEEK(3); - PyObject *attrs; - // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or - // None on failure. - assert(PyTuple_CheckExact(names)); - attrs = match_class(tstate, subject, type, oparg, names); - Py_DECREF(subject); - Py_DECREF(type); - Py_DECREF(names); - if (attrs) { - assert(PyTuple_CheckExact(attrs)); // Success! - } - else { - if (_PyErr_Occurred(tstate)) goto pop_3_error; - attrs = Py_NewRef(Py_None); // Failure! - } - STACK_SHRINK(2); - POKE(1, attrs); - DISPATCH(); - } - - TARGET(MATCH_MAPPING) { - PyObject *subject = PEEK(1); - PyObject *res; - int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; - res = Py_NewRef(match ? Py_True : Py_False); - STACK_GROW(1); - POKE(1, res); - PREDICT(POP_JUMP_IF_FALSE); - DISPATCH(); - } - - TARGET(MATCH_SEQUENCE) { - PyObject *subject = PEEK(1); - PyObject *res; - int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; - res = Py_NewRef(match ? Py_True : Py_False); - STACK_GROW(1); - POKE(1, res); - PREDICT(POP_JUMP_IF_FALSE); - DISPATCH(); - } - - TARGET(MATCH_KEYS) { - PyObject *keys = PEEK(1); - PyObject *subject = PEEK(2); - PyObject *values_or_none; - // On successful match, PUSH(values). Otherwise, PUSH(None). - values_or_none = match_keys(tstate, subject, keys); - if (values_or_none == NULL) goto error; - STACK_GROW(1); - POKE(1, values_or_none); - DISPATCH(); - } - - TARGET(GET_ITER) { - /* before: [obj]; after [getiter(obj)] */ - PyObject *iterable = TOP(); - PyObject *iter = PyObject_GetIter(iterable); - Py_DECREF(iterable); - SET_TOP(iter); - if (iter == NULL) - goto error; - DISPATCH(); - } - - TARGET(GET_YIELD_FROM_ITER) { - /* before: [obj]; after [getiter(obj)] */ - PyObject *iterable = TOP(); - PyObject *iter; - if (PyCoro_CheckExact(iterable)) { - /* `iterable` is a coroutine */ - if (!(frame->f_code->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) { - /* and it is used in a 'yield from' expression of a - regular generator. */ - Py_DECREF(iterable); - SET_TOP(NULL); - _PyErr_SetString(tstate, PyExc_TypeError, - "cannot 'yield from' a coroutine object " - "in a non-coroutine generator"); - goto error; - } - } - else if (!PyGen_CheckExact(iterable)) { - /* `iterable` is not a generator. */ - iter = PyObject_GetIter(iterable); - Py_DECREF(iterable); - SET_TOP(iter); - if (iter == NULL) - goto error; - } - PREDICT(LOAD_CONST); - DISPATCH(); - } - - TARGET(FOR_ITER) { - PREDICTED(FOR_ITER); - #if ENABLE_SPECIALIZATION - _PyForIterCache *cache = (_PyForIterCache *)next_instr; - if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); - next_instr--; - _Py_Specialize_ForIter(TOP(), next_instr, oparg); - DISPATCH_SAME_OPARG(); - } - STAT_INC(FOR_ITER, deferred); - DECREMENT_ADAPTIVE_COUNTER(cache->counter); - #endif /* ENABLE_SPECIALIZATION */ - /* before: [iter]; after: [iter, iter()] *or* [] */ - PyObject *iter = TOP(); - PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); - if (next != NULL) { - PUSH(next); - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); - } - else { - if (_PyErr_Occurred(tstate)) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { - goto error; - } - else if (tstate->c_tracefunc != NULL) { - call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame); - } - _PyErr_Clear(tstate); - } - /* iterator ended normally */ - assert(_Py_OPCODE(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg]) == END_FOR); - STACK_SHRINK(1); - Py_DECREF(iter); - /* Skip END_FOR */ - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); - } - DISPATCH(); - } - - TARGET(FOR_ITER_LIST) { - assert(cframe.use_tracing == 0); - _PyListIterObject *it = (_PyListIterObject *)TOP(); - DEOPT_IF(Py_TYPE(it) != &PyListIter_Type, FOR_ITER); - STAT_INC(FOR_ITER, hit); - PyListObject *seq = it->it_seq; - if (seq) { - if (it->it_index < PyList_GET_SIZE(seq)) { - PyObject *next = PyList_GET_ITEM(seq, it->it_index++); - PUSH(Py_NewRef(next)); - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); - goto end_for_iter_list; // End of this instruction - } - it->it_seq = NULL; - Py_DECREF(seq); - } - STACK_SHRINK(1); - Py_DECREF(it); - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); - end_for_iter_list: - DISPATCH(); - } - - TARGET(FOR_ITER_TUPLE) { - assert(cframe.use_tracing == 0); - _PyTupleIterObject *it = (_PyTupleIterObject *)TOP(); - DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); - STAT_INC(FOR_ITER, hit); - PyTupleObject *seq = it->it_seq; - if (seq) { - if (it->it_index < PyTuple_GET_SIZE(seq)) { - PyObject *next = PyTuple_GET_ITEM(seq, it->it_index++); - PUSH(Py_NewRef(next)); - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); - goto end_for_iter_tuple; // End of this instruction - } - it->it_seq = NULL; - Py_DECREF(seq); - } - STACK_SHRINK(1); - Py_DECREF(it); - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); - end_for_iter_tuple: - DISPATCH(); - } - - TARGET(FOR_ITER_RANGE) { - assert(cframe.use_tracing == 0); - _PyRangeIterObject *r = (_PyRangeIterObject *)TOP(); - DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); - STAT_INC(FOR_ITER, hit); - _Py_CODEUNIT next = next_instr[INLINE_CACHE_ENTRIES_FOR_ITER]; - assert(_PyOpcode_Deopt[_Py_OPCODE(next)] == STORE_FAST); - if (r->len <= 0) { - STACK_SHRINK(1); - Py_DECREF(r); - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); - } - else { - long value = r->start; - r->start = value + r->step; - r->len--; - if (_PyLong_AssignValue(&GETLOCAL(_Py_OPARG(next)), value) < 0) { - goto error; - } - // The STORE_FAST is already done. - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + 1); - } - DISPATCH(); - } - - TARGET(FOR_ITER_GEN) { - assert(cframe.use_tracing == 0); - PyGenObject *gen = (PyGenObject *)TOP(); - DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); - DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER); - STAT_INC(FOR_ITER, hit); - _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; - frame->yield_offset = oparg; - _PyFrame_StackPush(gen_frame, Py_NewRef(Py_None)); - gen->gi_frame_state = FRAME_EXECUTING; - gen->gi_exc_state.previous_item = tstate->exc_info; - tstate->exc_info = &gen->gi_exc_state; - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg); - assert(_Py_OPCODE(*next_instr) == END_FOR); - DISPATCH_INLINED(gen_frame); - } - - TARGET(BEFORE_ASYNC_WITH) { - PyObject *mgr = TOP(); - PyObject *res; - PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); - if (enter == NULL) { - if (!_PyErr_Occurred(tstate)) { - _PyErr_Format(tstate, PyExc_TypeError, - "'%.200s' object does not support the " - "asynchronous context manager protocol", - Py_TYPE(mgr)->tp_name); - } - goto error; - } - PyObject *exit = _PyObject_LookupSpecial(mgr, &_Py_ID(__aexit__)); - if (exit == NULL) { - if (!_PyErr_Occurred(tstate)) { - _PyErr_Format(tstate, PyExc_TypeError, - "'%.200s' object does not support the " - "asynchronous context manager protocol " - "(missed __aexit__ method)", - Py_TYPE(mgr)->tp_name); - } - Py_DECREF(enter); - goto error; - } - SET_TOP(exit); - Py_DECREF(mgr); - res = _PyObject_CallNoArgs(enter); - Py_DECREF(enter); - if (res == NULL) - goto error; - PUSH(res); - PREDICT(GET_AWAITABLE); - DISPATCH(); - } - - TARGET(BEFORE_WITH) { - PyObject *mgr = TOP(); - PyObject *res; - PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__enter__)); - if (enter == NULL) { - if (!_PyErr_Occurred(tstate)) { - _PyErr_Format(tstate, PyExc_TypeError, - "'%.200s' object does not support the " - "context manager protocol", - Py_TYPE(mgr)->tp_name); - } - goto error; - } - PyObject *exit = _PyObject_LookupSpecial(mgr, &_Py_ID(__exit__)); - if (exit == NULL) { - if (!_PyErr_Occurred(tstate)) { - _PyErr_Format(tstate, PyExc_TypeError, - "'%.200s' object does not support the " - "context manager protocol " - "(missed __exit__ method)", - Py_TYPE(mgr)->tp_name); - } - Py_DECREF(enter); - goto error; - } - SET_TOP(exit); - Py_DECREF(mgr); - res = _PyObject_CallNoArgs(enter); - Py_DECREF(enter); - if (res == NULL) { - goto error; - } - PUSH(res); - DISPATCH(); - } - - TARGET(WITH_EXCEPT_START) { - PyObject *val = PEEK(1); - PyObject *lasti = PEEK(3); - PyObject *exit_func = PEEK(4); - PyObject *res; - /* At the top of the stack are 4 values: - - val: TOP = exc_info() - - unused: SECOND = previous exception - - lasti: THIRD = lasti of exception in exc_info() - - exit_func: FOURTH = the context.__exit__ bound method - We call FOURTH(type(TOP), TOP, GetTraceback(TOP)). - Then we push the __exit__ return value. - */ - PyObject *exc, *tb; - - assert(val && PyExceptionInstance_Check(val)); - exc = PyExceptionInstance_Class(val); - tb = PyException_GetTraceback(val); - Py_XDECREF(tb); - assert(PyLong_Check(lasti)); - (void)lasti; // Shut up compiler warning if asserts are off - PyObject *stack[4] = {NULL, exc, val, tb}; - res = PyObject_Vectorcall(exit_func, stack + 1, - 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); - if (res == NULL) goto error; - STACK_GROW(1); - POKE(1, res); - DISPATCH(); - } - - TARGET(PUSH_EXC_INFO) { - PyObject *value = TOP(); - - _PyErr_StackItem *exc_info = tstate->exc_info; - if (exc_info->exc_value != NULL) { - SET_TOP(exc_info->exc_value); - } - else { - SET_TOP(Py_NewRef(Py_None)); - } - - PUSH(Py_NewRef(value)); - assert(PyExceptionInstance_Check(value)); - exc_info->exc_value = value; - DISPATCH(); - } - - TARGET(LOAD_ATTR_METHOD_WITH_VALUES) { - /* Cached method object */ - assert(cframe.use_tracing == 0); - PyObject *self = TOP(); - PyTypeObject *self_cls = Py_TYPE(self); - _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; - uint32_t type_version = read_u32(cache->type_version); - assert(type_version != 0); - DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); - assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT); - PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self); - DEOPT_IF(!_PyDictOrValues_IsValues(dorv), LOAD_ATTR); - PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls; - DEOPT_IF(self_heap_type->ht_cached_keys->dk_version != - read_u32(cache->keys_version), LOAD_ATTR); - STAT_INC(LOAD_ATTR, hit); - PyObject *res = read_obj(cache->descr); - assert(res != NULL); - assert(_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR)); - SET_TOP(Py_NewRef(res)); - PUSH(self); - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); - DISPATCH(); - } - - TARGET(LOAD_ATTR_METHOD_NO_DICT) { - assert(cframe.use_tracing == 0); - PyObject *self = TOP(); - PyTypeObject *self_cls = Py_TYPE(self); - _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; - uint32_t type_version = read_u32(cache->type_version); - DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); - assert(self_cls->tp_dictoffset == 0); - STAT_INC(LOAD_ATTR, hit); - PyObject *res = read_obj(cache->descr); - assert(res != NULL); - assert(_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR)); - SET_TOP(Py_NewRef(res)); - PUSH(self); - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); - DISPATCH(); - } - - TARGET(LOAD_ATTR_METHOD_LAZY_DICT) { - assert(cframe.use_tracing == 0); - PyObject *self = TOP(); - PyTypeObject *self_cls = Py_TYPE(self); - _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr; - uint32_t type_version = read_u32(cache->type_version); - DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); - Py_ssize_t dictoffset = self_cls->tp_dictoffset; - assert(dictoffset > 0); - PyObject *dict = *(PyObject **)((char *)self + dictoffset); - /* This object has a __dict__, just not yet created */ - DEOPT_IF(dict != NULL, LOAD_ATTR); - STAT_INC(LOAD_ATTR, hit); - PyObject *res = read_obj(cache->descr); - assert(res != NULL); - assert(_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR)); - SET_TOP(Py_NewRef(res)); - PUSH(self); - JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR); - DISPATCH(); - } - - TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { - DEOPT_IF(is_method(stack_pointer, oparg), CALL); - PyObject *function = PEEK(oparg + 1); - DEOPT_IF(Py_TYPE(function) != &PyMethod_Type, CALL); - STAT_INC(CALL, hit); - PyObject *self = ((PyMethodObject *)function)->im_self; - PEEK(oparg + 1) = Py_NewRef(self); - PyObject *meth = ((PyMethodObject *)function)->im_func; - PEEK(oparg + 2) = Py_NewRef(meth); - Py_DECREF(function); - GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - } - - TARGET(KW_NAMES) { - assert(kwnames == NULL); - assert(oparg < PyTuple_GET_SIZE(consts)); - kwnames = GETITEM(consts, oparg); - DISPATCH(); - } - - TARGET(CALL) { - PREDICTED(CALL); - #if ENABLE_SPECIALIZATION - _PyCallCache *cache = (_PyCallCache *)next_instr; - if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); - int is_meth = is_method(stack_pointer, oparg); - int nargs = oparg + is_meth; - PyObject *callable = PEEK(nargs + 1); - next_instr--; - _Py_Specialize_Call(callable, next_instr, nargs, kwnames); - DISPATCH_SAME_OPARG(); - } - STAT_INC(CALL, deferred); - DECREMENT_ADAPTIVE_COUNTER(cache->counter); - #endif /* ENABLE_SPECIALIZATION */ - int total_args, is_meth; - is_meth = is_method(stack_pointer, oparg); - PyObject *function = PEEK(oparg + 1); - if (!is_meth && Py_TYPE(function) == &PyMethod_Type) { - PyObject *self = ((PyMethodObject *)function)->im_self; - PEEK(oparg+1) = Py_NewRef(self); - PyObject *meth = ((PyMethodObject *)function)->im_func; - PEEK(oparg+2) = Py_NewRef(meth); - Py_DECREF(function); - is_meth = 1; - } - total_args = oparg + is_meth; - function = PEEK(total_args + 1); - int positional_args = total_args - KWNAMES_LEN(); - // Check if the call can be inlined or not - if (Py_TYPE(function) == &PyFunction_Type && - tstate->interp->eval_frame == NULL && - ((PyFunctionObject *)function)->vectorcall == _PyFunction_Vectorcall) - { - int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(function))->co_flags; - PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(function)); - STACK_SHRINK(total_args); - _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( - tstate, (PyFunctionObject *)function, locals, - stack_pointer, positional_args, kwnames - ); - kwnames = NULL; - STACK_SHRINK(2-is_meth); - // The frame has stolen all the arguments from the stack, - // so there is no need to clean them up. - if (new_frame == NULL) { - goto error; - } - JUMPBY(INLINE_CACHE_ENTRIES_CALL); - DISPATCH_INLINED(new_frame); - } - /* Callable is not a normal Python function */ - PyObject *res; - if (cframe.use_tracing) { - res = trace_call_function( - tstate, function, stack_pointer-total_args, - positional_args, kwnames); - } - else { - res = PyObject_Vectorcall( - function, stack_pointer-total_args, - positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, - kwnames); - } - kwnames = NULL; - assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - Py_DECREF(function); - /* Clear the stack */ - STACK_SHRINK(total_args); - for (int i = 0; i < total_args; i++) { - Py_DECREF(stack_pointer[i]); - } - STACK_SHRINK(2-is_meth); - PUSH(res); - if (res == NULL) { - goto error; - } - JUMPBY(INLINE_CACHE_ENTRIES_CALL); - CHECK_EVAL_BREAKER(); - DISPATCH(); - } - - TARGET(CALL_PY_EXACT_ARGS) { - PREDICTED(CALL_PY_EXACT_ARGS); - assert(kwnames == NULL); - DEOPT_IF(tstate->interp->eval_frame, CALL); - _PyCallCache *cache = (_PyCallCache *)next_instr; - int is_meth = is_method(stack_pointer, oparg); - int argcount = oparg + is_meth; - PyObject *callable = PEEK(argcount + 1); - DEOPT_IF(!PyFunction_Check(callable), CALL); - PyFunctionObject *func = (PyFunctionObject *)callable; - DEOPT_IF(func->func_version != read_u32(cache->func_version), CALL); - PyCodeObject *code = (PyCodeObject *)func->func_code; - DEOPT_IF(code->co_argcount != argcount, CALL); - DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); - STAT_INC(CALL, hit); - _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, func, argcount); - STACK_SHRINK(argcount); - for (int i = 0; i < argcount; i++) { - new_frame->localsplus[i] = stack_pointer[i]; - } - STACK_SHRINK(2-is_meth); - JUMPBY(INLINE_CACHE_ENTRIES_CALL); - DISPATCH_INLINED(new_frame); - } - - TARGET(CALL_PY_WITH_DEFAULTS) { - assert(kwnames == NULL); - DEOPT_IF(tstate->interp->eval_frame, CALL); - _PyCallCache *cache = (_PyCallCache *)next_instr; - int is_meth = is_method(stack_pointer, oparg); - int argcount = oparg + is_meth; - PyObject *callable = PEEK(argcount + 1); - DEOPT_IF(!PyFunction_Check(callable), CALL); - PyFunctionObject *func = (PyFunctionObject *)callable; - DEOPT_IF(func->func_version != read_u32(cache->func_version), CALL); - PyCodeObject *code = (PyCodeObject *)func->func_code; - DEOPT_IF(argcount > code->co_argcount, CALL); - int minargs = cache->min_args; - DEOPT_IF(argcount < minargs, CALL); - DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), CALL); - STAT_INC(CALL, hit); - _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, func, code->co_argcount); - STACK_SHRINK(argcount); - for (int i = 0; i < argcount; i++) { - new_frame->localsplus[i] = stack_pointer[i]; - } - for (int i = argcount; i < code->co_argcount; i++) { - PyObject *def = PyTuple_GET_ITEM(func->func_defaults, - i - minargs); - new_frame->localsplus[i] = Py_NewRef(def); - } - STACK_SHRINK(2-is_meth); - JUMPBY(INLINE_CACHE_ENTRIES_CALL); - DISPATCH_INLINED(new_frame); - } - - TARGET(CALL_NO_KW_TYPE_1) { - assert(kwnames == NULL); - assert(cframe.use_tracing == 0); - assert(oparg == 1); - DEOPT_IF(is_method(stack_pointer, 1), CALL); - PyObject *obj = TOP(); - PyObject *callable = SECOND(); - DEOPT_IF(callable != (PyObject *)&PyType_Type, CALL); - STAT_INC(CALL, hit); - JUMPBY(INLINE_CACHE_ENTRIES_CALL); - PyObject *res = Py_NewRef(Py_TYPE(obj)); - Py_DECREF(callable); - Py_DECREF(obj); - STACK_SHRINK(2); - SET_TOP(res); - DISPATCH(); - } - - TARGET(CALL_NO_KW_STR_1) { - assert(kwnames == NULL); - assert(cframe.use_tracing == 0); - assert(oparg == 1); - DEOPT_IF(is_method(stack_pointer, 1), CALL); - PyObject *callable = PEEK(2); - DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, CALL); - STAT_INC(CALL, hit); - PyObject *arg = TOP(); - PyObject *res = PyObject_Str(arg); - Py_DECREF(arg); - Py_DECREF(&PyUnicode_Type); - STACK_SHRINK(2); - SET_TOP(res); - if (res == NULL) { - goto error; - } - JUMPBY(INLINE_CACHE_ENTRIES_CALL); - CHECK_EVAL_BREAKER(); - DISPATCH(); - } - - TARGET(CALL_NO_KW_TUPLE_1) { - assert(kwnames == NULL); - assert(oparg == 1); - DEOPT_IF(is_method(stack_pointer, 1), CALL); - PyObject *callable = PEEK(2); - DEOPT_IF(callable != (PyObject *)&PyTuple_Type, CALL); - STAT_INC(CALL, hit); - PyObject *arg = TOP(); - PyObject *res = PySequence_Tuple(arg); - Py_DECREF(arg); - Py_DECREF(&PyTuple_Type); - STACK_SHRINK(2); - SET_TOP(res); - if (res == NULL) { - goto error; - } - JUMPBY(INLINE_CACHE_ENTRIES_CALL); - CHECK_EVAL_BREAKER(); - DISPATCH(); - } - - TARGET(CALL_BUILTIN_CLASS) { - int is_meth = is_method(stack_pointer, oparg); - int total_args = oparg + is_meth; - int kwnames_len = KWNAMES_LEN(); - PyObject *callable = PEEK(total_args + 1); - DEOPT_IF(!PyType_Check(callable), CALL); - PyTypeObject *tp = (PyTypeObject *)callable; - DEOPT_IF(tp->tp_vectorcall == NULL, CALL); - STAT_INC(CALL, hit); - STACK_SHRINK(total_args); - PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer, - total_args-kwnames_len, kwnames); - kwnames = NULL; - /* Free the arguments. */ - for (int i = 0; i < total_args; i++) { - Py_DECREF(stack_pointer[i]); - } - Py_DECREF(tp); - STACK_SHRINK(1-is_meth); - SET_TOP(res); - if (res == NULL) { - goto error; - } - JUMPBY(INLINE_CACHE_ENTRIES_CALL); - CHECK_EVAL_BREAKER(); - DISPATCH(); - } - - TARGET(CALL_NO_KW_BUILTIN_O) { - assert(cframe.use_tracing == 0); - /* Builtin METH_O functions */ - assert(kwnames == NULL); - int is_meth = is_method(stack_pointer, oparg); - int total_args = oparg + is_meth; - DEOPT_IF(total_args != 1, CALL); - PyObject *callable = PEEK(total_args + 1); - DEOPT_IF(!PyCFunction_CheckExact(callable), CALL); - DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_O, CALL); - STAT_INC(CALL, hit); - PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable); - // This is slower but CPython promises to check all non-vectorcall - // function calls. - if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) { - goto error; - } - PyObject *arg = TOP(); - PyObject *res = _PyCFunction_TrampolineCall(cfunc, PyCFunction_GET_SELF(callable), arg); - _Py_LeaveRecursiveCallTstate(tstate); - assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - - Py_DECREF(arg); - Py_DECREF(callable); - STACK_SHRINK(2-is_meth); - SET_TOP(res); - if (res == NULL) { - goto error; - } - JUMPBY(INLINE_CACHE_ENTRIES_CALL); - CHECK_EVAL_BREAKER(); - DISPATCH(); - } - - TARGET(CALL_NO_KW_BUILTIN_FAST) { - assert(cframe.use_tracing == 0); - /* Builtin METH_FASTCALL functions, without keywords */ - assert(kwnames == NULL); - int is_meth = is_method(stack_pointer, oparg); - int total_args = oparg + is_meth; - PyObject *callable = PEEK(total_args + 1); - DEOPT_IF(!PyCFunction_CheckExact(callable), CALL); - DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_FASTCALL, - CALL); - STAT_INC(CALL, hit); - PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable); - STACK_SHRINK(total_args); - /* res = func(self, args, nargs) */ - PyObject *res = ((_PyCFunctionFast)(void(*)(void))cfunc)( - PyCFunction_GET_SELF(callable), - stack_pointer, - total_args); - assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - - /* Free the arguments. */ - for (int i = 0; i < total_args; i++) { - Py_DECREF(stack_pointer[i]); - } - STACK_SHRINK(2-is_meth); - PUSH(res); - Py_DECREF(callable); - if (res == NULL) { - /* Not deopting because this doesn't mean our optimization was - wrong. `res` can be NULL for valid reasons. Eg. getattr(x, - 'invalid'). In those cases an exception is set, so we must - handle it. - */ - goto error; - } - JUMPBY(INLINE_CACHE_ENTRIES_CALL); - CHECK_EVAL_BREAKER(); - DISPATCH(); - } - - TARGET(CALL_BUILTIN_FAST_WITH_KEYWORDS) { - assert(cframe.use_tracing == 0); - /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ - int is_meth = is_method(stack_pointer, oparg); - int total_args = oparg + is_meth; - PyObject *callable = PEEK(total_args + 1); - DEOPT_IF(!PyCFunction_CheckExact(callable), CALL); - DEOPT_IF(PyCFunction_GET_FLAGS(callable) != - (METH_FASTCALL | METH_KEYWORDS), CALL); - STAT_INC(CALL, hit); - STACK_SHRINK(total_args); - /* res = func(self, args, nargs, kwnames) */ - _PyCFunctionFastWithKeywords cfunc = - (_PyCFunctionFastWithKeywords)(void(*)(void)) - PyCFunction_GET_FUNCTION(callable); - PyObject *res = cfunc( - PyCFunction_GET_SELF(callable), - stack_pointer, - total_args - KWNAMES_LEN(), - kwnames - ); - assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - kwnames = NULL; - - /* Free the arguments. */ - for (int i = 0; i < total_args; i++) { - Py_DECREF(stack_pointer[i]); - } - STACK_SHRINK(2-is_meth); - PUSH(res); - Py_DECREF(callable); - if (res == NULL) { - goto error; - } - JUMPBY(INLINE_CACHE_ENTRIES_CALL); - CHECK_EVAL_BREAKER(); - DISPATCH(); - } - - TARGET(CALL_NO_KW_LEN) { - assert(cframe.use_tracing == 0); - assert(kwnames == NULL); - /* len(o) */ - int is_meth = is_method(stack_pointer, oparg); - int total_args = oparg + is_meth; - DEOPT_IF(total_args != 1, CALL); - PyObject *callable = PEEK(total_args + 1); - PyInterpreterState *interp = _PyInterpreterState_GET(); - DEOPT_IF(callable != interp->callable_cache.len, CALL); - STAT_INC(CALL, hit); - PyObject *arg = TOP(); - Py_ssize_t len_i = PyObject_Length(arg); - if (len_i < 0) { - goto error; - } - PyObject *res = PyLong_FromSsize_t(len_i); - assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - - STACK_SHRINK(2-is_meth); - SET_TOP(res); - Py_DECREF(callable); - Py_DECREF(arg); - if (res == NULL) { - goto error; - } - JUMPBY(INLINE_CACHE_ENTRIES_CALL); - DISPATCH(); - } - - TARGET(CALL_NO_KW_ISINSTANCE) { - assert(cframe.use_tracing == 0); - assert(kwnames == NULL); - /* isinstance(o, o2) */ - int is_meth = is_method(stack_pointer, oparg); - int total_args = oparg + is_meth; - PyObject *callable = PEEK(total_args + 1); - DEOPT_IF(total_args != 2, CALL); - PyInterpreterState *interp = _PyInterpreterState_GET(); - DEOPT_IF(callable != interp->callable_cache.isinstance, CALL); - STAT_INC(CALL, hit); - PyObject *cls = POP(); - PyObject *inst = TOP(); - int retval = PyObject_IsInstance(inst, cls); - if (retval < 0) { - Py_DECREF(cls); - goto error; - } - PyObject *res = PyBool_FromLong(retval); - assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - - STACK_SHRINK(2-is_meth); - SET_TOP(res); - Py_DECREF(inst); - Py_DECREF(cls); - Py_DECREF(callable); - if (res == NULL) { - goto error; - } - JUMPBY(INLINE_CACHE_ENTRIES_CALL); - DISPATCH(); - } - - TARGET(CALL_NO_KW_LIST_APPEND) { - assert(cframe.use_tracing == 0); - assert(kwnames == NULL); - assert(oparg == 1); - PyObject *callable = PEEK(3); - PyInterpreterState *interp = _PyInterpreterState_GET(); - DEOPT_IF(callable != interp->callable_cache.list_append, CALL); - PyObject *list = SECOND(); - DEOPT_IF(!PyList_Check(list), CALL); - STAT_INC(CALL, hit); - PyObject *arg = POP(); - if (_PyList_AppendTakeRef((PyListObject *)list, arg) < 0) { - goto error; - } - STACK_SHRINK(2); - Py_DECREF(list); - Py_DECREF(callable); - // CALL + POP_TOP - JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1); - assert(_Py_OPCODE(next_instr[-1]) == POP_TOP); - DISPATCH(); - } - - TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { - assert(kwnames == NULL); - int is_meth = is_method(stack_pointer, oparg); - int total_args = oparg + is_meth; - PyMethodDescrObject *callable = - (PyMethodDescrObject *)PEEK(total_args + 1); - DEOPT_IF(total_args != 2, CALL); - DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); - PyMethodDef *meth = callable->d_method; - DEOPT_IF(meth->ml_flags != METH_O, CALL); - PyObject *arg = TOP(); - PyObject *self = SECOND(); - DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); - STAT_INC(CALL, hit); - PyCFunction cfunc = meth->ml_meth; - // This is slower but CPython promises to check all non-vectorcall - // function calls. - if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) { - goto error; - } - PyObject *res = _PyCFunction_TrampolineCall(cfunc, self, arg); - _Py_LeaveRecursiveCallTstate(tstate); - assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - Py_DECREF(self); - Py_DECREF(arg); - STACK_SHRINK(oparg + 1); - SET_TOP(res); - Py_DECREF(callable); - if (res == NULL) { - goto error; - } - JUMPBY(INLINE_CACHE_ENTRIES_CALL); - CHECK_EVAL_BREAKER(); - DISPATCH(); - } - - TARGET(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS) { - int is_meth = is_method(stack_pointer, oparg); - int total_args = oparg + is_meth; - PyMethodDescrObject *callable = - (PyMethodDescrObject *)PEEK(total_args + 1); - DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); - PyMethodDef *meth = callable->d_method; - DEOPT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS), CALL); - PyTypeObject *d_type = callable->d_common.d_type; - PyObject *self = PEEK(total_args); - DEOPT_IF(!Py_IS_TYPE(self, d_type), CALL); - STAT_INC(CALL, hit); - int nargs = total_args-1; - STACK_SHRINK(nargs); - _PyCFunctionFastWithKeywords cfunc = - (_PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; - PyObject *res = cfunc(self, stack_pointer, nargs - KWNAMES_LEN(), - kwnames); - assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - kwnames = NULL; - - /* Free the arguments. */ - for (int i = 0; i < nargs; i++) { - Py_DECREF(stack_pointer[i]); - } - Py_DECREF(self); - STACK_SHRINK(2-is_meth); - SET_TOP(res); - Py_DECREF(callable); - if (res == NULL) { - goto error; - } - JUMPBY(INLINE_CACHE_ENTRIES_CALL); - CHECK_EVAL_BREAKER(); - DISPATCH(); - } - - TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) { - assert(kwnames == NULL); - assert(oparg == 0 || oparg == 1); - int is_meth = is_method(stack_pointer, oparg); - int total_args = oparg + is_meth; - DEOPT_IF(total_args != 1, CALL); - PyMethodDescrObject *callable = (PyMethodDescrObject *)SECOND(); - DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); - PyMethodDef *meth = callable->d_method; - PyObject *self = TOP(); - DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); - DEOPT_IF(meth->ml_flags != METH_NOARGS, CALL); - STAT_INC(CALL, hit); - PyCFunction cfunc = meth->ml_meth; - // This is slower but CPython promises to check all non-vectorcall - // function calls. - if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) { - goto error; - } - PyObject *res = _PyCFunction_TrampolineCall(cfunc, self, NULL); - _Py_LeaveRecursiveCallTstate(tstate); - assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - Py_DECREF(self); - STACK_SHRINK(oparg + 1); - SET_TOP(res); - Py_DECREF(callable); - if (res == NULL) { - goto error; - } - JUMPBY(INLINE_CACHE_ENTRIES_CALL); - CHECK_EVAL_BREAKER(); - DISPATCH(); - } - - TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_FAST) { - assert(kwnames == NULL); - int is_meth = is_method(stack_pointer, oparg); - int total_args = oparg + is_meth; - PyMethodDescrObject *callable = - (PyMethodDescrObject *)PEEK(total_args + 1); - /* Builtin METH_FASTCALL methods, without keywords */ - DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); - PyMethodDef *meth = callable->d_method; - DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL); - PyObject *self = PEEK(total_args); - DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL); - STAT_INC(CALL, hit); - _PyCFunctionFast cfunc = - (_PyCFunctionFast)(void(*)(void))meth->ml_meth; - int nargs = total_args-1; - STACK_SHRINK(nargs); - PyObject *res = cfunc(self, stack_pointer, nargs); - assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - /* Clear the stack of the arguments. */ - for (int i = 0; i < nargs; i++) { - Py_DECREF(stack_pointer[i]); - } - Py_DECREF(self); - STACK_SHRINK(2-is_meth); - SET_TOP(res); - Py_DECREF(callable); - if (res == NULL) { - goto error; - } - JUMPBY(INLINE_CACHE_ENTRIES_CALL); - CHECK_EVAL_BREAKER(); - DISPATCH(); - } - - TARGET(CALL_FUNCTION_EX) { - PREDICTED(CALL_FUNCTION_EX); - PyObject *func, *callargs, *kwargs = NULL, *result; - if (oparg & 0x01) { - kwargs = POP(); - // DICT_MERGE is called before this opcode if there are kwargs. - // It converts all dict subtypes in kwargs into regular dicts. - assert(PyDict_CheckExact(kwargs)); - } - callargs = POP(); - func = TOP(); - if (!PyTuple_CheckExact(callargs)) { - if (check_args_iterable(tstate, func, callargs) < 0) { - Py_DECREF(callargs); - goto error; - } - Py_SETREF(callargs, PySequence_Tuple(callargs)); - if (callargs == NULL) { - goto error; - } - } - assert(PyTuple_CheckExact(callargs)); - - result = do_call_core(tstate, func, callargs, kwargs, cframe.use_tracing); - Py_DECREF(func); - Py_DECREF(callargs); - Py_XDECREF(kwargs); - - STACK_SHRINK(1); - assert(TOP() == NULL); - SET_TOP(result); - if (result == NULL) { - goto error; - } - CHECK_EVAL_BREAKER(); - DISPATCH(); - } - - TARGET(MAKE_FUNCTION) { - PyObject *codeobj = POP(); - PyFunctionObject *func = (PyFunctionObject *) - PyFunction_New(codeobj, GLOBALS()); - - Py_DECREF(codeobj); - if (func == NULL) { - goto error; - } - - if (oparg & 0x08) { - assert(PyTuple_CheckExact(TOP())); - func->func_closure = POP(); - } - if (oparg & 0x04) { - assert(PyTuple_CheckExact(TOP())); - func->func_annotations = POP(); - } - if (oparg & 0x02) { - assert(PyDict_CheckExact(TOP())); - func->func_kwdefaults = POP(); - } - if (oparg & 0x01) { - assert(PyTuple_CheckExact(TOP())); - func->func_defaults = POP(); - } - - func->func_version = ((PyCodeObject *)codeobj)->co_version; - PUSH((PyObject *)func); - DISPATCH(); - } - - TARGET(RETURN_GENERATOR) { - assert(PyFunction_Check(frame->f_funcobj)); - PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; - PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); - if (gen == NULL) { - goto error; - } - assert(EMPTY()); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; - _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); - assert(frame != &entry_frame); - _PyInterpreterFrame *prev = frame->previous; - _PyThreadState_PopFrame(tstate, frame); - frame = cframe.current_frame = prev; - _PyFrame_StackPush(frame, (PyObject *)gen); - goto resume_frame; - } - - TARGET(BUILD_SLICE) { - PyObject *start, *stop, *step, *slice; - if (oparg == 3) - step = POP(); - else - step = NULL; - stop = POP(); - start = TOP(); - slice = PySlice_New(start, stop, step); - Py_DECREF(start); - Py_DECREF(stop); - Py_XDECREF(step); - SET_TOP(slice); - if (slice == NULL) - goto error; - DISPATCH(); - } - - TARGET(FORMAT_VALUE) { - /* Handles f-string value formatting. */ - PyObject *result; - PyObject *fmt_spec; - PyObject *value; - PyObject *(*conv_fn)(PyObject *); - int which_conversion = oparg & FVC_MASK; - int have_fmt_spec = (oparg & FVS_MASK) == FVS_HAVE_SPEC; - - fmt_spec = have_fmt_spec ? POP() : NULL; - value = POP(); - - /* See if any conversion is specified. */ - switch (which_conversion) { - case FVC_NONE: conv_fn = NULL; break; - case FVC_STR: conv_fn = PyObject_Str; break; - case FVC_REPR: conv_fn = PyObject_Repr; break; - case FVC_ASCII: conv_fn = PyObject_ASCII; break; - default: - _PyErr_Format(tstate, PyExc_SystemError, - "unexpected conversion flag %d", - which_conversion); - goto error; - } - - /* If there's a conversion function, call it and replace - value with that result. Otherwise, just use value, - without conversion. */ - if (conv_fn != NULL) { - result = conv_fn(value); - Py_DECREF(value); - if (result == NULL) { - Py_XDECREF(fmt_spec); - goto error; - } - value = result; - } - - /* If value is a unicode object, and there's no fmt_spec, - then we know the result of format(value) is value - itself. In that case, skip calling format(). I plan to - move this optimization in to PyObject_Format() - itself. */ - if (PyUnicode_CheckExact(value) && fmt_spec == NULL) { - /* Do nothing, just transfer ownership to result. */ - result = value; - } else { - /* Actually call format(). */ - result = PyObject_Format(value, fmt_spec); - Py_DECREF(value); - Py_XDECREF(fmt_spec); - if (result == NULL) { - goto error; - } - } - - PUSH(result); - DISPATCH(); - } - - TARGET(COPY) { - assert(oparg != 0); - PyObject *peek = PEEK(oparg); - PUSH(Py_NewRef(peek)); - DISPATCH(); - } - - TARGET(BINARY_OP) { - PREDICTED(BINARY_OP); - static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); - PyObject *rhs = PEEK(1); - PyObject *lhs = PEEK(2); - PyObject *res; - #if ENABLE_SPECIALIZATION - _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; - if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { - assert(cframe.use_tracing == 0); - next_instr--; - _Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, &GETLOCAL(0)); - DISPATCH_SAME_OPARG(); - } - STAT_INC(BINARY_OP, deferred); - DECREMENT_ADAPTIVE_COUNTER(cache->counter); - #endif /* ENABLE_SPECIALIZATION */ - assert(0 <= oparg); - assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); - assert(binary_ops[oparg]); - res = binary_ops[oparg](lhs, rhs); - Py_DECREF(lhs); - Py_DECREF(rhs); - if (res == NULL) goto pop_2_error; - STACK_SHRINK(1); - POKE(1, res); - JUMPBY(1); - DISPATCH(); - } - - TARGET(SWAP) { - assert(oparg != 0); - PyObject *top = TOP(); - SET_TOP(PEEK(oparg)); - PEEK(oparg) = top; - DISPATCH(); - } - - TARGET(EXTENDED_ARG) { - assert(oparg); - assert(cframe.use_tracing == 0); - opcode = _Py_OPCODE(*next_instr); - oparg = oparg << 8 | _Py_OPARG(*next_instr); - PRE_DISPATCH_GOTO(); - DISPATCH_GOTO(); - } - - TARGET(CACHE) { - Py_UNREACHABLE(); - } diff --git a/Python/opcode_metadata_tier2.h b/Python/opcode_metadata_tier2.h deleted file mode 100644 index bf9170e99cf754..00000000000000 --- a/Python/opcode_metadata_tier2.h +++ /dev/null @@ -1,882 +0,0 @@ -// This file is generated by Tools\cases_generator\generate_cases.py --metadata -// from Python\bytecodes.c -// Do not edit! - -#ifndef NDEBUG -static int -_PyOpcode_num_popped(int opcode, int oparg) { - switch(opcode) { - case NOP: - return 0; - case RESUME: - return 0; - case LOAD_CLOSURE: - return 0; - case LOAD_FAST_CHECK: - return 0; - case LOAD_FAST: - return 0; - case LOAD_CONST: - return 0; - case STORE_FAST: - return 1; - case LOAD_FAST__LOAD_FAST: - return 0+0; - case LOAD_FAST__LOAD_CONST: - return 0+0; - case STORE_FAST__LOAD_FAST: - return 1+0; - case STORE_FAST__STORE_FAST: - return 1+1; - case LOAD_CONST__LOAD_FAST: - return 0+0; - case POP_TOP: - return 1; - case PUSH_NULL: - return 0; - case END_FOR: - return 1+1; - case UNARY_NEGATIVE: - return 1; - case UNARY_NOT: - return 1; - case UNARY_INVERT: - return 1; - case BINARY_OP_MULTIPLY_INT: - return 2; - case BINARY_OP_MULTIPLY_FLOAT: - return 2; - case BINARY_OP_SUBTRACT_INT: - return 2; - case BINARY_OP_SUBTRACT_FLOAT: - return 2; - case BINARY_OP_ADD_UNICODE: - return 2; - case BINARY_OP_INPLACE_ADD_UNICODE: - return 2; - case BINARY_OP_ADD_FLOAT: - return 2; - case BINARY_OP_ADD_INT_TYPE_CHECK: - return 2; - case BINARY_OP_ADD_INT_REST: - return 2; - case BINARY_OP_ADD_INT: - return 2; - case BINARY_SUBSCR: - return 2; - case BINARY_SLICE: - return 3; - case STORE_SLICE: - return 4; - case BINARY_SUBSCR_LIST_INT: - return 2; - case BINARY_SUBSCR_TUPLE_INT: - return 2; - case BINARY_SUBSCR_DICT: - return 2; - case BINARY_SUBSCR_GETITEM: - return 2; - case LIST_APPEND: - return (oparg-1) + 2; - case SET_ADD: - return (oparg-1) + 2; - case STORE_SUBSCR: - return 3; - case STORE_SUBSCR_LIST_INT: - return 3; - case STORE_SUBSCR_DICT: - return 3; - case DELETE_SUBSCR: - return 2; - case CALL_INTRINSIC_1: - return 1; - case RAISE_VARARGS: - return oparg; - case INTERPRETER_EXIT: - return 1; - case RETURN_VALUE: - return 1; - case GET_AITER: - return 1; - case GET_ANEXT: - return 1; - case GET_AWAITABLE: - return 1; - case SEND: - return -1; - case YIELD_VALUE: - return 1; - case POP_EXCEPT: - return 1; - case RERAISE: - return -1; - case PREP_RERAISE_STAR: - return 2; - case END_ASYNC_FOR: - return -1; - case CLEANUP_THROW: - return -1; - case LOAD_ASSERTION_ERROR: - return 0; - case LOAD_BUILD_CLASS: - return 0; - case STORE_NAME: - return 1; - case DELETE_NAME: - return 0; - case UNPACK_SEQUENCE: - return -1; - case UNPACK_SEQUENCE_TWO_TUPLE: - return -1; - case UNPACK_SEQUENCE_TUPLE: - return -1; - case UNPACK_SEQUENCE_LIST: - return -1; - case UNPACK_EX: - return -1; - case STORE_ATTR: - return 2; - case DELETE_ATTR: - return 1; - case STORE_GLOBAL: - return 1; - case DELETE_GLOBAL: - return 0; - case LOAD_NAME: - return 0; - case LOAD_GLOBAL: - return -1; - case LOAD_GLOBAL_MODULE: - return -1; - case LOAD_GLOBAL_BUILTIN: - return -1; - case DELETE_FAST: - return 0; - case MAKE_CELL: - return 0; - case DELETE_DEREF: - return 0; - case LOAD_CLASSDEREF: - return 0; - case LOAD_DEREF: - return 0; - case STORE_DEREF: - return 1; - case COPY_FREE_VARS: - return 0; - case BUILD_STRING: - return oparg; - case BUILD_TUPLE: - return oparg; - case BUILD_LIST: - return oparg; - case LIST_EXTEND: - return (oparg-1) + 2; - case SET_UPDATE: - return (oparg-1) + 2; - case BUILD_SET: - return oparg; - case BUILD_MAP: - return oparg*2; - case SETUP_ANNOTATIONS: - return 0; - case BUILD_CONST_KEY_MAP: - return oparg + 1; - case DICT_UPDATE: - return 1; - case DICT_MERGE: - return 1; - case MAP_ADD: - return 2; - case LOAD_ATTR: - return -1; - case LOAD_ATTR_INSTANCE_VALUE: - return -1; - case LOAD_ATTR_MODULE: - return -1; - case LOAD_ATTR_WITH_HINT: - return -1; - case LOAD_ATTR_SLOT: - return -1; - case LOAD_ATTR_CLASS: - return -1; - case LOAD_ATTR_PROPERTY: - return -1; - case LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN: - return -1; - case STORE_ATTR_INSTANCE_VALUE: - return 2; - case STORE_ATTR_WITH_HINT: - return 2; - case STORE_ATTR_SLOT: - return 2; - case COMPARE_OP: - return 2; - case COMPARE_AND_BRANCH: - return 2; - case COMPARE_AND_BRANCH_FLOAT: - return 2; - case COMPARE_AND_BRANCH_INT: - return 2; - case COMPARE_AND_BRANCH_STR: - return 2; - case IS_OP: - return 2; - case CONTAINS_OP: - return 2; - case CHECK_EG_MATCH: - return 2; - case CHECK_EXC_MATCH: - return 2; - case IMPORT_NAME: - return 2; - case IMPORT_FROM: - return 1; - case JUMP_FORWARD: - return 0; - case JUMP_BACKWARD: - return 0; - case POP_JUMP_IF_FALSE: - return -1; - case POP_JUMP_IF_TRUE: - return -1; - case POP_JUMP_IF_NOT_NONE: - return -1; - case POP_JUMP_IF_NONE: - return -1; - case JUMP_IF_FALSE_OR_POP: - return -1; - case JUMP_IF_TRUE_OR_POP: - return -1; - case JUMP_BACKWARD_NO_INTERRUPT: - return -1; - case GET_LEN: - return -1; - case MATCH_CLASS: - return 3; - case MATCH_MAPPING: - return 1; - case MATCH_SEQUENCE: - return 1; - case MATCH_KEYS: - return 2; - case GET_ITER: - return -1; - case GET_YIELD_FROM_ITER: - return -1; - case FOR_ITER: - return -1; - case FOR_ITER_LIST: - return -1; - case FOR_ITER_TUPLE: - return -1; - case FOR_ITER_RANGE: - return -1; - case FOR_ITER_GEN: - return -1; - case BEFORE_ASYNC_WITH: - return -1; - case BEFORE_WITH: - return -1; - case WITH_EXCEPT_START: - return 4; - case PUSH_EXC_INFO: - return -1; - case LOAD_ATTR_METHOD_WITH_VALUES: - return -1; - case LOAD_ATTR_METHOD_NO_DICT: - return -1; - case LOAD_ATTR_METHOD_LAZY_DICT: - return -1; - case CALL_BOUND_METHOD_EXACT_ARGS: - return -1; - case KW_NAMES: - return -1; - case CALL: - return -1; - case CALL_PY_EXACT_ARGS: - return -1; - case CALL_PY_WITH_DEFAULTS: - return -1; - case CALL_NO_KW_TYPE_1: - return -1; - case CALL_NO_KW_STR_1: - return -1; - case CALL_NO_KW_TUPLE_1: - return -1; - case CALL_BUILTIN_CLASS: - return -1; - case CALL_NO_KW_BUILTIN_O: - return -1; - case CALL_NO_KW_BUILTIN_FAST: - return -1; - case CALL_BUILTIN_FAST_WITH_KEYWORDS: - return -1; - case CALL_NO_KW_LEN: - return -1; - case CALL_NO_KW_ISINSTANCE: - return -1; - case CALL_NO_KW_LIST_APPEND: - return -1; - case CALL_NO_KW_METHOD_DESCRIPTOR_O: - return -1; - case CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: - return -1; - case CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS: - return -1; - case CALL_NO_KW_METHOD_DESCRIPTOR_FAST: - return -1; - case CALL_FUNCTION_EX: - return -1; - case MAKE_FUNCTION: - return -1; - case RETURN_GENERATOR: - return -1; - case BUILD_SLICE: - return -1; - case FORMAT_VALUE: - return -1; - case COPY: - return -1; - case BINARY_OP: - return 2; - case SWAP: - return -1; - case EXTENDED_ARG: - return -1; - case CACHE: - return -1; - default: - Py_UNREACHABLE(); - } -} -#endif - -#ifndef NDEBUG -static int -_PyOpcode_num_pushed(int opcode, int oparg) { - switch(opcode) { - case NOP: - return 0; - case RESUME: - return 0; - case LOAD_CLOSURE: - return 1; - case LOAD_FAST_CHECK: - return 1; - case LOAD_FAST: - return 1; - case LOAD_CONST: - return 1; - case STORE_FAST: - return 0; - case LOAD_FAST__LOAD_FAST: - return 1+1; - case LOAD_FAST__LOAD_CONST: - return 1+1; - case STORE_FAST__LOAD_FAST: - return 0+1; - case STORE_FAST__STORE_FAST: - return 0+0; - case LOAD_CONST__LOAD_FAST: - return 1+1; - case POP_TOP: - return 0; - case PUSH_NULL: - return 1; - case END_FOR: - return 0+0; - case UNARY_NEGATIVE: - return 1; - case UNARY_NOT: - return 1; - case UNARY_INVERT: - return 1; - case BINARY_OP_MULTIPLY_INT: - return 1; - case BINARY_OP_MULTIPLY_FLOAT: - return 1; - case BINARY_OP_SUBTRACT_INT: - return 1; - case BINARY_OP_SUBTRACT_FLOAT: - return 1; - case BINARY_OP_ADD_UNICODE: - return 1; - case BINARY_OP_INPLACE_ADD_UNICODE: - return 0; - case BINARY_OP_ADD_FLOAT: - return 1; - case BINARY_OP_ADD_INT_TYPE_CHECK: - return 2; - case BINARY_OP_ADD_INT_REST: - return 1; - case BINARY_OP_ADD_INT: - return 1; - case BINARY_SUBSCR: - return 1; - case BINARY_SLICE: - return 1; - case STORE_SLICE: - return 0; - case BINARY_SUBSCR_LIST_INT: - return 1; - case BINARY_SUBSCR_TUPLE_INT: - return 1; - case BINARY_SUBSCR_DICT: - return 1; - case BINARY_SUBSCR_GETITEM: - return 1; - case LIST_APPEND: - return (oparg-1) + 1; - case SET_ADD: - return (oparg-1) + 1; - case STORE_SUBSCR: - return 0; - case STORE_SUBSCR_LIST_INT: - return 0; - case STORE_SUBSCR_DICT: - return 0; - case DELETE_SUBSCR: - return 0; - case CALL_INTRINSIC_1: - return 1; - case RAISE_VARARGS: - return 0; - case INTERPRETER_EXIT: - return 0; - case RETURN_VALUE: - return 0; - case GET_AITER: - return 1; - case GET_ANEXT: - return 2; - case GET_AWAITABLE: - return 1; - case SEND: - return -1; - case YIELD_VALUE: - return 1; - case POP_EXCEPT: - return 0; - case RERAISE: - return -1; - case PREP_RERAISE_STAR: - return 1; - case END_ASYNC_FOR: - return -1; - case CLEANUP_THROW: - return -1; - case LOAD_ASSERTION_ERROR: - return 1; - case LOAD_BUILD_CLASS: - return 1; - case STORE_NAME: - return 0; - case DELETE_NAME: - return 0; - case UNPACK_SEQUENCE: - return -1; - case UNPACK_SEQUENCE_TWO_TUPLE: - return -1; - case UNPACK_SEQUENCE_TUPLE: - return -1; - case UNPACK_SEQUENCE_LIST: - return -1; - case UNPACK_EX: - return -1; - case STORE_ATTR: - return 0; - case DELETE_ATTR: - return 0; - case STORE_GLOBAL: - return 0; - case DELETE_GLOBAL: - return 0; - case LOAD_NAME: - return 1; - case LOAD_GLOBAL: - return -1; - case LOAD_GLOBAL_MODULE: - return -1; - case LOAD_GLOBAL_BUILTIN: - return -1; - case DELETE_FAST: - return 0; - case MAKE_CELL: - return 0; - case DELETE_DEREF: - return 0; - case LOAD_CLASSDEREF: - return 1; - case LOAD_DEREF: - return 1; - case STORE_DEREF: - return 0; - case COPY_FREE_VARS: - return 0; - case BUILD_STRING: - return 1; - case BUILD_TUPLE: - return 1; - case BUILD_LIST: - return 1; - case LIST_EXTEND: - return (oparg-1) + 1; - case SET_UPDATE: - return (oparg-1) + 1; - case BUILD_SET: - return 1; - case BUILD_MAP: - return 1; - case SETUP_ANNOTATIONS: - return 0; - case BUILD_CONST_KEY_MAP: - return 1; - case DICT_UPDATE: - return 0; - case DICT_MERGE: - return 0; - case MAP_ADD: - return 0; - case LOAD_ATTR: - return -1; - case LOAD_ATTR_INSTANCE_VALUE: - return -1; - case LOAD_ATTR_MODULE: - return -1; - case LOAD_ATTR_WITH_HINT: - return -1; - case LOAD_ATTR_SLOT: - return -1; - case LOAD_ATTR_CLASS: - return -1; - case LOAD_ATTR_PROPERTY: - return -1; - case LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN: - return -1; - case STORE_ATTR_INSTANCE_VALUE: - return 0; - case STORE_ATTR_WITH_HINT: - return 0; - case STORE_ATTR_SLOT: - return 0; - case COMPARE_OP: - return 1; - case COMPARE_AND_BRANCH: - return 0; - case COMPARE_AND_BRANCH_FLOAT: - return 0; - case COMPARE_AND_BRANCH_INT: - return 0; - case COMPARE_AND_BRANCH_STR: - return 0; - case IS_OP: - return 1; - case CONTAINS_OP: - return 1; - case CHECK_EG_MATCH: - return 2; - case CHECK_EXC_MATCH: - return 2; - case IMPORT_NAME: - return 1; - case IMPORT_FROM: - return 2; - case JUMP_FORWARD: - return 0; - case JUMP_BACKWARD: - return 0; - case POP_JUMP_IF_FALSE: - return -1; - case POP_JUMP_IF_TRUE: - return -1; - case POP_JUMP_IF_NOT_NONE: - return -1; - case POP_JUMP_IF_NONE: - return -1; - case JUMP_IF_FALSE_OR_POP: - return -1; - case JUMP_IF_TRUE_OR_POP: - return -1; - case JUMP_BACKWARD_NO_INTERRUPT: - return -1; - case GET_LEN: - return -1; - case MATCH_CLASS: - return 1; - case MATCH_MAPPING: - return 2; - case MATCH_SEQUENCE: - return 2; - case MATCH_KEYS: - return 3; - case GET_ITER: - return -1; - case GET_YIELD_FROM_ITER: - return -1; - case FOR_ITER: - return -1; - case FOR_ITER_LIST: - return -1; - case FOR_ITER_TUPLE: - return -1; - case FOR_ITER_RANGE: - return -1; - case FOR_ITER_GEN: - return -1; - case BEFORE_ASYNC_WITH: - return -1; - case BEFORE_WITH: - return -1; - case WITH_EXCEPT_START: - return 5; - case PUSH_EXC_INFO: - return -1; - case LOAD_ATTR_METHOD_WITH_VALUES: - return -1; - case LOAD_ATTR_METHOD_NO_DICT: - return -1; - case LOAD_ATTR_METHOD_LAZY_DICT: - return -1; - case CALL_BOUND_METHOD_EXACT_ARGS: - return -1; - case KW_NAMES: - return -1; - case CALL: - return -1; - case CALL_PY_EXACT_ARGS: - return -1; - case CALL_PY_WITH_DEFAULTS: - return -1; - case CALL_NO_KW_TYPE_1: - return -1; - case CALL_NO_KW_STR_1: - return -1; - case CALL_NO_KW_TUPLE_1: - return -1; - case CALL_BUILTIN_CLASS: - return -1; - case CALL_NO_KW_BUILTIN_O: - return -1; - case CALL_NO_KW_BUILTIN_FAST: - return -1; - case CALL_BUILTIN_FAST_WITH_KEYWORDS: - return -1; - case CALL_NO_KW_LEN: - return -1; - case CALL_NO_KW_ISINSTANCE: - return -1; - case CALL_NO_KW_LIST_APPEND: - return -1; - case CALL_NO_KW_METHOD_DESCRIPTOR_O: - return -1; - case CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: - return -1; - case CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS: - return -1; - case CALL_NO_KW_METHOD_DESCRIPTOR_FAST: - return -1; - case CALL_FUNCTION_EX: - return -1; - case MAKE_FUNCTION: - return -1; - case RETURN_GENERATOR: - return -1; - case BUILD_SLICE: - return -1; - case FORMAT_VALUE: - return -1; - case COPY: - return -1; - case BINARY_OP: - return 1; - case SWAP: - return -1; - case EXTENDED_ARG: - return -1; - case CACHE: - return -1; - default: - Py_UNREACHABLE(); - } -} -#endif -enum Direction { DIR_NONE, DIR_READ, DIR_WRITE }; -enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC0, INSTR_FMT_IBC000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; -struct opcode_metadata { - enum Direction dir_op1; - enum Direction dir_op2; - enum Direction dir_op3; - bool valid_entry; - enum InstructionFormat instr_format; -} _PyOpcode_opcode_metadata[256] = { - [NOP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [RESUME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_CLOSURE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_FAST_CHECK] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_CONST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_FAST__LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [LOAD_FAST__LOAD_CONST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [STORE_FAST__LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [STORE_FAST__STORE_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [LOAD_CONST__LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [POP_TOP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [PUSH_NULL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [END_FOR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [UNARY_NEGATIVE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [UNARY_NOT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [UNARY_INVERT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BINARY_OP_MULTIPLY_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_MULTIPLY_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_SUBTRACT_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_SUBTRACT_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_ADD_UNICODE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_INPLACE_ADD_UNICODE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BINARY_OP_ADD_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_ADD_INT_TYPE_CHECK] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_ADD_INT_REST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_SUBSCR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [BINARY_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [STORE_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BINARY_SUBSCR_LIST_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [BINARY_SUBSCR_TUPLE_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [BINARY_SUBSCR_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [BINARY_SUBSCR_GETITEM] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [LIST_APPEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [SET_ADD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_SUBSCR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [STORE_SUBSCR_LIST_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [STORE_SUBSCR_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [DELETE_SUBSCR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [CALL_INTRINSIC_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [RAISE_VARARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [INTERPRETER_EXIT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [RETURN_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [GET_AITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [GET_ANEXT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [GET_AWAITABLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [SEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [YIELD_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [POP_EXCEPT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [RERAISE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [PREP_RERAISE_STAR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [END_ASYNC_FOR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [CLEANUP_THROW] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [LOAD_ASSERTION_ERROR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [LOAD_BUILD_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [STORE_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DELETE_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [UNPACK_SEQUENCE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [UNPACK_SEQUENCE_TWO_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [UNPACK_SEQUENCE_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [UNPACK_SEQUENCE_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [UNPACK_EX] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_ATTR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [DELETE_ATTR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_GLOBAL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DELETE_GLOBAL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_GLOBAL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_GLOBAL_MODULE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_GLOBAL_BUILTIN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DELETE_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [MAKE_CELL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DELETE_DEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_CLASSDEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_DEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_DEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [COPY_FREE_VARS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_STRING] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LIST_EXTEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [SET_UPDATE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_SET] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_MAP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [SETUP_ANNOTATIONS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BUILD_CONST_KEY_MAP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DICT_UPDATE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DICT_MERGE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [MAP_ADD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_ATTR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_ATTR_INSTANCE_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_ATTR_MODULE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_ATTR_WITH_HINT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_ATTR_SLOT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_ATTR_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_ATTR_PROPERTY] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_ATTR_INSTANCE_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [STORE_ATTR_WITH_HINT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [STORE_ATTR_SLOT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [COMPARE_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [COMPARE_AND_BRANCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_STR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, - [IS_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CONTAINS_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CHECK_EG_MATCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [CHECK_EXC_MATCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [IMPORT_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [IMPORT_FROM] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [JUMP_FORWARD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [JUMP_BACKWARD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [POP_JUMP_IF_FALSE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [POP_JUMP_IF_TRUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [POP_JUMP_IF_NOT_NONE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [POP_JUMP_IF_NONE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [JUMP_IF_FALSE_OR_POP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [JUMP_IF_TRUE_OR_POP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [JUMP_BACKWARD_NO_INTERRUPT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [GET_LEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [MATCH_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [MATCH_MAPPING] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [MATCH_SEQUENCE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [MATCH_KEYS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [GET_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [GET_YIELD_FROM_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [FOR_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [FOR_ITER_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [FOR_ITER_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [FOR_ITER_RANGE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [FOR_ITER_GEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BEFORE_ASYNC_WITH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BEFORE_WITH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [WITH_EXCEPT_START] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [PUSH_EXC_INFO] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [LOAD_ATTR_METHOD_WITH_VALUES] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [LOAD_ATTR_METHOD_NO_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [LOAD_ATTR_METHOD_LAZY_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [CALL_BOUND_METHOD_EXACT_ARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [KW_NAMES] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_PY_EXACT_ARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_PY_WITH_DEFAULTS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_NO_KW_TYPE_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_NO_KW_STR_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_NO_KW_TUPLE_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_BUILTIN_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_NO_KW_BUILTIN_O] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_NO_KW_BUILTIN_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_NO_KW_LEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_NO_KW_ISINSTANCE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_NO_KW_LIST_APPEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_NO_KW_METHOD_DESCRIPTOR_O] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_FUNCTION_EX] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [MAKE_FUNCTION] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [RETURN_GENERATOR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BUILD_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [FORMAT_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [COPY] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BINARY_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [SWAP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [EXTENDED_ARG] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CACHE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, -}; diff --git a/Tools/build/generate_opcode_h.py b/Tools/build/generate_opcode_h.py index 3ff94a324a0803..d3889f5b67fd7f 100644 --- a/Tools/build/generate_opcode_h.py +++ b/Tools/build/generate_opcode_h.py @@ -113,19 +113,12 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna # The Tier 2 ops next_op = 1 uop_opmap = specialized_opmap.copy() - uop_opname = opname_including_specialized.copy() - # Remove macroops - for name in opcode['_macro_ops']: - op = uop_opmap[name] - del uop_opmap[name] - del uop_opname[op] - used[op] = False # Add microops for name in opcode['_uops']: while used[next_op]: next_op += 1 uop_opmap[name] = next_op - uop_opname[next_op] = name + opname_including_specialized[next_op] = name used[next_op] = True with open(outfile, 'w') as fobj, open(internaloutfile, 'w') as iobj: @@ -147,19 +140,13 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna if op == MAX_PSEUDO_OPCODE: fobj.write(DEFINE.format("MAX_PSEUDO_OPCODE", MAX_PSEUDO_OPCODE)) - fobj.write("\n") - fobj.write("#ifndef Py_TIER2_INTERPRETER\n") for name, op in specialized_opmap.items(): fobj.write(DEFINE.format(name, op)) - fobj.write("#endif\n") - fobj.write("\n") # Tier 2 opcodes - fobj.write("#ifdef Py_TIER2_INTERPRETER\n") + fobj.write("// Tier 2 interpreter ops\n") for name, op in uop_opmap.items(): fobj.write(DEFINE.format(name, op)) - fobj.write("#endif\n") - fobj.write("\n") iobj.write("\nextern const uint8_t _PyOpcode_Caches[256];\n") iobj.write("\nextern const uint8_t _PyOpcode_Deopt[256];\n") @@ -209,7 +196,7 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna iobj.write("\n") # Tier 1 opnames - iobj.write("#if defined(Py_DEBUG) && !defined(Py_TIER2_INTERPRETER)\n") + iobj.write("#ifdef Py_DEBUG\n") iobj.write(f"static const char *const _PyOpcode_OpName[{NUM_OPCODES}] = {{\n") for op, name in enumerate(opname_including_specialized): if name[0] != "<": @@ -219,15 +206,6 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna iobj.write("#endif\n") iobj.write("\n") - # Tier 2 opnames - iobj.write("#if defined(Py_DEBUG) && defined(Py_TIER2_INTERPRETER)\n") - iobj.write(f"static const char *const _PyOpcode_OpName[{NUM_OPCODES}] = {{\n") - for op, name in enumerate(uop_opname): - if name[0] != "<": - op = name - iobj.write(f''' [{op}] = "{name}",\n''') - iobj.write("};\n") - iobj.write("#endif\n") iobj.write("\n") iobj.write("#define EXTRA_CASES \\\n") diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 890d304def8098..39d50c43a59cd6 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -30,10 +30,6 @@ ) # Tier 2 interpreter -TIER2_OUTPUT = os.path.relpath(os.path.join(ROOT, "Python/generated_cases_tier2.c.h")) -TIER2_METADATA_OUTPUT = os.path.relpath( - os.path.join(ROOT, "Python/opcode_metadata_tier2.h") -) TIER2_MACRO_TO_MICRO_MAP_OUTPUT = os.path.relpath( os.path.join(ROOT, "Include/internal/pycore_opcode_macro_to_micro.h") ) @@ -70,11 +66,6 @@ ) -class InterpreterTier(Enum): - TIER1 = auto() - TIER2 = auto() - - def effect_size(effect: StackEffect) -> tuple[int, str]: """Return the 'size' impact of a stack effect. @@ -385,7 +376,7 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None for line in self.block_text: if m := re.match(r"(\s*)U_INST\((.+)\);\s*$", line): space, label = m.groups() - out.emit(f"{label}();") + out.emit(f"UOP_{label}();") elif m := re.match(r"(\s*)ERROR_IF\((.+), (\w+)\);\s*(?://.*)?$", line): space, cond, label = m.groups() # ERROR_IF() must pop the inputs from the stack. @@ -478,15 +469,13 @@ class Analyzer: filename: str output_filename: str - tier: InterpreterTier src: str errors: int = 0 - def __init__(self, filename: str, output_filename: str, tier: InterpreterTier): + def __init__(self, filename: str, output_filename: str): """Read the input file.""" self.filename = filename self.output_filename = output_filename - self.tier = tier with open(filename) as f: self.src = f.read() @@ -938,9 +927,6 @@ def write_metadata(self) -> None: case parser.InstDef(): if thing.kind == "op": continue - if ((thing.kind == "macro_inst" and self.tier != InterpreterTier.TIER1) - or (thing.kind == "u_inst" and self.tier != InterpreterTier.TIER2)): - continue self.write_metadata_for_inst(self.instrs[thing.name]) case parser.Super(): self.write_metadata_for_super(self.super_instrs[thing.name]) @@ -999,15 +985,14 @@ def write_instructions(self) -> None: n_macros = 0 # Single pass to hoist all the u_instructions to the top. - if self.tier == InterpreterTier.TIER1: - for thing in self.everything: - match thing: - case parser.InstDef(): - if thing.kind == "u_inst": - self.write_u_inst_as_c_macro( - self.instrs[thing.name]) - case _: - pass + for thing in self.everything: + match thing: + case parser.InstDef(): + if thing.kind == "u_inst": + self.write_u_inst_as_c_macro( + self.instrs[thing.name]) + case _: + pass # Everything else for thing in self.everything: @@ -1016,10 +1001,6 @@ def write_instructions(self) -> None: match thing.kind: case "op": pass - case "u_inst" if self.tier != InterpreterTier.TIER2: - pass - case "macro_inst" if self.tier != InterpreterTier.TIER1: - pass case _: n_instrs += 1 self.write_instr(self.instrs[thing.name]) @@ -1053,7 +1034,7 @@ def write_instr(self, instr: Instruction) -> None: def write_u_inst_as_c_macro(self, instr: Instruction) -> None: name = instr.name self.out.emit("") - self.out.emit(f"#define {name}() \\") + self.out.emit(f"#define UOP_{name}() \\") self.out.emit("do { \\") self.out.postfix = "\\" instr.write_body(self.out, 0) @@ -1167,40 +1148,29 @@ def variable_used(node: parser.Node, name: str) -> bool: """Determine whether a variable with a given name is used in a node.""" return any(token.kind == "IDENTIFIER" and token.text == name for token in node.tokens) +def main(): + """Parse command line, parse input, analyze, write output.""" + args = arg_parser.parse_args() # Prints message and sys.exit(2) on error -def generate_interpreter(input_: str, output: str, metadata: bool, macromap: bool, - tier: InterpreterTier) -> None: - if tier == InterpreterTier.TIER2 and macromap: - output = TIER2_MACRO_TO_MICRO_MAP_OUTPUT - if metadata: - if output == DEFAULT_OUTPUT: + if args.macromap: + if args.output == DEFAULT_OUTPUT: + output = TIER2_MACRO_TO_MICRO_MAP_OUTPUT + elif args.metadata: + if args.output == DEFAULT_OUTPUT: output = DEFAULT_METADATA_OUTPUT - elif output == TIER2_OUTPUT: - output = TIER2_METADATA_OUTPUT - a = Analyzer(input_, output, tier) # Raises OSError if input unreadable + a = Analyzer(args.input, args.output) # Raises OSError if input unreadable a.parse() # Raises SyntaxError on failure a.analyze() # Prints messages and sets a.errors on failure if a.errors: sys.exit(f"Found {a.errors} errors") - if macromap: + if args.macromap: a.write_macromap() return - if metadata: + elif args.metadata: a.write_metadata() else: a.write_instructions() # Raises OSError if output can't be written -def main(): - """Parse command line, parse input, analyze, write output.""" - args = arg_parser.parse_args() # Prints message and sys.exit(2) on error - - # Tier 1 interpreter - generate_interpreter(args.input, args.output, args.metadata, False, - InterpreterTier.TIER1) - # Tier 2 interpreter - generate_interpreter(args.input, TIER2_OUTPUT, args.metadata, args.macromap, - InterpreterTier.TIER2) - if __name__ == "__main__": main() From d7566dd9639d892fa72450bc3c5007c1d9994e9c Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sun, 29 Jan 2023 02:22:00 +0800 Subject: [PATCH 008/280] Generate type information mapping --- .../internal/pycore_opcode_macro_to_micro.h | 11 ++- PCbuild/pythoncore.vcxproj | 5 +- PCbuild/pythoncore.vcxproj.filters | 3 + Python/bytecodes.c | 2 +- Python/specialize.c | 1 + Tools/cases_generator/generate_cases.py | 82 ++++++++++++------- 6 files changed, 68 insertions(+), 36 deletions(-) diff --git a/Include/internal/pycore_opcode_macro_to_micro.h b/Include/internal/pycore_opcode_macro_to_micro.h index aa9049ee5b9518..ab2cd8b54eb368 100644 --- a/Include/internal/pycore_opcode_macro_to_micro.h +++ b/Include/internal/pycore_opcode_macro_to_micro.h @@ -2,8 +2,8 @@ // from Python\bytecodes.c // Do not edit! -#ifndef Py_INTERNAL_OPCODE_MACRO_TO_MICRO -#define Py_INTERNAL_OPCODE_MACRO_TO_MICRO +#ifndef Py_INTERNAL_OPCODE_MACRO_TO_MICRO_H +#define Py_INTERNAL_OPCODE_MACRO_TO_MICRO_H #ifdef __cplusplus extern "C" { #endif @@ -178,11 +178,14 @@ extern const int _Py_MacroOpUOpCount[] = { [SWAP] = 1, [EXTENDED_ARG] = 1, [CACHE] = 1, -} +}; extern const int _Py_MacroOpToUOp[][2] = { [BINARY_OP_ADD_INT] = {BINARY_OP_ADD_INT_TYPE_CHECK, BINARY_OP_ADD_INT_REST}, -} +}; +extern const PyTypeObject *_Py_UOpGuardTypes[][2] = { +[BINARY_OP_ADD_INT_TYPE_CHECK] = {&PyLong_Type, &PyLong_Type}, +}; #ifdef __cplusplus } #endif diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index d3bd5b378e0dd0..791562710efc54 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -123,6 +123,7 @@ + @@ -615,7 +616,6 @@ - @@ -624,8 +624,7 @@ - - + \ No newline at end of file diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index c1b531fd818a97..fe5bc990fec207 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -738,6 +738,9 @@ Include\internal + + Include\internal + diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 94f4b7ec15567c..8d9d4aee23b6a4 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -289,7 +289,7 @@ dummy_func( U_INST(BINARY_OP_ADD_INT_REST); } - u_inst(BINARY_OP_ADD_INT_TYPE_CHECK, (left, right -- left, right)) { + u_inst(BINARY_OP_ADD_INT_TYPE_CHECK, (left : PyLong_Type, right : PyLong_Type -- left, right)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); diff --git a/Python/specialize.c b/Python/specialize.c index 84784b2d149e82..77c5f2a30286bd 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -9,6 +9,7 @@ #include "pycore_opcode.h" // _PyOpcode_Caches #include "structmember.h" // struct PyMemberDef, T_OFFSET_EX #include "pycore_descrobject.h" +#include "pycore_opcode_macro_to_micro.h" #include // rand() diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 39d50c43a59cd6..8e6d9beb147511 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -62,6 +62,7 @@ "--macromap", action="store_true", help=f"Generate macro to micro instruction map instead," + f" along with the type for uop type guards" f"changes output default to {TIER2_MACRO_TO_MICRO_MAP_OUTPUT}", ) @@ -497,6 +498,7 @@ def error(self, msg: str, node: parser.Node) -> None: macros: dict[str, parser.Macro] macro_instrs: dict[str, MacroInstruction] macro_instdefs: list[parser.InstDef] + u_insts: list[parser.InstDef] families: dict[str, parser.Family] def parse(self) -> None: @@ -531,6 +533,7 @@ def parse(self) -> None: self.macros = {} self.macro_instrs = {} self.macro_instdefs = [] + self.u_insts = [] self.families = {} while thing := psr.definition(): match thing: @@ -539,6 +542,8 @@ def parse(self) -> None: self.everything.append(thing) if thing.kind == "macro_inst": self.macro_instdefs.append(thing) + elif thing.kind == "u_inst": + self.u_insts.append(thing) case parser.Super(name): self.supers[name] = thing self.everything.append(thing) @@ -829,8 +834,7 @@ def write_function(direction: str, data: list[tuple[Instruction, str]]) -> None: write_function('popped', popped_data) write_function('pushed', pushed_data) - def write_macromap(self): - """Write the macro instruction to uop mapping to output file.""" + def write_macromap_and_typedata(self): with open(self.output_filename, "w") as f: # Write provenance header f.write(f"// This file is generated by {THIS} --macromap\n") @@ -841,8 +845,8 @@ def write_macromap(self): self.out = Formatter(f, 0) # Header guard self.out.emit("") - self.out.emit("#ifndef Py_INTERNAL_OPCODE_MACRO_TO_MICRO") - self.out.emit("#define Py_INTERNAL_OPCODE_MACRO_TO_MICRO") + self.out.emit("#ifndef Py_INTERNAL_OPCODE_MACRO_TO_MICRO_H") + self.out.emit("#define Py_INTERNAL_OPCODE_MACRO_TO_MICRO_H") self.out.emit("#ifdef __cplusplus") self.out.emit('extern "C" {') self.out.emit("#endif") @@ -852,33 +856,55 @@ def write_macromap(self): self.out.emit("#endif") self.out.emit('#include "opcode.h"') self.out.emit("") - - self.out.emit("extern const int _Py_MacroOpUOpCount[] = {") - macro_instrdef_names = set() - max_instr_len = 0 - for name, instr_def in self.instrs.items(): - if (macro_def := instr_def.inst) in self.macro_instdefs: - u_insts = macro_def.u_insts - instr_len = len(u_insts) - max_instr_len = max(instr_len, max_instr_len) - self.out.emit(f"[{macro_def.name}] = {instr_len},") - macro_instrdef_names.add(macro_def.name) - else: - self.out.emit(f"[{name}] = 1,") - self.out.emit("}") - self.out.emit("") - self.out.emit(f"extern const int _Py_MacroOpToUOp[][{max_instr_len}] = {{") - for macro_def in self.macro_instdefs: - u_insts = macro_def.u_insts - self.out.emit(f"[{macro_def.name}] = {{{', '.join(u_insts)}}},") - self.out.emit("}") - + self.write_macromap() + self.write_uopguard_typedata() # Header guard end self.out.emit("#ifdef __cplusplus") self.out.emit("}") self.out.emit("#endif") self.out.emit("#endif // Py_INTERNAL_OPCODE_MACRO_TO_MICRO") + def write_macromap(self): + """Write the macro instruction to uop mapping to output file.""" + self.out.emit("extern const int _Py_MacroOpUOpCount[] = {") + macro_instrdef_names = set() + max_instr_len = 0 + for name, instr_def in self.instrs.items(): + if (macro_def := instr_def.inst) in self.macro_instdefs: + u_insts = macro_def.u_insts + instr_len = len(u_insts) + max_instr_len = max(instr_len, max_instr_len) + self.out.emit(f"[{macro_def.name}] = {instr_len},") + macro_instrdef_names.add(macro_def.name) + else: + self.out.emit(f"[{name}] = 1,") + self.out.emit("};") + self.out.emit("") + self.out.emit(f"extern const int _Py_MacroOpToUOp[][{max_instr_len}] = {{") + for macro_def in self.macro_instdefs: + u_insts = macro_def.u_insts + self.out.emit(f"[{macro_def.name}] = {{{', '.join(u_insts)}}},") + self.out.emit("};") + + def write_uopguard_typedata(self): + """Write the type information expected of each uop typeguard.""" + uop_to_type_input = {} + max_types = 0 + for instr_def in self.u_insts: + types = [] + for input_ in instr_def.inputs: + if isinstance(input_, StackEffect) and input_.type: + types.append(input_.type) + if types: + max_types = max(max_types, len(types)) + uop_to_type_input[instr_def.name] = types + + self.out.emit(f"extern const PyTypeObject *_Py_UOpGuardTypes[][{max_types}] = {{") + for name, types in uop_to_type_input.items(): + self.out.emit(f"[{name}] = {{{', '.join(['&' + type_ for type_ in types])}}},") + self.out.emit("};") + + def write_metadata(self) -> None: """Write instruction metadata to output file.""" @@ -1154,17 +1180,17 @@ def main(): if args.macromap: if args.output == DEFAULT_OUTPUT: - output = TIER2_MACRO_TO_MICRO_MAP_OUTPUT + args.output = TIER2_MACRO_TO_MICRO_MAP_OUTPUT elif args.metadata: if args.output == DEFAULT_OUTPUT: - output = DEFAULT_METADATA_OUTPUT + args.output = DEFAULT_METADATA_OUTPUT a = Analyzer(args.input, args.output) # Raises OSError if input unreadable a.parse() # Raises SyntaxError on failure a.analyze() # Prints messages and sets a.errors on failure if a.errors: sys.exit(f"Found {a.errors} errors") if args.macromap: - a.write_macromap() + a.write_macromap_and_typedata() return elif args.metadata: a.write_metadata() From ef6f491955f38c7b15969ac41a195a8a078bf7f2 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sun, 29 Jan 2023 15:29:17 +0800 Subject: [PATCH 009/280] Generate type data using output of guards --- Include/internal/pycore_opcode.h | 5 ++--- Include/opcode.h | 5 +++-- Lib/opcode.py | 1 + Python/bytecodes.c | 2 +- Python/compile.c | 1 + Tools/cases_generator/generate_cases.py | 12 ++++++------ 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 92ce888e0c322f..457a1a4d87ec23 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -389,13 +389,13 @@ static const char *const _PyOpcode_OpName[263] = { [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", - [BINARY_OP_ADD_INT_TYPE_CHECK] = "BINARY_OP_ADD_INT_TYPE_CHECK", + [BB_NEXT] = "BB_NEXT", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", + [BINARY_OP_ADD_INT_TYPE_CHECK] = "BINARY_OP_ADD_INT_TYPE_CHECK", [BINARY_OP_ADD_INT_REST] = "BINARY_OP_ADD_INT_REST", - [167] = "<167>", [168] = "<168>", [169] = "<169>", [170] = "<170>", @@ -496,7 +496,6 @@ static const char *const _PyOpcode_OpName[263] = { #define EXTRA_CASES \ - case 167: \ case 168: \ case 169: \ case 170: \ diff --git a/Include/opcode.h b/Include/opcode.h index 93635c89da2626..2b0c652e865331 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -250,8 +250,9 @@ extern "C" { #define UNPACK_SEQUENCE_TUPLE 159 #define UNPACK_SEQUENCE_TWO_TUPLE 160 #define DO_TRACING 255 -#define BINARY_OP_ADD_INT_TYPE_CHECK 161 -#define BINARY_OP_ADD_INT_REST 166 +#define BB_NEXT 161 +#define BINARY_OP_ADD_INT_TYPE_CHECK 166 +#define BINARY_OP_ADD_INT_REST 167 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/opcode.py b/Lib/opcode.py index 9c1402e316d395..292eae330c2095 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -437,6 +437,7 @@ def pseudo_op(name, op, real_ops): 'BINARY_OP_ADD_INT', ] _uops = [ + 'BB_NEXT', 'BINARY_OP_ADD_INT_TYPE_CHECK', 'BINARY_OP_ADD_INT_REST', ] diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 8d9d4aee23b6a4..5fdf0b137e638a 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -289,7 +289,7 @@ dummy_func( U_INST(BINARY_OP_ADD_INT_REST); } - u_inst(BINARY_OP_ADD_INT_TYPE_CHECK, (left : PyLong_Type, right : PyLong_Type -- left, right)) { + u_inst(BINARY_OP_ADD_INT_TYPE_CHECK, (left, right-- left : PyLong_Type, right: PyLong_Type)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); diff --git a/Python/compile.c b/Python/compile.c index c31f08c0a1797b..18ef7646117979 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1079,6 +1079,7 @@ stack_effect(int opcode, int oparg, int jump) case EXTENDED_ARG: case RESUME: case CACHE: + case BB_NEXT: return 0; /* Stack manipulation */ diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 8e6d9beb147511..0d173619a9b807 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -888,19 +888,19 @@ def write_macromap(self): def write_uopguard_typedata(self): """Write the type information expected of each uop typeguard.""" - uop_to_type_input = {} + uop_to_type_output = {} max_types = 0 for instr_def in self.u_insts: types = [] - for input_ in instr_def.inputs: - if isinstance(input_, StackEffect) and input_.type: - types.append(input_.type) + for output in instr_def.outputs: + if isinstance(output, StackEffect) and output.type: + types.append(output.type) if types: max_types = max(max_types, len(types)) - uop_to_type_input[instr_def.name] = types + uop_to_type_output[instr_def.name] = types self.out.emit(f"extern const PyTypeObject *_Py_UOpGuardTypes[][{max_types}] = {{") - for name, types in uop_to_type_input.items(): + for name, types in uop_to_type_output.items(): self.out.emit(f"[{name}] = {{{', '.join(['&' + type_ for type_ in types])}}},") self.out.emit("};") From 9c83802ddc8aa9f563771cc4dc27b78e169f88fe Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sun, 29 Jan 2023 20:42:33 +0800 Subject: [PATCH 010/280] [NOT WORKING] Allocate basic blocks --- Include/cpython/code.h | 19 ++ Include/internal/pycore_code.h | 3 + Include/internal/pycore_frame.h | 5 +- Include/internal/pycore_opcode.h | 66 +++---- Include/opcode.h | 254 +++++++++++++------------ Lib/opcode.py | 6 + Objects/codeobject.c | 23 +++ Objects/genobject.c | 5 +- PCbuild/_freeze_module.vcxproj | 1 + PCbuild/_freeze_module.vcxproj.filters | 3 + PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 3 + Python/bytecodes.c | 10 + Python/ceval_macros.h | 4 +- Python/generated_cases.c.h | 17 +- Python/opcode_targets.h | 60 +++--- Python/tier2.c | 62 ++++++ Tools/build/deepfreeze.py | 3 + 18 files changed, 351 insertions(+), 194 deletions(-) create mode 100644 Python/tier2.c diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 0cf49f06c87732..e0c173411594d4 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -42,6 +42,22 @@ typedef struct { PyObject *_co_freevars; } _PyCoCached; + +// What the tier 2 interpreter executes +typedef struct _PyTier2BB { + // Stores the start pointer in the tier 1 bytecode. + // So that when we exit the trace we can calculate where to return. + _Py_CODEUNIT *tier1_start; + _Py_CODEUNIT u_code[1]; +} _PyTier2BB; + +// Bump allocator for basic blocks (overallocated) +typedef struct _PyTier2BBSpace { + struct _PyTier2BBSpace *next; + void *water_level; + _PyTier2BB bbs[1]; +} _PyTier2BBSpace; + // To avoid repeating ourselves in deepfreeze.py, all PyCodeObject members are // defined in this macro: #define _PyCode_DEF(SIZE) { \ @@ -102,6 +118,9 @@ typedef struct { _PyCoCached *_co_cached; /* cached co_* attributes */ \ int _co_firsttraceable; /* index of first traceable instruction */ \ char *_co_linearray; /* array of line offsets */ \ + int _tier2_warmup; /* warmup counter for tier 2 */ \ + _PyTier2BB *_bb_next; /* the tier 2 basic block to execute (if any) */ \ + _PyTier2BBSpace *_bb_space; /* linked list storing basic blocks */ \ /* Scratch space for extra data relating to the code object. \ Type is a void* to keep the format private in codeobject.c to force \ people to go through the proper APIs. */ \ diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index a287250acc1912..090353cac17d6a 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -239,6 +239,9 @@ extern void _PyStaticCode_Fini(PyCodeObject *co); /* Function to intern strings of codeobjects and quicken the bytecode */ extern int _PyStaticCode_Init(PyCodeObject *co); +/* Tier 2 interpreter */ +extern void _PyCode_Tier2Warmup(struct _PyInterpreterFrame *, _Py_CODEUNIT **); + #ifdef Py_STATS diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index f12b225ebfccf2..695fc94cc956a9 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -69,7 +69,8 @@ typedef struct _PyInterpreterFrame { } _PyInterpreterFrame; #define _PyInterpreterFrame_LASTI(IF) \ - ((int)((IF)->prev_instr - _PyCode_CODE((IF)->f_code))) + ((int)((IF)->prev_instr - \ + ((IF)->f_code->_bb_next == NULL ? _PyCode_CODE((IF)->f_code) : (IF)->f_code->_bb_next->u_code))) static inline PyObject **_PyFrame_Stackbase(_PyInterpreterFrame *f) { return f->localsplus + f->f_code->co_nlocalsplus; @@ -121,7 +122,7 @@ _PyFrame_Initialize( frame->f_locals = locals; frame->stacktop = code->co_nlocalsplus; frame->frame_obj = NULL; - frame->prev_instr = _PyCode_CODE(code) - 1; + frame->prev_instr = (code->_bb_next == NULL ? _PyCode_CODE(code) - 1 : code->_bb_next->u_code - 1); frame->yield_offset = 0; frame->owner = FRAME_OWNED_BY_THREAD; diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 457a1a4d87ec23..b7f27863ba5e24 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -140,6 +140,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [IS_OP] = IS_OP, [JUMP_BACKWARD] = JUMP_BACKWARD, [JUMP_BACKWARD_NO_INTERRUPT] = JUMP_BACKWARD_NO_INTERRUPT, + [JUMP_BACKWARD_QUICK] = JUMP_BACKWARD, [JUMP_FORWARD] = JUMP_FORWARD, [JUMP_IF_FALSE_OR_POP] = JUMP_IF_FALSE_OR_POP, [JUMP_IF_TRUE_OR_POP] = JUMP_IF_TRUE_OR_POP, @@ -192,6 +193,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [RAISE_VARARGS] = RAISE_VARARGS, [RERAISE] = RERAISE, [RESUME] = RESUME, + [RESUME_QUICK] = RESUME, [RETURN_GENERATOR] = RETURN_GENERATOR, [RETURN_VALUE] = RETURN_VALUE, [SEND] = SEND, @@ -233,17 +235,19 @@ static const char *const _PyOpcode_OpName[263] = { [PUSH_NULL] = "PUSH_NULL", [INTERPRETER_EXIT] = "INTERPRETER_EXIT", [END_FOR] = "END_FOR", + [RESUME_QUICK] = "RESUME_QUICK", + [JUMP_BACKWARD_QUICK] = "JUMP_BACKWARD_QUICK", [BINARY_OP_ADD_FLOAT] = "BINARY_OP_ADD_FLOAT", [BINARY_OP_ADD_INT] = "BINARY_OP_ADD_INT", - [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE", - [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", [NOP] = "NOP", - [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT", + [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE", [UNARY_NEGATIVE] = "UNARY_NEGATIVE", [UNARY_NOT] = "UNARY_NOT", + [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", + [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT", + [UNARY_INVERT] = "UNARY_INVERT", [BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT", [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT", - [UNARY_INVERT] = "UNARY_INVERT", [BINARY_OP_SUBTRACT_INT] = "BINARY_OP_SUBTRACT_INT", [BINARY_SUBSCR_DICT] = "BINARY_SUBSCR_DICT", [BINARY_SUBSCR_GETITEM] = "BINARY_SUBSCR_GETITEM", @@ -251,21 +255,21 @@ static const char *const _PyOpcode_OpName[263] = { [BINARY_SUBSCR_TUPLE_INT] = "BINARY_SUBSCR_TUPLE_INT", [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS", [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", - [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", - [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", [BINARY_SUBSCR] = "BINARY_SUBSCR", [BINARY_SLICE] = "BINARY_SLICE", [STORE_SLICE] = "STORE_SLICE", - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", - [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", + [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", + [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", [GET_LEN] = "GET_LEN", [MATCH_MAPPING] = "MATCH_MAPPING", [MATCH_SEQUENCE] = "MATCH_SEQUENCE", [MATCH_KEYS] = "MATCH_KEYS", - [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", [PUSH_EXC_INFO] = "PUSH_EXC_INFO", [CHECK_EXC_MATCH] = "CHECK_EXC_MATCH", [CHECK_EG_MATCH] = "CHECK_EG_MATCH", + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", + [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", [CALL_NO_KW_BUILTIN_O] = "CALL_NO_KW_BUILTIN_O", [CALL_NO_KW_ISINSTANCE] = "CALL_NO_KW_ISINSTANCE", [CALL_NO_KW_LEN] = "CALL_NO_KW_LEN", @@ -275,8 +279,6 @@ static const char *const _PyOpcode_OpName[263] = { [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", - [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", - [COMPARE_AND_BRANCH_FLOAT] = "COMPARE_AND_BRANCH_FLOAT", [WITH_EXCEPT_START] = "WITH_EXCEPT_START", [GET_AITER] = "GET_AITER", [GET_ANEXT] = "GET_ANEXT", @@ -284,38 +286,38 @@ static const char *const _PyOpcode_OpName[263] = { [BEFORE_WITH] = "BEFORE_WITH", [END_ASYNC_FOR] = "END_ASYNC_FOR", [CLEANUP_THROW] = "CLEANUP_THROW", + [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", + [COMPARE_AND_BRANCH_FLOAT] = "COMPARE_AND_BRANCH_FLOAT", [COMPARE_AND_BRANCH_INT] = "COMPARE_AND_BRANCH_INT", [COMPARE_AND_BRANCH_STR] = "COMPARE_AND_BRANCH_STR", - [FOR_ITER_LIST] = "FOR_ITER_LIST", - [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", [STORE_SUBSCR] = "STORE_SUBSCR", [DELETE_SUBSCR] = "DELETE_SUBSCR", + [FOR_ITER_LIST] = "FOR_ITER_LIST", + [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", [FOR_ITER_RANGE] = "FOR_ITER_RANGE", [FOR_ITER_GEN] = "FOR_ITER_GEN", [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", - [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", - [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", [GET_ITER] = "GET_ITER", [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", - [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", + [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", - [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", - [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", + [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", + [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", [RETURN_GENERATOR] = "RETURN_GENERATOR", + [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", + [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", + [RETURN_VALUE] = "RETURN_VALUE", [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", + [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", - [RETURN_VALUE] = "RETURN_VALUE", [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", - [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", - [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", - [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [PREP_RERAISE_STAR] = "PREP_RERAISE_STAR", [POP_EXCEPT] = "POP_EXCEPT", [STORE_NAME] = "STORE_NAME", @@ -341,7 +343,7 @@ static const char *const _PyOpcode_OpName[263] = { [JUMP_FORWARD] = "JUMP_FORWARD", [JUMP_IF_FALSE_OR_POP] = "JUMP_IF_FALSE_OR_POP", [JUMP_IF_TRUE_OR_POP] = "JUMP_IF_TRUE_OR_POP", - [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", + [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -349,7 +351,7 @@ static const char *const _PyOpcode_OpName[263] = { [CONTAINS_OP] = "CONTAINS_OP", [RERAISE] = "RERAISE", [COPY] = "COPY", - [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", + [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [BINARY_OP] = "BINARY_OP", [SEND] = "SEND", [LOAD_FAST] = "LOAD_FAST", @@ -371,7 +373,7 @@ static const char *const _PyOpcode_OpName[263] = { [JUMP_BACKWARD] = "JUMP_BACKWARD", [COMPARE_AND_BRANCH] = "COMPARE_AND_BRANCH", [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", - [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", + [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -381,23 +383,23 @@ static const char *const _PyOpcode_OpName[263] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", - [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", - [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", + [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", + [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", + [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", + [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", - [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", - [BB_NEXT] = "BB_NEXT", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", + [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", + [BB_NEXT] = "BB_NEXT", [BINARY_OP_ADD_INT_TYPE_CHECK] = "BINARY_OP_ADD_INT_TYPE_CHECK", [BINARY_OP_ADD_INT_REST] = "BINARY_OP_ADD_INT_REST", - [168] = "<168>", - [169] = "<169>", [170] = "<170>", [CALL] = "CALL", [KW_NAMES] = "KW_NAMES", @@ -496,8 +498,6 @@ static const char *const _PyOpcode_OpName[263] = { #define EXTRA_CASES \ - case 168: \ - case 169: \ case 170: \ case 174: \ case 175: \ diff --git a/Include/opcode.h b/Include/opcode.h index 2b0c652e865331..bdd4f8b8e44d46 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -125,134 +125,138 @@ extern "C" { #define JUMP_NO_INTERRUPT 261 #define LOAD_METHOD 262 #define MAX_PSEUDO_OPCODE 262 -#define BINARY_OP_ADD_FLOAT 5 -#define BINARY_OP_ADD_INT 6 -#define BINARY_OP_ADD_UNICODE 7 -#define BINARY_OP_INPLACE_ADD_UNICODE 8 -#define BINARY_OP_MULTIPLY_FLOAT 10 -#define BINARY_OP_MULTIPLY_INT 13 -#define BINARY_OP_SUBTRACT_FLOAT 14 -#define BINARY_OP_SUBTRACT_INT 16 -#define BINARY_SUBSCR_DICT 17 -#define BINARY_SUBSCR_GETITEM 18 -#define BINARY_SUBSCR_LIST_INT 19 -#define BINARY_SUBSCR_TUPLE_INT 20 -#define CALL_PY_EXACT_ARGS 21 -#define CALL_PY_WITH_DEFAULTS 22 -#define CALL_BOUND_METHOD_EXACT_ARGS 23 -#define CALL_BUILTIN_CLASS 24 -#define CALL_BUILTIN_FAST_WITH_KEYWORDS 28 -#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 29 -#define CALL_NO_KW_BUILTIN_FAST 34 -#define CALL_NO_KW_BUILTIN_O 38 -#define CALL_NO_KW_ISINSTANCE 39 -#define CALL_NO_KW_LEN 40 -#define CALL_NO_KW_LIST_APPEND 41 -#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 42 -#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 43 -#define CALL_NO_KW_METHOD_DESCRIPTOR_O 44 -#define CALL_NO_KW_STR_1 45 -#define CALL_NO_KW_TUPLE_1 46 -#define CALL_NO_KW_TYPE_1 47 -#define COMPARE_AND_BRANCH_FLOAT 48 -#define COMPARE_AND_BRANCH_INT 56 -#define COMPARE_AND_BRANCH_STR 57 -#define FOR_ITER_LIST 58 -#define FOR_ITER_TUPLE 59 -#define FOR_ITER_RANGE 62 -#define FOR_ITER_GEN 63 -#define LOAD_ATTR_CLASS 64 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 65 -#define LOAD_ATTR_INSTANCE_VALUE 66 -#define LOAD_ATTR_MODULE 67 -#define LOAD_ATTR_PROPERTY 70 -#define LOAD_ATTR_SLOT 72 -#define LOAD_ATTR_WITH_HINT 73 -#define LOAD_ATTR_METHOD_LAZY_DICT 76 -#define LOAD_ATTR_METHOD_NO_DICT 77 -#define LOAD_ATTR_METHOD_WITH_VALUES 78 -#define LOAD_CONST__LOAD_FAST 79 -#define LOAD_FAST__LOAD_CONST 80 -#define LOAD_FAST__LOAD_FAST 81 -#define LOAD_GLOBAL_BUILTIN 82 -#define LOAD_GLOBAL_MODULE 84 -#define STORE_ATTR_INSTANCE_VALUE 86 -#define STORE_ATTR_SLOT 87 -#define STORE_ATTR_WITH_HINT 113 -#define STORE_FAST__LOAD_FAST 121 -#define STORE_FAST__STORE_FAST 143 -#define STORE_SUBSCR_DICT 153 -#define STORE_SUBSCR_LIST_INT 154 -#define UNPACK_SEQUENCE_LIST 158 -#define UNPACK_SEQUENCE_TUPLE 159 -#define UNPACK_SEQUENCE_TWO_TUPLE 160 +#define RESUME_QUICK 5 +#define JUMP_BACKWARD_QUICK 6 +#define BINARY_OP_ADD_FLOAT 7 +#define BINARY_OP_ADD_INT 8 +#define BINARY_OP_ADD_UNICODE 10 +#define BINARY_OP_INPLACE_ADD_UNICODE 13 +#define BINARY_OP_MULTIPLY_FLOAT 14 +#define BINARY_OP_MULTIPLY_INT 16 +#define BINARY_OP_SUBTRACT_FLOAT 17 +#define BINARY_OP_SUBTRACT_INT 18 +#define BINARY_SUBSCR_DICT 19 +#define BINARY_SUBSCR_GETITEM 20 +#define BINARY_SUBSCR_LIST_INT 21 +#define BINARY_SUBSCR_TUPLE_INT 22 +#define CALL_PY_EXACT_ARGS 23 +#define CALL_PY_WITH_DEFAULTS 24 +#define CALL_BOUND_METHOD_EXACT_ARGS 28 +#define CALL_BUILTIN_CLASS 29 +#define CALL_BUILTIN_FAST_WITH_KEYWORDS 34 +#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 38 +#define CALL_NO_KW_BUILTIN_FAST 39 +#define CALL_NO_KW_BUILTIN_O 40 +#define CALL_NO_KW_ISINSTANCE 41 +#define CALL_NO_KW_LEN 42 +#define CALL_NO_KW_LIST_APPEND 43 +#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 44 +#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 45 +#define CALL_NO_KW_METHOD_DESCRIPTOR_O 46 +#define CALL_NO_KW_STR_1 47 +#define CALL_NO_KW_TUPLE_1 48 +#define CALL_NO_KW_TYPE_1 56 +#define COMPARE_AND_BRANCH_FLOAT 57 +#define COMPARE_AND_BRANCH_INT 58 +#define COMPARE_AND_BRANCH_STR 59 +#define FOR_ITER_LIST 62 +#define FOR_ITER_TUPLE 63 +#define FOR_ITER_RANGE 64 +#define FOR_ITER_GEN 65 +#define LOAD_ATTR_CLASS 66 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 67 +#define LOAD_ATTR_INSTANCE_VALUE 70 +#define LOAD_ATTR_MODULE 72 +#define LOAD_ATTR_PROPERTY 73 +#define LOAD_ATTR_SLOT 76 +#define LOAD_ATTR_WITH_HINT 77 +#define LOAD_ATTR_METHOD_LAZY_DICT 78 +#define LOAD_ATTR_METHOD_NO_DICT 79 +#define LOAD_ATTR_METHOD_WITH_VALUES 80 +#define LOAD_CONST__LOAD_FAST 81 +#define LOAD_FAST__LOAD_CONST 82 +#define LOAD_FAST__LOAD_FAST 84 +#define LOAD_GLOBAL_BUILTIN 86 +#define LOAD_GLOBAL_MODULE 87 +#define STORE_ATTR_INSTANCE_VALUE 113 +#define STORE_ATTR_SLOT 121 +#define STORE_ATTR_WITH_HINT 143 +#define STORE_FAST__LOAD_FAST 153 +#define STORE_FAST__STORE_FAST 154 +#define STORE_SUBSCR_DICT 158 +#define STORE_SUBSCR_LIST_INT 159 +#define UNPACK_SEQUENCE_LIST 160 +#define UNPACK_SEQUENCE_TUPLE 161 +#define UNPACK_SEQUENCE_TWO_TUPLE 166 #define DO_TRACING 255 // Tier 2 interpreter ops -#define BINARY_OP_ADD_FLOAT 5 -#define BINARY_OP_ADD_INT 6 -#define BINARY_OP_ADD_UNICODE 7 -#define BINARY_OP_INPLACE_ADD_UNICODE 8 -#define BINARY_OP_MULTIPLY_FLOAT 10 -#define BINARY_OP_MULTIPLY_INT 13 -#define BINARY_OP_SUBTRACT_FLOAT 14 -#define BINARY_OP_SUBTRACT_INT 16 -#define BINARY_SUBSCR_DICT 17 -#define BINARY_SUBSCR_GETITEM 18 -#define BINARY_SUBSCR_LIST_INT 19 -#define BINARY_SUBSCR_TUPLE_INT 20 -#define CALL_PY_EXACT_ARGS 21 -#define CALL_PY_WITH_DEFAULTS 22 -#define CALL_BOUND_METHOD_EXACT_ARGS 23 -#define CALL_BUILTIN_CLASS 24 -#define CALL_BUILTIN_FAST_WITH_KEYWORDS 28 -#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 29 -#define CALL_NO_KW_BUILTIN_FAST 34 -#define CALL_NO_KW_BUILTIN_O 38 -#define CALL_NO_KW_ISINSTANCE 39 -#define CALL_NO_KW_LEN 40 -#define CALL_NO_KW_LIST_APPEND 41 -#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 42 -#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 43 -#define CALL_NO_KW_METHOD_DESCRIPTOR_O 44 -#define CALL_NO_KW_STR_1 45 -#define CALL_NO_KW_TUPLE_1 46 -#define CALL_NO_KW_TYPE_1 47 -#define COMPARE_AND_BRANCH_FLOAT 48 -#define COMPARE_AND_BRANCH_INT 56 -#define COMPARE_AND_BRANCH_STR 57 -#define FOR_ITER_LIST 58 -#define FOR_ITER_TUPLE 59 -#define FOR_ITER_RANGE 62 -#define FOR_ITER_GEN 63 -#define LOAD_ATTR_CLASS 64 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 65 -#define LOAD_ATTR_INSTANCE_VALUE 66 -#define LOAD_ATTR_MODULE 67 -#define LOAD_ATTR_PROPERTY 70 -#define LOAD_ATTR_SLOT 72 -#define LOAD_ATTR_WITH_HINT 73 -#define LOAD_ATTR_METHOD_LAZY_DICT 76 -#define LOAD_ATTR_METHOD_NO_DICT 77 -#define LOAD_ATTR_METHOD_WITH_VALUES 78 -#define LOAD_CONST__LOAD_FAST 79 -#define LOAD_FAST__LOAD_CONST 80 -#define LOAD_FAST__LOAD_FAST 81 -#define LOAD_GLOBAL_BUILTIN 82 -#define LOAD_GLOBAL_MODULE 84 -#define STORE_ATTR_INSTANCE_VALUE 86 -#define STORE_ATTR_SLOT 87 -#define STORE_ATTR_WITH_HINT 113 -#define STORE_FAST__LOAD_FAST 121 -#define STORE_FAST__STORE_FAST 143 -#define STORE_SUBSCR_DICT 153 -#define STORE_SUBSCR_LIST_INT 154 -#define UNPACK_SEQUENCE_LIST 158 -#define UNPACK_SEQUENCE_TUPLE 159 -#define UNPACK_SEQUENCE_TWO_TUPLE 160 +#define RESUME_QUICK 5 +#define JUMP_BACKWARD_QUICK 6 +#define BINARY_OP_ADD_FLOAT 7 +#define BINARY_OP_ADD_INT 8 +#define BINARY_OP_ADD_UNICODE 10 +#define BINARY_OP_INPLACE_ADD_UNICODE 13 +#define BINARY_OP_MULTIPLY_FLOAT 14 +#define BINARY_OP_MULTIPLY_INT 16 +#define BINARY_OP_SUBTRACT_FLOAT 17 +#define BINARY_OP_SUBTRACT_INT 18 +#define BINARY_SUBSCR_DICT 19 +#define BINARY_SUBSCR_GETITEM 20 +#define BINARY_SUBSCR_LIST_INT 21 +#define BINARY_SUBSCR_TUPLE_INT 22 +#define CALL_PY_EXACT_ARGS 23 +#define CALL_PY_WITH_DEFAULTS 24 +#define CALL_BOUND_METHOD_EXACT_ARGS 28 +#define CALL_BUILTIN_CLASS 29 +#define CALL_BUILTIN_FAST_WITH_KEYWORDS 34 +#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 38 +#define CALL_NO_KW_BUILTIN_FAST 39 +#define CALL_NO_KW_BUILTIN_O 40 +#define CALL_NO_KW_ISINSTANCE 41 +#define CALL_NO_KW_LEN 42 +#define CALL_NO_KW_LIST_APPEND 43 +#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 44 +#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 45 +#define CALL_NO_KW_METHOD_DESCRIPTOR_O 46 +#define CALL_NO_KW_STR_1 47 +#define CALL_NO_KW_TUPLE_1 48 +#define CALL_NO_KW_TYPE_1 56 +#define COMPARE_AND_BRANCH_FLOAT 57 +#define COMPARE_AND_BRANCH_INT 58 +#define COMPARE_AND_BRANCH_STR 59 +#define FOR_ITER_LIST 62 +#define FOR_ITER_TUPLE 63 +#define FOR_ITER_RANGE 64 +#define FOR_ITER_GEN 65 +#define LOAD_ATTR_CLASS 66 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 67 +#define LOAD_ATTR_INSTANCE_VALUE 70 +#define LOAD_ATTR_MODULE 72 +#define LOAD_ATTR_PROPERTY 73 +#define LOAD_ATTR_SLOT 76 +#define LOAD_ATTR_WITH_HINT 77 +#define LOAD_ATTR_METHOD_LAZY_DICT 78 +#define LOAD_ATTR_METHOD_NO_DICT 79 +#define LOAD_ATTR_METHOD_WITH_VALUES 80 +#define LOAD_CONST__LOAD_FAST 81 +#define LOAD_FAST__LOAD_CONST 82 +#define LOAD_FAST__LOAD_FAST 84 +#define LOAD_GLOBAL_BUILTIN 86 +#define LOAD_GLOBAL_MODULE 87 +#define STORE_ATTR_INSTANCE_VALUE 113 +#define STORE_ATTR_SLOT 121 +#define STORE_ATTR_WITH_HINT 143 +#define STORE_FAST__LOAD_FAST 153 +#define STORE_FAST__STORE_FAST 154 +#define STORE_SUBSCR_DICT 158 +#define STORE_SUBSCR_LIST_INT 159 +#define UNPACK_SEQUENCE_LIST 160 +#define UNPACK_SEQUENCE_TUPLE 161 +#define UNPACK_SEQUENCE_TWO_TUPLE 166 #define DO_TRACING 255 -#define BB_NEXT 161 -#define BINARY_OP_ADD_INT_TYPE_CHECK 166 -#define BINARY_OP_ADD_INT_REST 167 +#define BB_NEXT 167 +#define BINARY_OP_ADD_INT_TYPE_CHECK 168 +#define BINARY_OP_ADD_INT_REST 169 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/opcode.py b/Lib/opcode.py index 292eae330c2095..08c73abd28848f 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -279,6 +279,12 @@ def pseudo_op(name, op, real_ops): ] _specializations = { + "RESUME": [ + "RESUME_QUICK", + ], + "JUMP_BACKWARD": [ + "JUMP_BACKWARD_QUICK", + ], "BINARY_OP": [ "BINARY_OP_ADD_FLOAT", "BINARY_OP_ADD_INT", diff --git a/Objects/codeobject.c b/Objects/codeobject.c index ab31b6582cdaae..ba3c7bdce5a772 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -409,6 +409,9 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con) co->_co_linearray_entry_size = 0; co->_co_linearray = NULL; + co->_tier2_warmup = -64; + co->_bb_next = NULL; + co->_bb_space = NULL; memcpy(_PyCode_CODE(co), PyBytes_AS_STRING(con->code), PyBytes_GET_SIZE(con->code)); int entry_point = 0; @@ -1705,6 +1708,16 @@ code_dealloc(PyCodeObject *co) if (co->_co_linearray) { PyMem_Free(co->_co_linearray); } + co->_bb_next = NULL; + if (co->_bb_space != NULL) { + // Traverse the linked list + for (_PyTier2BBSpace *curr = co->_bb_space; curr != NULL;) { + _PyTier2BBSpace *prev = curr; + curr = curr->next; + PyMem_Free(prev); + } + co->_bb_space = NULL; + } PyObject_Free(co); } @@ -2282,6 +2295,16 @@ _PyStaticCode_Fini(PyCodeObject *co) PyMem_Free(co->_co_cached); co->_co_cached = NULL; } + co->_bb_next = NULL; + if (co->_bb_space != NULL) { + // Traverse the linked list + for (_PyTier2BBSpace *curr = co->_bb_space; curr != NULL;) { + _PyTier2BBSpace *prev = curr; + curr = curr->next; + PyMem_Free(prev); + } + co->_bb_space = NULL; + } co->co_extra = NULL; if (co->co_weakreflist != NULL) { PyObject_ClearWeakRefs((PyObject *)co); diff --git a/Objects/genobject.c b/Objects/genobject.c index 35246653c45348..b74073c39314ef 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -336,7 +336,8 @@ _PyGen_yf(PyGenObject *gen) return NULL; } _Py_CODEUNIT next = frame->prev_instr[1]; - if (_Py_OPCODE(next) != RESUME || _Py_OPARG(next) < 2) + if ((_Py_OPCODE(next) != RESUME && _Py_OPCODE(next) != RESUME_QUICK) || + _Py_OPARG(next) < 2) { /* Not in a yield from */ return NULL; @@ -372,7 +373,7 @@ gen_close(PyGenObject *gen, PyObject *args) /* It is possible for the previous instruction to not be a * YIELD_VALUE if the debugger has changed the lineno. */ if (err == 0 && frame->prev_instr->opcode == YIELD_VALUE) { - assert(frame->prev_instr[1].opcode == RESUME); + assert(frame->prev_instr[1].opcode == RESUME || frame->prev_instr[1].opcode == RESUME_QUICK); int exception_handler_depth = frame->prev_instr->oparg; assert(exception_handler_depth > 0); /* We can safely ignore the outermost try block diff --git a/PCbuild/_freeze_module.vcxproj b/PCbuild/_freeze_module.vcxproj index 4f39756019e692..5271008885aa34 100644 --- a/PCbuild/_freeze_module.vcxproj +++ b/PCbuild/_freeze_module.vcxproj @@ -229,6 +229,7 @@ + diff --git a/PCbuild/_freeze_module.vcxproj.filters b/PCbuild/_freeze_module.vcxproj.filters index 7d7c4587b9a3f3..1f2ae059d6fd1a 100644 --- a/PCbuild/_freeze_module.vcxproj.filters +++ b/PCbuild/_freeze_module.vcxproj.filters @@ -343,6 +343,9 @@ Source Files + + Source Files + Source Files diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 791562710efc54..5a3723f8043e33 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -546,6 +546,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index fe5bc990fec207..afa37380aebda4 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -1223,6 +1223,9 @@ Python + + Python + Python diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 5fdf0b137e638a..491becdad860fd 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -88,6 +88,11 @@ dummy_func( } inst(RESUME, (--)) { + _PyCode_Tier2Warmup(frame, &next_instr); + GO_TO_INSTRUCTION(RESUME_QUICK); + } + + inst(RESUME_QUICK, (--)) { assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { @@ -1949,6 +1954,11 @@ dummy_func( } inst(JUMP_BACKWARD, (--)) { + _PyCode_Tier2Warmup(frame, &next_instr); + GO_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); + } + + inst(JUMP_BACKWARD_QUICK, (--)) { assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); CHECK_EVAL_BREAKER(); diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index d7a8f0beeec872..0bac6c08a4f73d 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -140,7 +140,9 @@ GETITEM(PyObject *v, Py_ssize_t i) { /* Code access macros */ /* The integer overflow is checked by an assertion below. */ -#define INSTR_OFFSET() ((int)(next_instr - _PyCode_CODE(frame->f_code))) +// TODO change this calculation when interpreter is bb aware. +#define INSTR_OFFSET() ((int)(next_instr - \ + (frame->f_code->_bb_next == NULL ? _PyCode_CODE(frame->f_code) : frame->f_code->_bb_next->u_code))) #define NEXTOPARG() do { \ _Py_CODEUNIT word = *next_instr; \ opcode = _Py_OPCODE(word); \ diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index da28e41dbc7f70..e269f3bb35feb7 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -23,6 +23,12 @@ } TARGET(RESUME) { + _PyCode_Tier2Warmup(frame, &next_instr); + GO_TO_INSTRUCTION(RESUME_QUICK); + } + + TARGET(RESUME_QUICK) { + PREDICTED(RESUME_QUICK); assert(tstate->cframe == &cframe); assert(frame == cframe.current_frame); if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) { @@ -2360,7 +2366,16 @@ TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - assert(oparg < INSTR_OFFSET()); + _PyCode_Tier2Warmup(frame, &next_instr); + GO_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); + } + + TARGET(JUMP_BACKWARD_QUICK) { + PREDICTED(JUMP_BACKWARD_QUICK); + if (oparg >= INSTR_OFFSET()) { + fprintf(stderr, "%ld, %ld\n", oparg, INSTR_OFFSET()); + } + //assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); CHECK_EVAL_BREAKER(); DISPATCH(); diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index f1c3f3e0c4ee17..98c27d3b27e25c 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -4,17 +4,19 @@ static void *opcode_targets[256] = { &&TARGET_PUSH_NULL, &&TARGET_INTERPRETER_EXIT, &&TARGET_END_FOR, + &&TARGET_RESUME_QUICK, + &&TARGET_JUMP_BACKWARD_QUICK, &&TARGET_BINARY_OP_ADD_FLOAT, &&TARGET_BINARY_OP_ADD_INT, - &&TARGET_BINARY_OP_ADD_UNICODE, - &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, &&TARGET_NOP, - &&TARGET_BINARY_OP_MULTIPLY_FLOAT, + &&TARGET_BINARY_OP_ADD_UNICODE, &&TARGET_UNARY_NEGATIVE, &&TARGET_UNARY_NOT, + &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, + &&TARGET_BINARY_OP_MULTIPLY_FLOAT, + &&TARGET_UNARY_INVERT, &&TARGET_BINARY_OP_MULTIPLY_INT, &&TARGET_BINARY_OP_SUBTRACT_FLOAT, - &&TARGET_UNARY_INVERT, &&TARGET_BINARY_OP_SUBTRACT_INT, &&TARGET_BINARY_SUBSCR_DICT, &&TARGET_BINARY_SUBSCR_GETITEM, @@ -22,21 +24,21 @@ static void *opcode_targets[256] = { &&TARGET_BINARY_SUBSCR_TUPLE_INT, &&TARGET_CALL_PY_EXACT_ARGS, &&TARGET_CALL_PY_WITH_DEFAULTS, - &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, - &&TARGET_CALL_BUILTIN_CLASS, &&TARGET_BINARY_SUBSCR, &&TARGET_BINARY_SLICE, &&TARGET_STORE_SLICE, - &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, - &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, + &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, + &&TARGET_CALL_BUILTIN_CLASS, &&TARGET_GET_LEN, &&TARGET_MATCH_MAPPING, &&TARGET_MATCH_SEQUENCE, &&TARGET_MATCH_KEYS, - &&TARGET_CALL_NO_KW_BUILTIN_FAST, + &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, &&TARGET_PUSH_EXC_INFO, &&TARGET_CHECK_EXC_MATCH, &&TARGET_CHECK_EG_MATCH, + &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, + &&TARGET_CALL_NO_KW_BUILTIN_FAST, &&TARGET_CALL_NO_KW_BUILTIN_O, &&TARGET_CALL_NO_KW_ISINSTANCE, &&TARGET_CALL_NO_KW_LEN, @@ -46,8 +48,6 @@ static void *opcode_targets[256] = { &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, &&TARGET_CALL_NO_KW_STR_1, &&TARGET_CALL_NO_KW_TUPLE_1, - &&TARGET_CALL_NO_KW_TYPE_1, - &&TARGET_COMPARE_AND_BRANCH_FLOAT, &&TARGET_WITH_EXCEPT_START, &&TARGET_GET_AITER, &&TARGET_GET_ANEXT, @@ -55,38 +55,38 @@ static void *opcode_targets[256] = { &&TARGET_BEFORE_WITH, &&TARGET_END_ASYNC_FOR, &&TARGET_CLEANUP_THROW, + &&TARGET_CALL_NO_KW_TYPE_1, + &&TARGET_COMPARE_AND_BRANCH_FLOAT, &&TARGET_COMPARE_AND_BRANCH_INT, &&TARGET_COMPARE_AND_BRANCH_STR, - &&TARGET_FOR_ITER_LIST, - &&TARGET_FOR_ITER_TUPLE, &&TARGET_STORE_SUBSCR, &&TARGET_DELETE_SUBSCR, + &&TARGET_FOR_ITER_LIST, + &&TARGET_FOR_ITER_TUPLE, &&TARGET_FOR_ITER_RANGE, &&TARGET_FOR_ITER_GEN, &&TARGET_LOAD_ATTR_CLASS, &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, - &&TARGET_LOAD_ATTR_INSTANCE_VALUE, - &&TARGET_LOAD_ATTR_MODULE, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, - &&TARGET_LOAD_ATTR_PROPERTY, + &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_BUILD_CLASS, - &&TARGET_LOAD_ATTR_SLOT, - &&TARGET_LOAD_ATTR_WITH_HINT, + &&TARGET_LOAD_ATTR_MODULE, + &&TARGET_LOAD_ATTR_PROPERTY, &&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_RETURN_GENERATOR, + &&TARGET_LOAD_ATTR_SLOT, + &&TARGET_LOAD_ATTR_WITH_HINT, &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, &&TARGET_LOAD_ATTR_METHOD_NO_DICT, &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_LOAD_FAST__LOAD_CONST, + &&TARGET_RETURN_VALUE, &&TARGET_LOAD_FAST__LOAD_FAST, + &&TARGET_SETUP_ANNOTATIONS, &&TARGET_LOAD_GLOBAL_BUILTIN, - &&TARGET_RETURN_VALUE, &&TARGET_LOAD_GLOBAL_MODULE, - &&TARGET_SETUP_ANNOTATIONS, - &&TARGET_STORE_ATTR_INSTANCE_VALUE, - &&TARGET_STORE_ATTR_SLOT, &&TARGET_PREP_RERAISE_STAR, &&TARGET_POP_EXCEPT, &&TARGET_STORE_NAME, @@ -112,7 +112,7 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_FORWARD, &&TARGET_JUMP_IF_FALSE_OR_POP, &&TARGET_JUMP_IF_TRUE_OR_POP, - &&TARGET_STORE_ATTR_WITH_HINT, + &&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -120,7 +120,7 @@ static void *opcode_targets[256] = { &&TARGET_CONTAINS_OP, &&TARGET_RERAISE, &&TARGET_COPY, - &&TARGET_STORE_FAST__LOAD_FAST, + &&TARGET_STORE_ATTR_SLOT, &&TARGET_BINARY_OP, &&TARGET_SEND, &&TARGET_LOAD_FAST, @@ -142,7 +142,7 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_BACKWARD, &&TARGET_COMPARE_AND_BRANCH, &&TARGET_CALL_FUNCTION_EX, - &&TARGET_STORE_FAST__STORE_FAST, + &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,20 +152,20 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, - &&TARGET_STORE_SUBSCR_DICT, - &&TARGET_STORE_SUBSCR_LIST_INT, + &&TARGET_STORE_FAST__LOAD_FAST, + &&TARGET_STORE_FAST__STORE_FAST, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, + &&TARGET_STORE_SUBSCR_DICT, + &&TARGET_STORE_SUBSCR_LIST_INT, &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_UNPACK_SEQUENCE_TUPLE, - &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, - &&_unknown_opcode, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, - &&_unknown_opcode, + &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, diff --git a/Python/tier2.c b/Python/tier2.c new file mode 100644 index 00000000000000..f3ece7f851a262 --- /dev/null +++ b/Python/tier2.c @@ -0,0 +1,62 @@ +#include "Python.h" +#include "pycore_code.h" +#include "pycore_frame.h" + +#include "opcode.h" + +static int +_PyCode_Tier2Initialize(_PyInterpreterFrame *, _Py_CODEUNIT **); + +// Tier 2 warmup counter +void +_PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT **next_instr) +{ + PyCodeObject *code = frame->f_code; + if (code->_tier2_warmup != 0) { + code->_tier2_warmup++; + if (code->_tier2_warmup == 0) { + // If it fails, due to lack of memory or whatever, + // just fall back to the tier 1 interpreter. + if (_PyCode_Tier2Initialize(frame, next_instr) < 0) { + PyErr_Clear(); + } + } + } +} + +static int +_PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT **next_instr) +{ + PyCodeObject *co = frame->f_code; + if (co->_bb_space != NULL) { + return 0; + } + // 1. Initialize basic blocks space. + // 2. Copy over instructions to basic blocks. + // (For now, just have one basic block = on code object) + // @TODO split up code object into basic blocks. + // 3. Set the instruction pointer to correct one. + fprintf(stderr, "INITIALIZING %ld\n", Py_SIZE(co)); + _PyTier2BBSpace *bb_space = PyMem_Malloc(Py_SIZE(co) * sizeof(_Py_CODEUNIT) * 2); + if (bb_space == NULL) { + PyErr_NoMemory(); + return -1; + } + bb_space->next = NULL; + bb_space->water_level = 0; + co->_bb_space = bb_space; + + _PyTier2BB *bb_ptr = (_PyTier2BB *)bb_space->bbs; + bb_ptr->tier1_start = _PyCode_CODE(co); + memcpy(bb_ptr->u_code, _PyCode_CODE(co), Py_SIZE(co) * sizeof(_Py_CODEUNIT)); + + co->_bb_next = bb_ptr; + // test to see we are working + _py_set_opcode(bb_ptr->u_code, CACHE); + + // Set the instruction pointer to the next one in the bb + frame->prev_instr = bb_ptr->u_code + (frame->prev_instr - _PyCode_CODE(co)); + *next_instr = frame->prev_instr + 1; + + return 0; +} diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py index 511b26a5ce3dc7..7718bc95722138 100644 --- a/Tools/build/deepfreeze.py +++ b/Tools/build/deepfreeze.py @@ -277,6 +277,9 @@ def generate_code(self, name: str, code: types.CodeType) -> str: self.write(f".co_linetable = {co_linetable},") self.write(f"._co_cached = NULL,") self.write("._co_linearray = NULL,") + self.write("._tier2_warmup = -64,") + self.write("._bb_next = NULL,") + self.write("._bb_space = NULL,") self.write(f".co_code_adaptive = {co_code_adaptive},") for i, op in enumerate(code.co_code[::2]): if op == RESUME: From 9b2e69a73c6d5db67c0e8a55efbaa79b72e9d233 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sun, 29 Jan 2023 21:56:16 +0800 Subject: [PATCH 011/280] [partially not working] rewrite resumes and jumps --- Include/cpython/code.h | 1 + Include/internal/pycore_code.h | 2 +- Python/bytecodes.c | 7 +++-- Python/generated_cases.c.h | 8 ++--- Python/tier2.c | 56 +++++++++++++++++++++++----------- 5 files changed, 49 insertions(+), 25 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index e0c173411594d4..01eed3380a4929 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -47,6 +47,7 @@ typedef struct { typedef struct _PyTier2BB { // Stores the start pointer in the tier 1 bytecode. // So that when we exit the trace we can calculate where to return. + struct _PyTier2BB *bb_next; _Py_CODEUNIT *tier1_start; _Py_CODEUNIT u_code[1]; } _PyTier2BB; diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 090353cac17d6a..392ea9cf83055a 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -240,7 +240,7 @@ extern void _PyStaticCode_Fini(PyCodeObject *co); extern int _PyStaticCode_Init(PyCodeObject *co); /* Tier 2 interpreter */ -extern void _PyCode_Tier2Warmup(struct _PyInterpreterFrame *, _Py_CODEUNIT **); +extern _Py_CODEUNIT *_PyCode_Tier2Warmup(struct _PyInterpreterFrame *, _Py_CODEUNIT *); #ifdef Py_STATS diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 491becdad860fd..473c9a6f8c814a 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -88,7 +88,7 @@ dummy_func( } inst(RESUME, (--)) { - _PyCode_Tier2Warmup(frame, &next_instr); + next_instr = _PyCode_Tier2Warmup(frame, next_instr); GO_TO_INSTRUCTION(RESUME_QUICK); } @@ -1954,11 +1954,14 @@ dummy_func( } inst(JUMP_BACKWARD, (--)) { - _PyCode_Tier2Warmup(frame, &next_instr); + next_instr = _PyCode_Tier2Warmup(frame, next_instr); GO_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); } inst(JUMP_BACKWARD_QUICK, (--)) { + if (oparg >= INSTR_OFFSET()) { + fprintf(stderr, "%ld, %p, %p, %p\n", oparg, next_instr, _PyCode_CODE(frame->f_code), frame->f_code->_bb_next->u_code); + } assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); CHECK_EVAL_BREAKER(); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index e269f3bb35feb7..1a4aadb96b40d6 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -23,7 +23,7 @@ } TARGET(RESUME) { - _PyCode_Tier2Warmup(frame, &next_instr); + next_instr = _PyCode_Tier2Warmup(frame, next_instr); GO_TO_INSTRUCTION(RESUME_QUICK); } @@ -2366,16 +2366,16 @@ TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - _PyCode_Tier2Warmup(frame, &next_instr); + next_instr = _PyCode_Tier2Warmup(frame, next_instr); GO_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); } TARGET(JUMP_BACKWARD_QUICK) { PREDICTED(JUMP_BACKWARD_QUICK); if (oparg >= INSTR_OFFSET()) { - fprintf(stderr, "%ld, %ld\n", oparg, INSTR_OFFSET()); + fprintf(stderr, "%ld, %p, %p, %p IS_NULL %d\n", oparg, next_instr, _PyCode_CODE(frame->f_code), frame->f_code->_bb_next->u_code, frame->f_code->_bb_next == NULL); } - //assert(oparg < INSTR_OFFSET()); + assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); CHECK_EVAL_BREAKER(); DISPATCH(); diff --git a/Python/tier2.c b/Python/tier2.c index f3ece7f851a262..25c5afe855f922 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -4,12 +4,12 @@ #include "opcode.h" -static int -_PyCode_Tier2Initialize(_PyInterpreterFrame *, _Py_CODEUNIT **); +static _Py_CODEUNIT * +_PyCode_Tier2Initialize(_PyInterpreterFrame *, _Py_CODEUNIT *); // Tier 2 warmup counter -void -_PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT **next_instr) +_Py_CODEUNIT * +_PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) { PyCodeObject *code = frame->f_code; if (code->_tier2_warmup != 0) { @@ -17,30 +17,35 @@ _PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT **next_instr) if (code->_tier2_warmup == 0) { // If it fails, due to lack of memory or whatever, // just fall back to the tier 1 interpreter. - if (_PyCode_Tier2Initialize(frame, next_instr) < 0) { + _Py_CODEUNIT *next = _PyCode_Tier2Initialize(frame, next_instr); + if (next == NULL) { PyErr_Clear(); } + else { + return next; + } } } + return next_instr; } -static int -_PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT **next_instr) +static _Py_CODEUNIT * +_PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) { + int curr = _Py_OPCODE(*(next_instr - 1)); + assert(curr == RESUME || curr == JUMP_BACKWARD); PyCodeObject *co = frame->f_code; - if (co->_bb_space != NULL) { - return 0; - } + assert(co->_bb_space == NULL); // 1. Initialize basic blocks space. // 2. Copy over instructions to basic blocks. // (For now, just have one basic block = on code object) // @TODO split up code object into basic blocks. // 3. Set the instruction pointer to correct one. fprintf(stderr, "INITIALIZING %ld\n", Py_SIZE(co)); - _PyTier2BBSpace *bb_space = PyMem_Malloc(Py_SIZE(co) * sizeof(_Py_CODEUNIT) * 2); + _PyTier2BBSpace *bb_space = PyMem_Malloc((sizeof(_PyTier2BB) + Py_SIZE(co) * sizeof(_Py_CODEUNIT)) * 2); if (bb_space == NULL) { PyErr_NoMemory(); - return -1; + return NULL; } bb_space->next = NULL; bb_space->water_level = 0; @@ -49,14 +54,29 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT **next_instr) _PyTier2BB *bb_ptr = (_PyTier2BB *)bb_space->bbs; bb_ptr->tier1_start = _PyCode_CODE(co); memcpy(bb_ptr->u_code, _PyCode_CODE(co), Py_SIZE(co) * sizeof(_Py_CODEUNIT)); + // Remove all the RESUME and JUMP_BACKWARDS instructions + for (Py_ssize_t i = 0; i < Py_SIZE(co); i++) { + _Py_CODEUNIT instr = bb_ptr->u_code[i]; + switch (_Py_OPCODE(instr)) { + case RESUME: + _py_set_opcode(&(bb_ptr->u_code[i]), RESUME_QUICK); + break; + case JUMP_BACKWARD: + _py_set_opcode(&(bb_ptr->u_code[i]), JUMP_BACKWARD); + break; + } + + } + co->_bb_next = bb_ptr; - // test to see we are working - _py_set_opcode(bb_ptr->u_code, CACHE); - // Set the instruction pointer to the next one in the bb - frame->prev_instr = bb_ptr->u_code + (frame->prev_instr - _PyCode_CODE(co)); - *next_instr = frame->prev_instr + 1; - return 0; + // Set the instruction pointer to the next one in the bb + Py_ssize_t offset_from_start = (frame->prev_instr - _PyCode_CODE(co)); + assert(offset_from_start >= -1); + frame->prev_instr = bb_ptr->u_code + offset_from_start; + // test to see we are working + // _py_set_opcode(next_instr, CACHE); + return bb_ptr->u_code + (next_instr - _PyCode_CODE(co)); } From 319c18938a70bfb15d9aa4f69b25fd0e153bc6c4 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 30 Jan 2023 02:41:55 +0800 Subject: [PATCH 012/280] Use first_instr --- Include/cpython/code.h | 1 + Include/internal/pycore_frame.h | 3 +-- Include/internal/pycore_opcode_macro_to_micro.h | 2 ++ Lib/importlib/_bootstrap_external.py | 2 +- Objects/codeobject.c | 4 ++++ Python/bytecodes.c | 10 +++++++--- Python/ceval_macros.h | 3 +-- Python/generated_cases.c.h | 11 ++++++++--- Python/tier2.c | 14 +++++--------- Tools/build/deepfreeze.py | 1 + 10 files changed, 31 insertions(+), 20 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 01eed3380a4929..594dfbc7eb7213 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -119,6 +119,7 @@ typedef struct _PyTier2BBSpace { _PyCoCached *_co_cached; /* cached co_* attributes */ \ int _co_firsttraceable; /* index of first traceable instruction */ \ char *_co_linearray; /* array of line offsets */ \ + _Py_CODEUNIT *_first_instr; /* points to first tier 1/tier 2 instruction */ \ int _tier2_warmup; /* warmup counter for tier 2 */ \ _PyTier2BB *_bb_next; /* the tier 2 basic block to execute (if any) */ \ _PyTier2BBSpace *_bb_space; /* linked list storing basic blocks */ \ diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 695fc94cc956a9..63fb9b2d26fca5 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -69,8 +69,7 @@ typedef struct _PyInterpreterFrame { } _PyInterpreterFrame; #define _PyInterpreterFrame_LASTI(IF) \ - ((int)((IF)->prev_instr - \ - ((IF)->f_code->_bb_next == NULL ? _PyCode_CODE((IF)->f_code) : (IF)->f_code->_bb_next->u_code))) + ((int)((IF)->prev_instr - (IF)->f_code->_first_instr)) static inline PyObject **_PyFrame_Stackbase(_PyInterpreterFrame *f) { return f->localsplus + f->f_code->co_nlocalsplus; diff --git a/Include/internal/pycore_opcode_macro_to_micro.h b/Include/internal/pycore_opcode_macro_to_micro.h index ab2cd8b54eb368..13d681be4afa83 100644 --- a/Include/internal/pycore_opcode_macro_to_micro.h +++ b/Include/internal/pycore_opcode_macro_to_micro.h @@ -16,6 +16,7 @@ extern "C" { extern const int _Py_MacroOpUOpCount[] = { [NOP] = 1, [RESUME] = 1, +[RESUME_QUICK] = 1, [LOAD_CLOSURE] = 1, [LOAD_FAST_CHECK] = 1, [LOAD_FAST] = 1, @@ -123,6 +124,7 @@ extern const int _Py_MacroOpUOpCount[] = { [IMPORT_FROM] = 1, [JUMP_FORWARD] = 1, [JUMP_BACKWARD] = 1, +[JUMP_BACKWARD_QUICK] = 1, [POP_JUMP_IF_FALSE] = 1, [POP_JUMP_IF_TRUE] = 1, [POP_JUMP_IF_NOT_NONE] = 1, diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index e760fbb15759d4..ebe1ef832289ac 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -443,7 +443,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3517).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3519).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Objects/codeobject.c b/Objects/codeobject.c index ba3c7bdce5a772..cfc07fc98b8ba4 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -409,6 +409,7 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con) co->_co_linearray_entry_size = 0; co->_co_linearray = NULL; + co->_first_instr = _PyCode_CODE(co); co->_tier2_warmup = -64; co->_bb_next = NULL; co->_bb_space = NULL; @@ -1708,6 +1709,7 @@ code_dealloc(PyCodeObject *co) if (co->_co_linearray) { PyMem_Free(co->_co_linearray); } + co->_first_instr = NULL; co->_bb_next = NULL; if (co->_bb_space != NULL) { // Traverse the linked list @@ -2295,6 +2297,7 @@ _PyStaticCode_Fini(PyCodeObject *co) PyMem_Free(co->_co_cached); co->_co_cached = NULL; } + co->_first_instr = NULL; co->_bb_next = NULL; if (co->_bb_space != NULL) { // Traverse the linked list @@ -2319,6 +2322,7 @@ _PyStaticCode_Fini(PyCodeObject *co) int _PyStaticCode_Init(PyCodeObject *co) { + co->_first_instr = _PyCode_CODE(co); int res = intern_strings(co->co_names); if (res < 0) { return -1; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 473c9a6f8c814a..e0f18670358cc8 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -88,7 +88,9 @@ dummy_func( } inst(RESUME, (--)) { - next_instr = _PyCode_Tier2Warmup(frame, next_instr); + if (cframe.use_tracing == 0) { + next_instr = _PyCode_Tier2Warmup(frame, next_instr); + } GO_TO_INSTRUCTION(RESUME_QUICK); } @@ -1954,13 +1956,15 @@ dummy_func( } inst(JUMP_BACKWARD, (--)) { - next_instr = _PyCode_Tier2Warmup(frame, next_instr); + if (cframe.use_tracing == 0) { + next_instr = _PyCode_Tier2Warmup(frame, next_instr); + } GO_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); } inst(JUMP_BACKWARD_QUICK, (--)) { if (oparg >= INSTR_OFFSET()) { - fprintf(stderr, "%ld, %p, %p, %p\n", oparg, next_instr, _PyCode_CODE(frame->f_code), frame->f_code->_bb_next->u_code); + fprintf(stderr, "%ld, %p, %p, %p, %p, %p\n", oparg, next_instr, _PyCode_CODE(frame->f_code), frame->f_code->_bb_next->u_code, frame->f_code->_first_instr, frame->prev_instr); } assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 0bac6c08a4f73d..255409348ee74a 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -141,8 +141,7 @@ GETITEM(PyObject *v, Py_ssize_t i) { /* The integer overflow is checked by an assertion below. */ // TODO change this calculation when interpreter is bb aware. -#define INSTR_OFFSET() ((int)(next_instr - \ - (frame->f_code->_bb_next == NULL ? _PyCode_CODE(frame->f_code) : frame->f_code->_bb_next->u_code))) +#define INSTR_OFFSET() ((int)(next_instr - frame->f_code->_first_instr)) #define NEXTOPARG() do { \ _Py_CODEUNIT word = *next_instr; \ opcode = _Py_OPCODE(word); \ diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 1a4aadb96b40d6..c9e79c5f846e64 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -23,7 +23,9 @@ } TARGET(RESUME) { - next_instr = _PyCode_Tier2Warmup(frame, next_instr); + if (cframe.use_tracing == 0) { + next_instr = _PyCode_Tier2Warmup(frame, next_instr); + } GO_TO_INSTRUCTION(RESUME_QUICK); } @@ -2366,14 +2368,17 @@ TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - next_instr = _PyCode_Tier2Warmup(frame, next_instr); + if (cframe.use_tracing == 0) { + next_instr = _PyCode_Tier2Warmup(frame, next_instr); + } GO_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); } TARGET(JUMP_BACKWARD_QUICK) { PREDICTED(JUMP_BACKWARD_QUICK); if (oparg >= INSTR_OFFSET()) { - fprintf(stderr, "%ld, %p, %p, %p IS_NULL %d\n", oparg, next_instr, _PyCode_CODE(frame->f_code), frame->f_code->_bb_next->u_code, frame->f_code->_bb_next == NULL); + fprintf(stderr, "%ld, %p, %p, %p, %p, %p\n", oparg, next_instr, _PyCode_CODE(frame->f_code), frame->f_code->_bb_next->u_code, frame->f_code->_first_instr, frame->prev_instr); + } assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); diff --git a/Python/tier2.c b/Python/tier2.c index 25c5afe855f922..ce1dbad39c6866 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -18,10 +18,7 @@ _PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) // If it fails, due to lack of memory or whatever, // just fall back to the tier 1 interpreter. _Py_CODEUNIT *next = _PyCode_Tier2Initialize(frame, next_instr); - if (next == NULL) { - PyErr_Clear(); - } - else { + if (next != NULL) { return next; } } @@ -42,18 +39,17 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) // @TODO split up code object into basic blocks. // 3. Set the instruction pointer to correct one. fprintf(stderr, "INITIALIZING %ld\n", Py_SIZE(co)); - _PyTier2BBSpace *bb_space = PyMem_Malloc((sizeof(_PyTier2BB) + Py_SIZE(co) * sizeof(_Py_CODEUNIT)) * 2); + _PyTier2BBSpace *bb_space = PyMem_Malloc((sizeof(_PyTier2BB) + _PyCode_NBYTES(co)) * 2); if (bb_space == NULL) { - PyErr_NoMemory(); return NULL; } bb_space->next = NULL; bb_space->water_level = 0; co->_bb_space = bb_space; - _PyTier2BB *bb_ptr = (_PyTier2BB *)bb_space->bbs; + _PyTier2BB *bb_ptr = bb_space->bbs; bb_ptr->tier1_start = _PyCode_CODE(co); - memcpy(bb_ptr->u_code, _PyCode_CODE(co), Py_SIZE(co) * sizeof(_Py_CODEUNIT)); + memcpy(bb_ptr->u_code, _PyCode_CODE(co), _PyCode_NBYTES(co)); // Remove all the RESUME and JUMP_BACKWARDS instructions for (Py_ssize_t i = 0; i < Py_SIZE(co); i++) { _Py_CODEUNIT instr = bb_ptr->u_code[i]; @@ -70,7 +66,7 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) co->_bb_next = bb_ptr; - + co->_first_instr = bb_ptr->u_code; // Set the instruction pointer to the next one in the bb Py_ssize_t offset_from_start = (frame->prev_instr - _PyCode_CODE(co)); diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py index 7718bc95722138..81e64516ecff3a 100644 --- a/Tools/build/deepfreeze.py +++ b/Tools/build/deepfreeze.py @@ -277,6 +277,7 @@ def generate_code(self, name: str, code: types.CodeType) -> str: self.write(f".co_linetable = {co_linetable},") self.write(f"._co_cached = NULL,") self.write("._co_linearray = NULL,") + self.write(f"._first_instr = NULL,") self.write("._tier2_warmup = -64,") self.write("._bb_next = NULL,") self.write("._bb_space = NULL,") From d749e58e33e3b23406caf6dbd680c8797f2c9a69 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 30 Jan 2023 16:33:40 +0800 Subject: [PATCH 013/280] Remove first_instr We don't need to calculate the first_instr because all basic blocks won't have JUMP instructions --- Include/cpython/code.h | 1 - Include/internal/pycore_frame.h | 2 +- Objects/codeobject.c | 4 ---- Python/bytecodes.c | 3 --- Python/ceval_macros.h | 2 +- Python/generated_cases.c.h | 4 ---- Tools/build/deepfreeze.py | 1 - 7 files changed, 2 insertions(+), 15 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 594dfbc7eb7213..01eed3380a4929 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -119,7 +119,6 @@ typedef struct _PyTier2BBSpace { _PyCoCached *_co_cached; /* cached co_* attributes */ \ int _co_firsttraceable; /* index of first traceable instruction */ \ char *_co_linearray; /* array of line offsets */ \ - _Py_CODEUNIT *_first_instr; /* points to first tier 1/tier 2 instruction */ \ int _tier2_warmup; /* warmup counter for tier 2 */ \ _PyTier2BB *_bb_next; /* the tier 2 basic block to execute (if any) */ \ _PyTier2BBSpace *_bb_space; /* linked list storing basic blocks */ \ diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 63fb9b2d26fca5..1aff2dc6a6d065 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -69,7 +69,7 @@ typedef struct _PyInterpreterFrame { } _PyInterpreterFrame; #define _PyInterpreterFrame_LASTI(IF) \ - ((int)((IF)->prev_instr - (IF)->f_code->_first_instr)) + ((int)((IF)->prev_instr - _PyCode_CODE((IF)->f_code))) static inline PyObject **_PyFrame_Stackbase(_PyInterpreterFrame *f) { return f->localsplus + f->f_code->co_nlocalsplus; diff --git a/Objects/codeobject.c b/Objects/codeobject.c index cfc07fc98b8ba4..ba3c7bdce5a772 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -409,7 +409,6 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con) co->_co_linearray_entry_size = 0; co->_co_linearray = NULL; - co->_first_instr = _PyCode_CODE(co); co->_tier2_warmup = -64; co->_bb_next = NULL; co->_bb_space = NULL; @@ -1709,7 +1708,6 @@ code_dealloc(PyCodeObject *co) if (co->_co_linearray) { PyMem_Free(co->_co_linearray); } - co->_first_instr = NULL; co->_bb_next = NULL; if (co->_bb_space != NULL) { // Traverse the linked list @@ -2297,7 +2295,6 @@ _PyStaticCode_Fini(PyCodeObject *co) PyMem_Free(co->_co_cached); co->_co_cached = NULL; } - co->_first_instr = NULL; co->_bb_next = NULL; if (co->_bb_space != NULL) { // Traverse the linked list @@ -2322,7 +2319,6 @@ _PyStaticCode_Fini(PyCodeObject *co) int _PyStaticCode_Init(PyCodeObject *co) { - co->_first_instr = _PyCode_CODE(co); int res = intern_strings(co->co_names); if (res < 0) { return -1; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index e0f18670358cc8..ad16ad8f203158 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1963,9 +1963,6 @@ dummy_func( } inst(JUMP_BACKWARD_QUICK, (--)) { - if (oparg >= INSTR_OFFSET()) { - fprintf(stderr, "%ld, %p, %p, %p, %p, %p\n", oparg, next_instr, _PyCode_CODE(frame->f_code), frame->f_code->_bb_next->u_code, frame->f_code->_first_instr, frame->prev_instr); - } assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); CHECK_EVAL_BREAKER(); diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 255409348ee74a..7d601c71fde43b 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -141,7 +141,7 @@ GETITEM(PyObject *v, Py_ssize_t i) { /* The integer overflow is checked by an assertion below. */ // TODO change this calculation when interpreter is bb aware. -#define INSTR_OFFSET() ((int)(next_instr - frame->f_code->_first_instr)) +#define INSTR_OFFSET() ((int)(next_instr - _PyCode_CODE(frame->f_code))) #define NEXTOPARG() do { \ _Py_CODEUNIT word = *next_instr; \ opcode = _Py_OPCODE(word); \ diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index c9e79c5f846e64..f8766a4ccd1bb1 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2376,10 +2376,6 @@ TARGET(JUMP_BACKWARD_QUICK) { PREDICTED(JUMP_BACKWARD_QUICK); - if (oparg >= INSTR_OFFSET()) { - fprintf(stderr, "%ld, %p, %p, %p, %p, %p\n", oparg, next_instr, _PyCode_CODE(frame->f_code), frame->f_code->_bb_next->u_code, frame->f_code->_first_instr, frame->prev_instr); - - } assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); CHECK_EVAL_BREAKER(); diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py index 81e64516ecff3a..7718bc95722138 100644 --- a/Tools/build/deepfreeze.py +++ b/Tools/build/deepfreeze.py @@ -277,7 +277,6 @@ def generate_code(self, name: str, code: types.CodeType) -> str: self.write(f".co_linetable = {co_linetable},") self.write(f"._co_cached = NULL,") self.write("._co_linearray = NULL,") - self.write(f"._first_instr = NULL,") self.write("._tier2_warmup = -64,") self.write("._bb_next = NULL,") self.write("._bb_space = NULL,") From 90cd348cc17ecedefa4c9edd15ad3e02c0a084f4 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 30 Jan 2023 16:34:21 +0800 Subject: [PATCH 014/280] Remove first_instr for real this time --- Python/tier2.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Python/tier2.c b/Python/tier2.c index ce1dbad39c6866..4225a25f2dde7d 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -66,7 +66,6 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) co->_bb_next = bb_ptr; - co->_first_instr = bb_ptr->u_code; // Set the instruction pointer to the next one in the bb Py_ssize_t offset_from_start = (frame->prev_instr - _PyCode_CODE(co)); From 266f8fbe4f0329e4b46ae2de150a48c2971acb5d Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 30 Jan 2023 19:48:46 +0800 Subject: [PATCH 015/280] try (and fail) to add CACHE after each jump --- Include/internal/pycore_code.h | 7 +++++++ Include/internal/pycore_opcode.h | 8 +++++++- Lib/importlib/_bootstrap_external.py | 2 +- Lib/opcode.py | 20 ++++++++++++++++++++ Python/specialize.c | 26 +++++++++++++------------- Python/tier2.c | 12 ++++++------ 6 files changed, 54 insertions(+), 21 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 392ea9cf83055a..991278ac1d80d3 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -41,10 +41,17 @@ typedef struct { typedef struct { uint16_t counter; + uint16_t branch_counter; } _PyCompareOpCache; #define INLINE_CACHE_ENTRIES_COMPARE_OP CACHE_ENTRIES(_PyCompareOpCache) +typedef struct { + uint16_t branch_counter; +} _PyConditionalJumpCache; + +#define INLINE_CACHE_ENTRIES_CONDITIONAL_JUMP CACHE_ENTRIES(_PyConditionalJumpCache) + typedef struct { uint16_t counter; uint16_t type_version[2]; diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index b7f27863ba5e24..3d6fe300c0b584 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -48,9 +48,15 @@ const uint8_t _PyOpcode_Caches[256] = { [STORE_ATTR] = 4, [LOAD_ATTR] = 9, [COMPARE_OP] = 1, + [JUMP_IF_FALSE_OR_POP] = 1, + [JUMP_IF_TRUE_OR_POP] = 1, + [POP_JUMP_IF_FALSE] = 1, + [POP_JUMP_IF_TRUE] = 1, [LOAD_GLOBAL] = 5, [BINARY_OP] = 1, - [COMPARE_AND_BRANCH] = 1, + [POP_JUMP_IF_NOT_NONE] = 1, + [POP_JUMP_IF_NONE] = 1, + [COMPARE_AND_BRANCH] = 2, [CALL] = 4, }; diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index ebe1ef832289ac..4decba46906772 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -443,7 +443,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3519).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3529).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/opcode.py b/Lib/opcode.py index 08c73abd28848f..8b4fb2f60c10a1 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -403,8 +403,28 @@ def pseudo_op(name, op, real_ops): "COMPARE_OP": { "counter": 1, }, + # Conditional branch instructions all need a branch counter. "COMPARE_AND_BRANCH": { "counter": 1, + "branch_counter": 1, + }, + "JUMP_IF_FALSE_OR_POP": { + "branch_counter": 1, + }, + "JUMP_IF_TRUE_OR_POP": { + "branch_counter": 1, + }, + "POP_JUMP_IF_FALSE": { + "branch_counter": 1, + }, + "POP_JUMP_IF_TRUE": { + "branch_counter": 1, + }, + "POP_JUMP_IF_NOT_NONE": { + "branch_counter": 1, + }, + "POP_JUMP_IF_NONE": { + "branch_counter": 1, }, "BINARY_SUBSCR": { "counter": 1, diff --git a/Python/specialize.c b/Python/specialize.c index 77c5f2a30286bd..debad90f550695 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -305,19 +305,19 @@ _PyCode_Quicken(PyCodeObject *code) case STORE_FAST << 8 | STORE_FAST: instructions[i - 1].opcode = STORE_FAST__STORE_FAST; break; - case COMPARE_OP << 8 | POP_JUMP_IF_TRUE: - case COMPARE_OP << 8 | POP_JUMP_IF_FALSE: - { - int oparg = instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].oparg; - assert((oparg >> 4) <= Py_GE); - int mask = compare_masks[oparg >> 4]; - if (opcode == POP_JUMP_IF_FALSE) { - mask = mask ^ 0xf; - } - instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].opcode = COMPARE_AND_BRANCH; - instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].oparg = (oparg & 0xf0) | mask; - break; - } + //case COMPARE_OP << 8 | POP_JUMP_IF_TRUE: + //case COMPARE_OP << 8 | POP_JUMP_IF_FALSE: + //{ + // int oparg = instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].oparg; + // assert((oparg >> 4) <= Py_GE); + // int mask = compare_masks[oparg >> 4]; + // if (opcode == POP_JUMP_IF_FALSE) { + // mask = mask ^ 0xf; + // } + // instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].opcode = COMPARE_AND_BRANCH; + // instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].oparg = (oparg & 0xf0) | mask; + // break; + //} } } #endif /* ENABLE_SPECIALIZATION */ diff --git a/Python/tier2.c b/Python/tier2.c index 4225a25f2dde7d..8ba91ce4f2d3a5 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -15,12 +15,12 @@ _PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) if (code->_tier2_warmup != 0) { code->_tier2_warmup++; if (code->_tier2_warmup == 0) { - // If it fails, due to lack of memory or whatever, - // just fall back to the tier 1 interpreter. - _Py_CODEUNIT *next = _PyCode_Tier2Initialize(frame, next_instr); - if (next != NULL) { - return next; - } + //// If it fails, due to lack of memory or whatever, + //// just fall back to the tier 1 interpreter. + //_Py_CODEUNIT *next = _PyCode_Tier2Initialize(frame, next_instr); + //if (next != NULL) { + // return next; + //} } } return next_instr; From aec0d6f7689d8d1596b48c1ad279015dd6482aa4 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 1 Feb 2023 20:22:13 +0800 Subject: [PATCH 016/280] Revert "try (and fail) to add CACHE after each jump" This reverts commit 266f8fbe4f0329e4b46ae2de150a48c2971acb5d. --- Include/internal/pycore_code.h | 7 ------- Include/internal/pycore_opcode.h | 8 +------- Lib/importlib/_bootstrap_external.py | 2 +- Lib/opcode.py | 20 -------------------- Python/specialize.c | 26 +++++++++++++------------- Python/tier2.c | 12 ++++++------ 6 files changed, 21 insertions(+), 54 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 991278ac1d80d3..392ea9cf83055a 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -41,17 +41,10 @@ typedef struct { typedef struct { uint16_t counter; - uint16_t branch_counter; } _PyCompareOpCache; #define INLINE_CACHE_ENTRIES_COMPARE_OP CACHE_ENTRIES(_PyCompareOpCache) -typedef struct { - uint16_t branch_counter; -} _PyConditionalJumpCache; - -#define INLINE_CACHE_ENTRIES_CONDITIONAL_JUMP CACHE_ENTRIES(_PyConditionalJumpCache) - typedef struct { uint16_t counter; uint16_t type_version[2]; diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 3d6fe300c0b584..b7f27863ba5e24 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -48,15 +48,9 @@ const uint8_t _PyOpcode_Caches[256] = { [STORE_ATTR] = 4, [LOAD_ATTR] = 9, [COMPARE_OP] = 1, - [JUMP_IF_FALSE_OR_POP] = 1, - [JUMP_IF_TRUE_OR_POP] = 1, - [POP_JUMP_IF_FALSE] = 1, - [POP_JUMP_IF_TRUE] = 1, [LOAD_GLOBAL] = 5, [BINARY_OP] = 1, - [POP_JUMP_IF_NOT_NONE] = 1, - [POP_JUMP_IF_NONE] = 1, - [COMPARE_AND_BRANCH] = 2, + [COMPARE_AND_BRANCH] = 1, [CALL] = 4, }; diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 4decba46906772..ebe1ef832289ac 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -443,7 +443,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3529).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3519).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/opcode.py b/Lib/opcode.py index 8b4fb2f60c10a1..08c73abd28848f 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -403,28 +403,8 @@ def pseudo_op(name, op, real_ops): "COMPARE_OP": { "counter": 1, }, - # Conditional branch instructions all need a branch counter. "COMPARE_AND_BRANCH": { "counter": 1, - "branch_counter": 1, - }, - "JUMP_IF_FALSE_OR_POP": { - "branch_counter": 1, - }, - "JUMP_IF_TRUE_OR_POP": { - "branch_counter": 1, - }, - "POP_JUMP_IF_FALSE": { - "branch_counter": 1, - }, - "POP_JUMP_IF_TRUE": { - "branch_counter": 1, - }, - "POP_JUMP_IF_NOT_NONE": { - "branch_counter": 1, - }, - "POP_JUMP_IF_NONE": { - "branch_counter": 1, }, "BINARY_SUBSCR": { "counter": 1, diff --git a/Python/specialize.c b/Python/specialize.c index debad90f550695..77c5f2a30286bd 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -305,19 +305,19 @@ _PyCode_Quicken(PyCodeObject *code) case STORE_FAST << 8 | STORE_FAST: instructions[i - 1].opcode = STORE_FAST__STORE_FAST; break; - //case COMPARE_OP << 8 | POP_JUMP_IF_TRUE: - //case COMPARE_OP << 8 | POP_JUMP_IF_FALSE: - //{ - // int oparg = instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].oparg; - // assert((oparg >> 4) <= Py_GE); - // int mask = compare_masks[oparg >> 4]; - // if (opcode == POP_JUMP_IF_FALSE) { - // mask = mask ^ 0xf; - // } - // instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].opcode = COMPARE_AND_BRANCH; - // instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].oparg = (oparg & 0xf0) | mask; - // break; - //} + case COMPARE_OP << 8 | POP_JUMP_IF_TRUE: + case COMPARE_OP << 8 | POP_JUMP_IF_FALSE: + { + int oparg = instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].oparg; + assert((oparg >> 4) <= Py_GE); + int mask = compare_masks[oparg >> 4]; + if (opcode == POP_JUMP_IF_FALSE) { + mask = mask ^ 0xf; + } + instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].opcode = COMPARE_AND_BRANCH; + instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].oparg = (oparg & 0xf0) | mask; + break; + } } } #endif /* ENABLE_SPECIALIZATION */ diff --git a/Python/tier2.c b/Python/tier2.c index 8ba91ce4f2d3a5..4225a25f2dde7d 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -15,12 +15,12 @@ _PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) if (code->_tier2_warmup != 0) { code->_tier2_warmup++; if (code->_tier2_warmup == 0) { - //// If it fails, due to lack of memory or whatever, - //// just fall back to the tier 1 interpreter. - //_Py_CODEUNIT *next = _PyCode_Tier2Initialize(frame, next_instr); - //if (next != NULL) { - // return next; - //} + // If it fails, due to lack of memory or whatever, + // just fall back to the tier 1 interpreter. + _Py_CODEUNIT *next = _PyCode_Tier2Initialize(frame, next_instr); + if (next != NULL) { + return next; + } } } return next_instr; From 146bf1369fbd3968551af46d15e73420d5434d7a Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 8 Feb 2023 23:50:57 +0800 Subject: [PATCH 017/280] Write functions to allocate execution bbs --- Include/cpython/code.h | 4 +- Include/internal/pycore_opcode.h | 3 +- Include/opcode.h | 5 +- Lib/importlib/_bootstrap_external.py | 2 +- Lib/opcode.py | 1 - Python/tier2.c | 68 +++++++++++++++++++++++++--- 6 files changed, 70 insertions(+), 13 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 01eed3380a4929..f71a4a679e9098 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -55,7 +55,9 @@ typedef struct _PyTier2BB { // Bump allocator for basic blocks (overallocated) typedef struct _PyTier2BBSpace { struct _PyTier2BBSpace *next; - void *water_level; + int max_capacity; + // How much space has been consumed in bbs. + int water_level; _PyTier2BB bbs[1]; } _PyTier2BBSpace; diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index b7f27863ba5e24..36623f101e82ef 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -397,9 +397,9 @@ static const char *const _PyOpcode_OpName[263] = { [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", - [BB_NEXT] = "BB_NEXT", [BINARY_OP_ADD_INT_TYPE_CHECK] = "BINARY_OP_ADD_INT_TYPE_CHECK", [BINARY_OP_ADD_INT_REST] = "BINARY_OP_ADD_INT_REST", + [169] = "<169>", [170] = "<170>", [CALL] = "CALL", [KW_NAMES] = "KW_NAMES", @@ -498,6 +498,7 @@ static const char *const _PyOpcode_OpName[263] = { #define EXTRA_CASES \ + case 169: \ case 170: \ case 174: \ case 175: \ diff --git a/Include/opcode.h b/Include/opcode.h index bdd4f8b8e44d46..e81d95e0f8fcc5 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -254,9 +254,8 @@ extern "C" { #define UNPACK_SEQUENCE_TUPLE 161 #define UNPACK_SEQUENCE_TWO_TUPLE 166 #define DO_TRACING 255 -#define BB_NEXT 167 -#define BINARY_OP_ADD_INT_TYPE_CHECK 168 -#define BINARY_OP_ADD_INT_REST 169 +#define BINARY_OP_ADD_INT_TYPE_CHECK 167 +#define BINARY_OP_ADD_INT_REST 168 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index ebe1ef832289ac..e760fbb15759d4 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -443,7 +443,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3519).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3517).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/opcode.py b/Lib/opcode.py index 08c73abd28848f..47abe8e508aa3b 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -443,7 +443,6 @@ def pseudo_op(name, op, real_ops): 'BINARY_OP_ADD_INT', ] _uops = [ - 'BB_NEXT', 'BINARY_OP_ADD_INT_TYPE_CHECK', 'BINARY_OP_ADD_INT_REST', ] diff --git a/Python/tier2.c b/Python/tier2.c index 4225a25f2dde7d..a5a2ebc569eb0d 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -26,6 +26,33 @@ _PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) return next_instr; } + +static _PyTier2BBSpace * +_PyTier2_CreateBBSpace(Py_ssize_t space_to_alloc) +{ + _PyTier2BBSpace *bb_space = PyMem_Malloc(space_to_alloc); + if (bb_space == NULL) { + return NULL; + } + bb_space->next = NULL; + bb_space->water_level = 0; + bb_space->max_capacity = space_to_alloc - sizeof(_PyTier2BB); + return bb_space; +} + +/* Init a BB in BB space without any checks for waterlevel. */ +static _PyTier2BB * +_PyTier2_InitBBNoCheck(_PyTier2BBSpace *bb_space, _Py_CODEUNIT *tier1_start, + const void *instr_bytes_src, Py_ssize_t instr_nbytes) +{ + _PyTier2BB *bb_ptr = &bb_space->bbs[bb_space->water_level]; + bb_ptr->tier1_start = tier1_start; + memcpy(bb_ptr->u_code, instr_bytes_src, instr_nbytes); + assert(bb_space->water_level + instr_nbytes == (int)(bb_space->water_level + instr_nbytes)); + bb_space->water_level += instr_nbytes; + return bb_ptr; +} + static _Py_CODEUNIT * _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) { @@ -39,17 +66,18 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) // @TODO split up code object into basic blocks. // 3. Set the instruction pointer to correct one. fprintf(stderr, "INITIALIZING %ld\n", Py_SIZE(co)); - _PyTier2BBSpace *bb_space = PyMem_Malloc((sizeof(_PyTier2BB) + _PyCode_NBYTES(co)) * 2); + Py_ssize_t space_to_alloc = (sizeof(_PyTier2BB) + _PyCode_NBYTES(co)) * 2; + + _PyTier2BBSpace *bb_space = _PyTier2_CreateBBSpace(space_to_alloc); if (bb_space == NULL) { return NULL; } - bb_space->next = NULL; - bb_space->water_level = 0; + co->_bb_space = bb_space; - _PyTier2BB *bb_ptr = bb_space->bbs; - bb_ptr->tier1_start = _PyCode_CODE(co); - memcpy(bb_ptr->u_code, _PyCode_CODE(co), _PyCode_NBYTES(co)); + _PyTier2BB *bb_ptr = _PyTier2_InitBBNoCheck(bb_space, _PyCode_CODE(co), + _PyCode_CODE(co), _PyCode_NBYTES(co)); + // Remove all the RESUME and JUMP_BACKWARDS instructions for (Py_ssize_t i = 0; i < Py_SIZE(co); i++) { _Py_CODEUNIT instr = bb_ptr->u_code[i]; @@ -75,3 +103,31 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) // _py_set_opcode(next_instr, CACHE); return bb_ptr->u_code + (next_instr - _PyCode_CODE(co)); } + +/* Allocates and initializes a new basic block. If not enough space in + the overallocated array, create a new array. + + Make sure to call _PyCode_Tier2Initialize before this! +*/ +static _PyTier2BB * +_PyCode_Tier2BBNew(PyCodeObject *co, _Py_CODEUNIT *tier1_start, _Py_CODEUNIT *instr, Py_ssize_t code_size) +{ + assert(co->_bb_space != NULL); + + _PyTier2BBSpace *bb_space = co->_bb_space; + Py_ssize_t amount_to_alloc = code_size + sizeof(_PyTier2BB); + assert(bb_space->water_level + amount_to_alloc == (int)(bb_space->water_level + amount_to_alloc)); + + // Need to allocate a new array. + if (bb_space->water_level + amount_to_alloc > bb_space->max_capacity) { + _PyTier2BBSpace *next_bb_space = _PyTier2_CreateBBSpace(bb_space->max_capacity + amount_to_alloc); + if (next_bb_space == NULL) { + return NULL; + } + next_bb_space->next = bb_space; + // We want to make our bb_space point to the most recent one to get O(1) BB allocations. + co->_bb_space = next_bb_space; + bb_space = next_bb_space; + } + return _PyTier2_InitBBNoCheck(bb_space, tier1_start, instr, code_size * sizeof(_Py_CODEUNIT)); +} From fd10c2cf46fa28d23127f6f98a208cd1fc069911 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu, 9 Feb 2023 12:25:09 +0800 Subject: [PATCH 018/280] tracer/profiler kind of thing --- Include/internal/pycore_code.h | 2 +- Include/internal/pycore_interp.h | 1 + Python/bytecodes.c | 13 +- Python/ceval.c | 397 +++++++++++++++++++++++++++++++ Python/ceval_macros.h | 117 +++++++-- Python/compile.c | 1 - Python/generated_cases.c.h | 15 +- Python/tier2.c | 26 +- 8 files changed, 541 insertions(+), 31 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 392ea9cf83055a..b1520b2923a650 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -240,7 +240,7 @@ extern void _PyStaticCode_Fini(PyCodeObject *co); extern int _PyStaticCode_Init(PyCodeObject *co); /* Tier 2 interpreter */ -extern _Py_CODEUNIT *_PyCode_Tier2Warmup(struct _PyInterpreterFrame *, _Py_CODEUNIT *); +extern int _PyCode_Tier2Warmup(PyThreadState *, struct _PyInterpreterFrame *, int, _Py_CODEUNIT *, PyObject **, PyObject **); #ifdef Py_STATS diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 0e3d46852f2e6d..c4f11d8e0c4e31 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -230,6 +230,7 @@ PyAPI_FUNC(int) _PyInterpreterState_IDInitref(PyInterpreterState *); PyAPI_FUNC(int) _PyInterpreterState_IDIncref(PyInterpreterState *); PyAPI_FUNC(void) _PyInterpreterState_IDDecref(PyInterpreterState *); +PyObject *_PyEval_EvalFrameTier2Profile(PyThreadState *tstate, struct _PyInterpreterFrame *frame, int throwflag); #ifdef __cplusplus } #endif diff --git a/Python/bytecodes.c b/Python/bytecodes.c index c310802d577507..47e270c663b0ab 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -89,7 +89,10 @@ dummy_func( inst(RESUME, (--)) { if (cframe.use_tracing == 0) { - next_instr = _PyCode_Tier2Warmup(frame, next_instr); + PyObject *retval = NULL; + if (_PyCode_Tier2Warmup(tstate, frame, throwflag, next_instr, stack_pointer, &retval)) { + return retval; + } } GO_TO_INSTRUCTION(RESUME_QUICK); } @@ -1881,10 +1884,14 @@ dummy_func( } inst(JUMP_BACKWARD, (--)) { + JUMPBY(-oparg); + CHECK_EVAL_BREAKER(); if (cframe.use_tracing == 0) { - next_instr = _PyCode_Tier2Warmup(frame, next_instr); + PyObject *retval = NULL; + if (_PyCode_Tier2Warmup(tstate, frame, throwflag, next_instr, stack_pointer, &retval)) { + return retval; + } } - GO_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); } inst(JUMP_BACKWARD_QUICK, (--)) { diff --git a/Python/ceval.c b/Python/ceval.c index a91f5baca8853e..6102f5d025edc9 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -706,6 +706,7 @@ static inline void _Py_LeaveRecursiveCallPy(PyThreadState *tstate) { # pragma warning(disable:4102) #endif +#undef TIER2_PROFILING PyObject* _Py_HOT_FUNCTION _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag) { @@ -1094,6 +1095,402 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int # pragma warning(pop) #endif +// CARBON-COPY of _PyEval_EvalFrameDefault. KEEP IN SYNC WITH THAT FUNCTION. +#define TIER2_PROFILING 1 +#undef INSTRUCTION_START +#undef TARGET +#undef GETITEM +#include "ceval_macros.h" +PyObject * +_PyEval_EvalFrameTier2Profile(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag, PyObject **old_stack_pointer) +{ + fprintf(stderr, "TIER2_PROFILING\n"); + _Py_EnsureTstateNotNULL(tstate); + CALL_STAT_INC(pyeval_calls); + +#if USE_COMPUTED_GOTOS + /* Import the static jump table */ +#include "opcode_targets.h" +#endif + +#ifdef Py_STATS + int lastopcode = 0; +#endif + // opcode is an 8-bit value to improve the code generated by MSVC + // for the big switch below (in combination with the EXTRA_CASES macro). + uint8_t opcode; /* Current opcode */ + int oparg; /* Current opcode argument, if any */ + _Py_atomic_int *const eval_breaker = &tstate->interp->ceval.eval_breaker; +#ifdef LLTRACE + int lltrace = 0; +#endif + + _PyCFrame cframe; + _PyInterpreterFrame entry_frame; + PyObject *kwnames = NULL; // Borrowed reference. Reset by CALL instructions. + + /* WARNING: Because the _PyCFrame lives on the C stack, + * but can be accessed from a heap allocated object (tstate) + * strict stack discipline must be maintained. + */ + _PyCFrame *prev_cframe = tstate->cframe; + cframe.use_tracing = prev_cframe->use_tracing; + cframe.previous = prev_cframe; + tstate->cframe = &cframe; + + assert(tstate->interp->interpreter_trampoline != NULL); +#ifdef Py_DEBUG + /* Set these to invalid but identifiable values for debugging. */ + entry_frame.f_funcobj = (PyObject *)0xaaa0; + entry_frame.f_locals = (PyObject *)0xaaa1; + entry_frame.frame_obj = (PyFrameObject *)0xaaa2; + entry_frame.f_globals = (PyObject *)0xaaa3; + entry_frame.f_builtins = (PyObject *)0xaaa4; +#endif + entry_frame.f_code = tstate->interp->interpreter_trampoline; + entry_frame.prev_instr = + _PyCode_CODE(tstate->interp->interpreter_trampoline); + entry_frame.stacktop = 0; + entry_frame.owner = FRAME_OWNED_BY_CSTACK; + entry_frame.yield_offset = 0; + /* Push frame */ + entry_frame.previous = prev_cframe->current_frame; + frame->previous = &entry_frame; + cframe.current_frame = frame; + + if (_Py_EnterRecursiveCallTstate(tstate, "")) { + tstate->c_recursion_remaining--; + tstate->py_recursion_remaining--; + goto exit_unwind; + } + + /* support for generator.throw() */ + if (throwflag) { + if (_Py_EnterRecursivePy(tstate)) { + goto exit_unwind; + } + TRACE_FUNCTION_THROW_ENTRY(); + DTRACE_FUNCTION_ENTRY(); + goto resume_with_error; + } + + /* Local "register" variables. + * These are cached values from the frame and code object. */ + + PyObject *names; + PyObject *consts; + _Py_CODEUNIT *next_instr; + PyObject **stack_pointer; + + /* Sets the above local variables from the frame */ +#define SET_LOCALS_FROM_FRAME() \ + { \ + PyCodeObject *co = frame->f_code; \ + names = co->co_names; \ + consts = co->co_consts; \ + } \ + assert(_PyInterpreterFrame_LASTI(frame) >= -1); \ + /* Jump back to the last instruction executed... */ \ + next_instr = frame->prev_instr + 1; \ + stack_pointer = _PyFrame_GetStackPointer(frame); \ + /* Set stackdepth to -1. \ + Update when returning or calling trace function. \ + Having stackdepth <= 0 ensures that invalid \ + values are not visible to the cycle GC. \ + We choose -1 rather than 0 to assist debugging. \ + */ \ + frame->stacktop = -1; + + +start_frame: + if (_Py_EnterRecursivePy(tstate)) { + goto exit_unwind; + } + +resume_frame: + SET_LOCALS_FROM_FRAME(); + +#ifdef LLTRACE + { + if (frame != &entry_frame) { + int r = PyDict_Contains(GLOBALS(), &_Py_ID(__lltrace__)); + if (r < 0) { + goto exit_unwind; + } + lltrace = r; + } + if (lltrace) { + lltrace_resume_frame(frame); + } + } +#endif + +#ifdef Py_DEBUG + /* _PyEval_EvalFrameDefault() must not be called with an exception set, + because it can clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!_PyErr_Occurred(tstate)); +#endif + + DISPATCH(); + +handle_eval_breaker: + + /* Do periodic things, like check for signals and async I/0. + * We need to do reasonably frequently, but not too frequently. + * All loops should include a check of the eval breaker. + * We also check on return from any builtin function. + */ + if (_Py_HandlePending(tstate) != 0) { + goto error; + } + DISPATCH(); + + { + /* Start instructions */ +#if !USE_COMPUTED_GOTOS + dispatch_opcode : + switch (opcode) +#endif + { + +#include "generated_cases.c.h" + +#if USE_COMPUTED_GOTOS + TARGET_DO_TRACING : +#else + case DO_TRACING: +#endif + { + assert(cframe.use_tracing); + assert(tstate->tracing == 0); + if (INSTR_OFFSET() >= frame->f_code->_co_firsttraceable) { + int instr_prev = _PyInterpreterFrame_LASTI(frame); + frame->prev_instr = next_instr; + NEXTOPARG(); + // No _PyOpcode_Deopt here, since RESUME has no optimized forms: + if (opcode == RESUME) { + if (oparg < 2) { + CHECK_EVAL_BREAKER(); + } + /* Call tracing */ + TRACE_FUNCTION_ENTRY(); + DTRACE_FUNCTION_ENTRY(); + } + else { + /* line-by-line tracing support */ + if (PyDTrace_LINE_ENABLED()) { + maybe_dtrace_line(frame, &tstate->trace_info, instr_prev); + } + + if (cframe.use_tracing && + tstate->c_tracefunc != NULL && !tstate->tracing) { + int err; + /* see maybe_call_line_trace() + for expository comments */ + _PyFrame_SetStackPointer(frame, stack_pointer); + + err = maybe_call_line_trace(tstate->c_tracefunc, + tstate->c_traceobj, + tstate, frame, instr_prev); + // Reload possibly changed frame fields: + stack_pointer = _PyFrame_GetStackPointer(frame); + frame->stacktop = -1; + // next_instr is only reloaded if tracing *does not* raise. + // This is consistent with the behavior of older Python + // versions. If a trace function sets a new f_lineno and + // *then* raises, we use the *old* location when searching + // for an exception handler, displaying the traceback, and + // so on: + if (err) { + // next_instr wasn't incremented at the start of this + // instruction. Increment it before handling the error, + // so that it looks the same as a "normal" instruction: + next_instr++; + goto error; + } + // Reload next_instr. Don't increment it, though, since + // we're going to re-dispatch to the "true" instruction now: + next_instr = frame->prev_instr; + } + } + } + NEXTOPARG(); + PRE_DISPATCH_GOTO(); + // No _PyOpcode_Deopt here, since EXTENDED_ARG has no optimized forms: + while (opcode == EXTENDED_ARG) { + // CPython hasn't ever traced the instruction after an EXTENDED_ARG. + // Inline the EXTENDED_ARG here, so we can avoid branching there: + INSTRUCTION_START(EXTENDED_ARG); + opcode = _Py_OPCODE(*next_instr); + oparg = oparg << 8 | _Py_OPARG(*next_instr); + // Make sure the next instruction isn't a RESUME, since that needs + // to trace properly (and shouldn't have an EXTENDED_ARG, anyways): + assert(opcode != RESUME); + PRE_DISPATCH_GOTO(); + } + opcode = _PyOpcode_Deopt[opcode]; + if (_PyOpcode_Caches[opcode]) { + uint16_t *counter = &next_instr[1].cache; + // The instruction is going to decrement the counter, so we need to + // increment it here to make sure it doesn't try to specialize: + if (!ADAPTIVE_COUNTER_IS_MAX(*counter)) { + INCREMENT_ADAPTIVE_COUNTER(*counter); + } + } + DISPATCH_GOTO(); + } + +#if USE_COMPUTED_GOTOS + _unknown_opcode : +#else + EXTRA_CASES // From opcode.h, a 'case' for each unused opcode +#endif + /* Tell C compilers not to hold the opcode variable in the loop. + next_instr points the current instruction without TARGET(). */ + opcode = _Py_OPCODE(*next_instr); + _PyErr_Format(tstate, PyExc_SystemError, + "%U:%d: unknown opcode %d", + frame->f_code->co_filename, + _PyInterpreterFrame_GetLine(frame), + opcode); + goto error; + + } /* End instructions */ + + /* This should never be reached. Every opcode should end with DISPATCH() + or goto error. */ + Py_UNREACHABLE(); + + unbound_local_error: + { + format_exc_check_arg(tstate, PyExc_UnboundLocalError, + UNBOUNDLOCAL_ERROR_MSG, + PyTuple_GetItem(frame->f_code->co_localsplusnames, oparg) + ); + goto error; + } + + pop_4_error: + STACK_SHRINK(1); + pop_3_error: + STACK_SHRINK(1); + pop_2_error: + STACK_SHRINK(1); + pop_1_error: + STACK_SHRINK(1); + error: + kwnames = NULL; + /* Double-check exception status. */ +#ifdef NDEBUG + if (!_PyErr_Occurred(tstate)) { + _PyErr_SetString(tstate, PyExc_SystemError, + "error return without exception set"); + } +#else + assert(_PyErr_Occurred(tstate)); +#endif + + /* Log traceback info. */ + assert(frame != &entry_frame); + if (!_PyFrame_IsIncomplete(frame)) { + PyFrameObject *f = _PyFrame_GetFrameObject(frame); + if (f != NULL) { + PyTraceBack_Here(f); + } + } + + if (tstate->c_tracefunc != NULL) { + /* Make sure state is set to FRAME_UNWINDING for tracing */ + call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, + tstate, frame); + } + + exception_unwind: + { + /* We can't use frame->f_lasti here, as RERAISE may have set it */ + int offset = INSTR_OFFSET() - 1; + int level, handler, lasti; + if (get_exception_handler(frame->f_code, offset, &level, &handler, &lasti) == 0) { + // No handlers, so exit. + assert(_PyErr_Occurred(tstate)); + + /* Pop remaining stack entries. */ + PyObject **stackbase = _PyFrame_Stackbase(frame); + while (stack_pointer > stackbase) { + PyObject *o = POP(); + Py_XDECREF(o); + } + assert(STACK_LEVEL() == 0); + _PyFrame_SetStackPointer(frame, stack_pointer); + TRACE_FUNCTION_UNWIND(); + DTRACE_FUNCTION_EXIT(); + goto exit_unwind; + } + + assert(STACK_LEVEL() >= level); + PyObject **new_top = _PyFrame_Stackbase(frame) + level; + while (stack_pointer > new_top) { + PyObject *v = POP(); + Py_XDECREF(v); + } + PyObject *exc, *val, *tb; + if (lasti) { + int frame_lasti = _PyInterpreterFrame_LASTI(frame); + PyObject *lasti = PyLong_FromLong(frame_lasti); + if (lasti == NULL) { + goto exception_unwind; + } + PUSH(lasti); + } + _PyErr_Fetch(tstate, &exc, &val, &tb); + /* Make the raw exception data + available to the handler, + so a program can emulate the + Python main loop. */ + _PyErr_NormalizeException(tstate, &exc, &val, &tb); + if (tb != NULL) + PyException_SetTraceback(val, tb); + else + PyException_SetTraceback(val, Py_None); + Py_XDECREF(tb); + Py_XDECREF(exc); + PUSH(val); + JUMPTO(handler); + /* Resume normal execution */ + DISPATCH(); + } + } + +exit_unwind: + assert(_PyErr_Occurred(tstate)); + _Py_LeaveRecursiveCallPy(tstate); + assert(frame != &entry_frame); + // GH-99729: We need to unlink the frame *before* clearing it: + _PyInterpreterFrame *dying = frame; + frame = cframe.current_frame = dying->previous; + _PyEvalFrameClearAndPop(tstate, dying); + if (frame == &entry_frame) { + /* Restore previous cframe and exit */ + tstate->cframe = cframe.previous; + tstate->cframe->use_tracing = cframe.use_tracing; + assert(tstate->cframe->current_frame == frame->previous); + _Py_LeaveRecursiveCallTstate(tstate); + return NULL; + } + +resume_with_error: + SET_LOCALS_FROM_FRAME(); + goto error; + +} + +#undef TIER2_PROFILING +#undef INSTRUCTION_START +#undef TARGET +#undef GETITEM +#include "ceval_macros.h" + static void format_missing(PyThreadState *tstate, const char *kind, PyCodeObject *co, PyObject *names, PyObject *qualname) diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 7d601c71fde43b..1aa12383b748c6 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -47,6 +47,10 @@ #define OR_DTRACE_LINE #endif +#ifdef USE_COMPUTED_GOTOS + #undef USE_COMPUTED_GOTOS +#endif + #ifdef HAVE_COMPUTED_GOTOS #ifndef USE_COMPUTED_GOTOS #define USE_COMPUTED_GOTOS 1 @@ -59,26 +63,57 @@ #define USE_COMPUTED_GOTOS 0 #endif -#ifdef Py_STATS -#define INSTRUCTION_START(op) \ - do { \ - frame->prev_instr = next_instr++; \ - OPCODE_EXE_INC(op); \ - if (_py_stats) _py_stats->opcode_stats[lastopcode].pair_count[op]++; \ - lastopcode = op; \ - } while (0) -#else -#define INSTRUCTION_START(op) (frame->prev_instr = next_instr++) +#ifdef INSTRUCTION_START + #undef INSTRUCTION_START #endif -#if USE_COMPUTED_GOTOS -# define TARGET(op) TARGET_##op: INSTRUCTION_START(op); -# define DISPATCH_GOTO() goto *opcode_targets[opcode] +#ifndef TIER2_PROFILING + #ifdef Py_STATS + #define INSTRUCTION_START(op) \ + do { \ + frame->prev_instr = next_instr++; \ + OPCODE_EXE_INC(op); \ + if (_py_stats) _py_stats->opcode_stats[lastopcode].pair_count[op]++; \ + lastopcode = op; \ + } while (0) + #else + #define INSTRUCTION_START(op) (frame->prev_instr = next_instr++) + #endif #else -# define TARGET(op) case op: TARGET_##op: INSTRUCTION_START(op); -# define DISPATCH_GOTO() goto dispatch_opcode + #define INSTRUCTION_START(op) \ + do { \ + frame->prev_instr = next_instr++; \ + fprintf(stderr, "%d\n", op); \ + } while (0) +#endif /* TIER2_PROFILING */ + +#ifdef TARGET +#undef TARGET +#endif + +#ifdef DISPATCH_GOTO +#undef DISPATCH_GOTO #endif +#ifndef TIER2_PROFILING + #if USE_COMPUTED_GOTOS + # define TARGET(op) TARGET_##op: INSTRUCTION_START(op); + # define DISPATCH_GOTO() goto *opcode_targets[opcode] + #else + # define TARGET(op) case op: TARGET_##op: INSTRUCTION_START(op); + # define DISPATCH_GOTO() goto dispatch_opcode + #endif +#else + #if USE_COMPUTED_GOTOS + # define TARGET(op) TARGET_TIER2_PROFILE_##op: INSTRUCTION_START(op); + # define DISPATCH_GOTO() goto *opcode_targets[opcode] + #else + # define TARGET(op) case op: TARGET_TIER2_PROFILE_##op: INSTRUCTION_START(op); + # define DISPATCH_GOTO() goto dispatch_opcode + #endif +#endif /* TIER2_PROFILING */ + + /* PRE_DISPATCH_GOTO() does lltrace if enabled. Normally a no-op */ #ifdef LLTRACE #define PRE_DISPATCH_GOTO() if (lltrace) { \ @@ -87,6 +122,9 @@ #define PRE_DISPATCH_GOTO() ((void)0) #endif +#ifdef DISPATCH +#undef DISPATCH +#endif /* Do interpreter dispatch accounting for tracing and instrumentation */ #define DISPATCH() \ @@ -98,6 +136,10 @@ DISPATCH_GOTO(); \ } +#ifdef DISPATCH_SAME_OPARG +#undef DISPATCH_SAME_OPARG +#endif + #define DISPATCH_SAME_OPARG() \ { \ opcode = _Py_OPCODE(*next_instr); \ @@ -106,6 +148,10 @@ DISPATCH_GOTO(); \ } +#ifdef DISPATCH_INLINED +#undef DISPATCH_INLINED +#endif + #define DISPATCH_INLINED(NEW_FRAME) \ do { \ _PyFrame_SetStackPointer(frame, stack_pointer); \ @@ -116,6 +162,10 @@ goto start_frame; \ } while (0) +#ifdef CHECK_EVAL_BREAKER +#undef CHECK_EVAL_BREAKER +#endif + #define CHECK_EVAL_BREAKER() \ _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); \ if (_Py_atomic_load_relaxed_int32(eval_breaker)) { \ @@ -125,9 +175,12 @@ /* Tuple access macros */ + #ifndef Py_DEBUG #define GETITEM(v, i) PyTuple_GET_ITEM((v), (i)) #else +#ifndef _GETITEM_DEF_H +#define _GETITEM_DEF_H static inline PyObject * GETITEM(PyObject *v, Py_ssize_t i) { assert(PyTuple_Check(v)); @@ -135,10 +188,27 @@ GETITEM(PyObject *v, Py_ssize_t i) { assert(i < PyTuple_GET_SIZE(v)); return PyTuple_GET_ITEM(v, i); } +#endif /* _GETITEM_DEF_H */ #endif /* Code access macros */ +#ifdef INSTR_OFFSET +#undef INSTR_OFFSET +#endif + +#ifdef NEXTOPARG +#undef NEXTOPARG +#endif + +#ifdef JUMPTO +#undef JUMPTO +#endif + +#ifdef JUMPBY +#undef JUMPBY +#endif + /* The integer overflow is checked by an assertion below. */ // TODO change this calculation when interpreter is bb aware. #define INSTR_OFFSET() ((int)(next_instr - _PyCode_CODE(frame->f_code))) @@ -176,7 +246,23 @@ GETITEM(PyObject *v, Py_ssize_t i) { */ +#ifdef PREDICT_ID +#undef PREDICT_ID +#endif + +#ifndef TIER2_PROFILING #define PREDICT_ID(op) PRED_##op +#else +#define PREDICT_ID(op) PRED_TIER2_PROFILING_##op +#endif + +#ifdef PREDICT +#undef PREDICT +#endif + +#ifdef PREDICTED +#undef PREDICTED +#endif #if USE_COMPUTED_GOTOS #define PREDICT(op) if (0) goto PREDICT_ID(op) @@ -251,6 +337,7 @@ GETITEM(PyObject *v, Py_ssize_t i) { GETLOCAL(i) = value; \ Py_XDECREF(tmp); } while (0) + #define GO_TO_INSTRUCTION(op) goto PREDICT_ID(op) #ifdef Py_STATS diff --git a/Python/compile.c b/Python/compile.c index bdc25ba9df9b4a..df2dffb95bbd7e 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1079,7 +1079,6 @@ stack_effect(int opcode, int oparg, int jump) case EXTENDED_ARG: case RESUME: case CACHE: - case BB_NEXT: return 0; /* Stack manipulation */ diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 605b9767417d3c..ca6216218f03c2 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -24,7 +24,10 @@ TARGET(RESUME) { if (cframe.use_tracing == 0) { - next_instr = _PyCode_Tier2Warmup(frame, next_instr); + PyObject *retval = NULL; + if (_PyCode_Tier2Warmup(tstate, frame, throwflag, next_instr, stack_pointer, &retval)) { + return retval; + } } GO_TO_INSTRUCTION(RESUME_QUICK); } @@ -2417,14 +2420,18 @@ TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); + JUMPBY(-oparg); + CHECK_EVAL_BREAKER(); if (cframe.use_tracing == 0) { - next_instr = _PyCode_Tier2Warmup(frame, next_instr); + PyObject *retval = NULL; + if (_PyCode_Tier2Warmup(tstate, frame, throwflag, next_instr, stack_pointer, &retval)) { + return retval; + } } - GO_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); + DISPATCH(); } TARGET(JUMP_BACKWARD_QUICK) { - PREDICTED(JUMP_BACKWARD_QUICK); assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); CHECK_EVAL_BREAKER(); diff --git a/Python/tier2.c b/Python/tier2.c index a5a2ebc569eb0d..ddb82526d7e719 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -1,16 +1,22 @@ #include "Python.h" #include "pycore_code.h" #include "pycore_frame.h" +#include "pycore_interp.h" #include "opcode.h" +#include "pystate.h" +#include "pytypedefs.h" static _Py_CODEUNIT * _PyCode_Tier2Initialize(_PyInterpreterFrame *, _Py_CODEUNIT *); // Tier 2 warmup counter -_Py_CODEUNIT * -_PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) +int +_PyCode_Tier2Warmup(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag, _Py_CODEUNIT *next_instr, PyObject **stack_pointer, PyObject **retval) { + if (tstate->interp->eval_frame != NULL) { + return 0; + } PyCodeObject *code = frame->f_code; if (code->_tier2_warmup != 0) { code->_tier2_warmup++; @@ -18,15 +24,22 @@ _PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) // If it fails, due to lack of memory or whatever, // just fall back to the tier 1 interpreter. _Py_CODEUNIT *next = _PyCode_Tier2Initialize(frame, next_instr); - if (next != NULL) { - return next; - } + // Swap out the profiler to use the profiling eval loop. + frame->prev_instr = next_instr - 1; + _PyFrame_SetStackPointer(frame, stack_pointer); + // Do something with entry_frame here, maybe set the current frame to an entry + // frame and check for that in RETURN_VALUE? + *retval = _PyEval_EvalFrameTier2Profile(tstate, frame, throwflag); + PyObject_Print(*retval, stderr, Py_PRINT_RAW); + return 1; + } } - return next_instr; + return 0; } + static _PyTier2BBSpace * _PyTier2_CreateBBSpace(Py_ssize_t space_to_alloc) { @@ -57,7 +70,6 @@ static _Py_CODEUNIT * _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) { int curr = _Py_OPCODE(*(next_instr - 1)); - assert(curr == RESUME || curr == JUMP_BACKWARD); PyCodeObject *co = frame->f_code; assert(co->_bb_space == NULL); // 1. Initialize basic blocks space. From f87f8f4251a7bf58c780776eee2af9446ebda70d Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu, 9 Feb 2023 12:25:43 +0800 Subject: [PATCH 019/280] Revert "tracer/profiler kind of thing" This reverts commit fd10c2cf46fa28d23127f6f98a208cd1fc069911. --- Include/internal/pycore_code.h | 2 +- Include/internal/pycore_interp.h | 1 - Python/bytecodes.c | 13 +- Python/ceval.c | 397 ------------------------------- Python/ceval_macros.h | 117 ++------- Python/compile.c | 1 + Python/generated_cases.c.h | 15 +- Python/tier2.c | 26 +- 8 files changed, 31 insertions(+), 541 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index b1520b2923a650..392ea9cf83055a 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -240,7 +240,7 @@ extern void _PyStaticCode_Fini(PyCodeObject *co); extern int _PyStaticCode_Init(PyCodeObject *co); /* Tier 2 interpreter */ -extern int _PyCode_Tier2Warmup(PyThreadState *, struct _PyInterpreterFrame *, int, _Py_CODEUNIT *, PyObject **, PyObject **); +extern _Py_CODEUNIT *_PyCode_Tier2Warmup(struct _PyInterpreterFrame *, _Py_CODEUNIT *); #ifdef Py_STATS diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index c4f11d8e0c4e31..0e3d46852f2e6d 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -230,7 +230,6 @@ PyAPI_FUNC(int) _PyInterpreterState_IDInitref(PyInterpreterState *); PyAPI_FUNC(int) _PyInterpreterState_IDIncref(PyInterpreterState *); PyAPI_FUNC(void) _PyInterpreterState_IDDecref(PyInterpreterState *); -PyObject *_PyEval_EvalFrameTier2Profile(PyThreadState *tstate, struct _PyInterpreterFrame *frame, int throwflag); #ifdef __cplusplus } #endif diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 47e270c663b0ab..c310802d577507 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -89,10 +89,7 @@ dummy_func( inst(RESUME, (--)) { if (cframe.use_tracing == 0) { - PyObject *retval = NULL; - if (_PyCode_Tier2Warmup(tstate, frame, throwflag, next_instr, stack_pointer, &retval)) { - return retval; - } + next_instr = _PyCode_Tier2Warmup(frame, next_instr); } GO_TO_INSTRUCTION(RESUME_QUICK); } @@ -1884,14 +1881,10 @@ dummy_func( } inst(JUMP_BACKWARD, (--)) { - JUMPBY(-oparg); - CHECK_EVAL_BREAKER(); if (cframe.use_tracing == 0) { - PyObject *retval = NULL; - if (_PyCode_Tier2Warmup(tstate, frame, throwflag, next_instr, stack_pointer, &retval)) { - return retval; - } + next_instr = _PyCode_Tier2Warmup(frame, next_instr); } + GO_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); } inst(JUMP_BACKWARD_QUICK, (--)) { diff --git a/Python/ceval.c b/Python/ceval.c index 6102f5d025edc9..a91f5baca8853e 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -706,7 +706,6 @@ static inline void _Py_LeaveRecursiveCallPy(PyThreadState *tstate) { # pragma warning(disable:4102) #endif -#undef TIER2_PROFILING PyObject* _Py_HOT_FUNCTION _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag) { @@ -1095,402 +1094,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int # pragma warning(pop) #endif -// CARBON-COPY of _PyEval_EvalFrameDefault. KEEP IN SYNC WITH THAT FUNCTION. -#define TIER2_PROFILING 1 -#undef INSTRUCTION_START -#undef TARGET -#undef GETITEM -#include "ceval_macros.h" -PyObject * -_PyEval_EvalFrameTier2Profile(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag, PyObject **old_stack_pointer) -{ - fprintf(stderr, "TIER2_PROFILING\n"); - _Py_EnsureTstateNotNULL(tstate); - CALL_STAT_INC(pyeval_calls); - -#if USE_COMPUTED_GOTOS - /* Import the static jump table */ -#include "opcode_targets.h" -#endif - -#ifdef Py_STATS - int lastopcode = 0; -#endif - // opcode is an 8-bit value to improve the code generated by MSVC - // for the big switch below (in combination with the EXTRA_CASES macro). - uint8_t opcode; /* Current opcode */ - int oparg; /* Current opcode argument, if any */ - _Py_atomic_int *const eval_breaker = &tstate->interp->ceval.eval_breaker; -#ifdef LLTRACE - int lltrace = 0; -#endif - - _PyCFrame cframe; - _PyInterpreterFrame entry_frame; - PyObject *kwnames = NULL; // Borrowed reference. Reset by CALL instructions. - - /* WARNING: Because the _PyCFrame lives on the C stack, - * but can be accessed from a heap allocated object (tstate) - * strict stack discipline must be maintained. - */ - _PyCFrame *prev_cframe = tstate->cframe; - cframe.use_tracing = prev_cframe->use_tracing; - cframe.previous = prev_cframe; - tstate->cframe = &cframe; - - assert(tstate->interp->interpreter_trampoline != NULL); -#ifdef Py_DEBUG - /* Set these to invalid but identifiable values for debugging. */ - entry_frame.f_funcobj = (PyObject *)0xaaa0; - entry_frame.f_locals = (PyObject *)0xaaa1; - entry_frame.frame_obj = (PyFrameObject *)0xaaa2; - entry_frame.f_globals = (PyObject *)0xaaa3; - entry_frame.f_builtins = (PyObject *)0xaaa4; -#endif - entry_frame.f_code = tstate->interp->interpreter_trampoline; - entry_frame.prev_instr = - _PyCode_CODE(tstate->interp->interpreter_trampoline); - entry_frame.stacktop = 0; - entry_frame.owner = FRAME_OWNED_BY_CSTACK; - entry_frame.yield_offset = 0; - /* Push frame */ - entry_frame.previous = prev_cframe->current_frame; - frame->previous = &entry_frame; - cframe.current_frame = frame; - - if (_Py_EnterRecursiveCallTstate(tstate, "")) { - tstate->c_recursion_remaining--; - tstate->py_recursion_remaining--; - goto exit_unwind; - } - - /* support for generator.throw() */ - if (throwflag) { - if (_Py_EnterRecursivePy(tstate)) { - goto exit_unwind; - } - TRACE_FUNCTION_THROW_ENTRY(); - DTRACE_FUNCTION_ENTRY(); - goto resume_with_error; - } - - /* Local "register" variables. - * These are cached values from the frame and code object. */ - - PyObject *names; - PyObject *consts; - _Py_CODEUNIT *next_instr; - PyObject **stack_pointer; - - /* Sets the above local variables from the frame */ -#define SET_LOCALS_FROM_FRAME() \ - { \ - PyCodeObject *co = frame->f_code; \ - names = co->co_names; \ - consts = co->co_consts; \ - } \ - assert(_PyInterpreterFrame_LASTI(frame) >= -1); \ - /* Jump back to the last instruction executed... */ \ - next_instr = frame->prev_instr + 1; \ - stack_pointer = _PyFrame_GetStackPointer(frame); \ - /* Set stackdepth to -1. \ - Update when returning or calling trace function. \ - Having stackdepth <= 0 ensures that invalid \ - values are not visible to the cycle GC. \ - We choose -1 rather than 0 to assist debugging. \ - */ \ - frame->stacktop = -1; - - -start_frame: - if (_Py_EnterRecursivePy(tstate)) { - goto exit_unwind; - } - -resume_frame: - SET_LOCALS_FROM_FRAME(); - -#ifdef LLTRACE - { - if (frame != &entry_frame) { - int r = PyDict_Contains(GLOBALS(), &_Py_ID(__lltrace__)); - if (r < 0) { - goto exit_unwind; - } - lltrace = r; - } - if (lltrace) { - lltrace_resume_frame(frame); - } - } -#endif - -#ifdef Py_DEBUG - /* _PyEval_EvalFrameDefault() must not be called with an exception set, - because it can clear it (directly or indirectly) and so the - caller loses its exception */ - assert(!_PyErr_Occurred(tstate)); -#endif - - DISPATCH(); - -handle_eval_breaker: - - /* Do periodic things, like check for signals and async I/0. - * We need to do reasonably frequently, but not too frequently. - * All loops should include a check of the eval breaker. - * We also check on return from any builtin function. - */ - if (_Py_HandlePending(tstate) != 0) { - goto error; - } - DISPATCH(); - - { - /* Start instructions */ -#if !USE_COMPUTED_GOTOS - dispatch_opcode : - switch (opcode) -#endif - { - -#include "generated_cases.c.h" - -#if USE_COMPUTED_GOTOS - TARGET_DO_TRACING : -#else - case DO_TRACING: -#endif - { - assert(cframe.use_tracing); - assert(tstate->tracing == 0); - if (INSTR_OFFSET() >= frame->f_code->_co_firsttraceable) { - int instr_prev = _PyInterpreterFrame_LASTI(frame); - frame->prev_instr = next_instr; - NEXTOPARG(); - // No _PyOpcode_Deopt here, since RESUME has no optimized forms: - if (opcode == RESUME) { - if (oparg < 2) { - CHECK_EVAL_BREAKER(); - } - /* Call tracing */ - TRACE_FUNCTION_ENTRY(); - DTRACE_FUNCTION_ENTRY(); - } - else { - /* line-by-line tracing support */ - if (PyDTrace_LINE_ENABLED()) { - maybe_dtrace_line(frame, &tstate->trace_info, instr_prev); - } - - if (cframe.use_tracing && - tstate->c_tracefunc != NULL && !tstate->tracing) { - int err; - /* see maybe_call_line_trace() - for expository comments */ - _PyFrame_SetStackPointer(frame, stack_pointer); - - err = maybe_call_line_trace(tstate->c_tracefunc, - tstate->c_traceobj, - tstate, frame, instr_prev); - // Reload possibly changed frame fields: - stack_pointer = _PyFrame_GetStackPointer(frame); - frame->stacktop = -1; - // next_instr is only reloaded if tracing *does not* raise. - // This is consistent with the behavior of older Python - // versions. If a trace function sets a new f_lineno and - // *then* raises, we use the *old* location when searching - // for an exception handler, displaying the traceback, and - // so on: - if (err) { - // next_instr wasn't incremented at the start of this - // instruction. Increment it before handling the error, - // so that it looks the same as a "normal" instruction: - next_instr++; - goto error; - } - // Reload next_instr. Don't increment it, though, since - // we're going to re-dispatch to the "true" instruction now: - next_instr = frame->prev_instr; - } - } - } - NEXTOPARG(); - PRE_DISPATCH_GOTO(); - // No _PyOpcode_Deopt here, since EXTENDED_ARG has no optimized forms: - while (opcode == EXTENDED_ARG) { - // CPython hasn't ever traced the instruction after an EXTENDED_ARG. - // Inline the EXTENDED_ARG here, so we can avoid branching there: - INSTRUCTION_START(EXTENDED_ARG); - opcode = _Py_OPCODE(*next_instr); - oparg = oparg << 8 | _Py_OPARG(*next_instr); - // Make sure the next instruction isn't a RESUME, since that needs - // to trace properly (and shouldn't have an EXTENDED_ARG, anyways): - assert(opcode != RESUME); - PRE_DISPATCH_GOTO(); - } - opcode = _PyOpcode_Deopt[opcode]; - if (_PyOpcode_Caches[opcode]) { - uint16_t *counter = &next_instr[1].cache; - // The instruction is going to decrement the counter, so we need to - // increment it here to make sure it doesn't try to specialize: - if (!ADAPTIVE_COUNTER_IS_MAX(*counter)) { - INCREMENT_ADAPTIVE_COUNTER(*counter); - } - } - DISPATCH_GOTO(); - } - -#if USE_COMPUTED_GOTOS - _unknown_opcode : -#else - EXTRA_CASES // From opcode.h, a 'case' for each unused opcode -#endif - /* Tell C compilers not to hold the opcode variable in the loop. - next_instr points the current instruction without TARGET(). */ - opcode = _Py_OPCODE(*next_instr); - _PyErr_Format(tstate, PyExc_SystemError, - "%U:%d: unknown opcode %d", - frame->f_code->co_filename, - _PyInterpreterFrame_GetLine(frame), - opcode); - goto error; - - } /* End instructions */ - - /* This should never be reached. Every opcode should end with DISPATCH() - or goto error. */ - Py_UNREACHABLE(); - - unbound_local_error: - { - format_exc_check_arg(tstate, PyExc_UnboundLocalError, - UNBOUNDLOCAL_ERROR_MSG, - PyTuple_GetItem(frame->f_code->co_localsplusnames, oparg) - ); - goto error; - } - - pop_4_error: - STACK_SHRINK(1); - pop_3_error: - STACK_SHRINK(1); - pop_2_error: - STACK_SHRINK(1); - pop_1_error: - STACK_SHRINK(1); - error: - kwnames = NULL; - /* Double-check exception status. */ -#ifdef NDEBUG - if (!_PyErr_Occurred(tstate)) { - _PyErr_SetString(tstate, PyExc_SystemError, - "error return without exception set"); - } -#else - assert(_PyErr_Occurred(tstate)); -#endif - - /* Log traceback info. */ - assert(frame != &entry_frame); - if (!_PyFrame_IsIncomplete(frame)) { - PyFrameObject *f = _PyFrame_GetFrameObject(frame); - if (f != NULL) { - PyTraceBack_Here(f); - } - } - - if (tstate->c_tracefunc != NULL) { - /* Make sure state is set to FRAME_UNWINDING for tracing */ - call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, - tstate, frame); - } - - exception_unwind: - { - /* We can't use frame->f_lasti here, as RERAISE may have set it */ - int offset = INSTR_OFFSET() - 1; - int level, handler, lasti; - if (get_exception_handler(frame->f_code, offset, &level, &handler, &lasti) == 0) { - // No handlers, so exit. - assert(_PyErr_Occurred(tstate)); - - /* Pop remaining stack entries. */ - PyObject **stackbase = _PyFrame_Stackbase(frame); - while (stack_pointer > stackbase) { - PyObject *o = POP(); - Py_XDECREF(o); - } - assert(STACK_LEVEL() == 0); - _PyFrame_SetStackPointer(frame, stack_pointer); - TRACE_FUNCTION_UNWIND(); - DTRACE_FUNCTION_EXIT(); - goto exit_unwind; - } - - assert(STACK_LEVEL() >= level); - PyObject **new_top = _PyFrame_Stackbase(frame) + level; - while (stack_pointer > new_top) { - PyObject *v = POP(); - Py_XDECREF(v); - } - PyObject *exc, *val, *tb; - if (lasti) { - int frame_lasti = _PyInterpreterFrame_LASTI(frame); - PyObject *lasti = PyLong_FromLong(frame_lasti); - if (lasti == NULL) { - goto exception_unwind; - } - PUSH(lasti); - } - _PyErr_Fetch(tstate, &exc, &val, &tb); - /* Make the raw exception data - available to the handler, - so a program can emulate the - Python main loop. */ - _PyErr_NormalizeException(tstate, &exc, &val, &tb); - if (tb != NULL) - PyException_SetTraceback(val, tb); - else - PyException_SetTraceback(val, Py_None); - Py_XDECREF(tb); - Py_XDECREF(exc); - PUSH(val); - JUMPTO(handler); - /* Resume normal execution */ - DISPATCH(); - } - } - -exit_unwind: - assert(_PyErr_Occurred(tstate)); - _Py_LeaveRecursiveCallPy(tstate); - assert(frame != &entry_frame); - // GH-99729: We need to unlink the frame *before* clearing it: - _PyInterpreterFrame *dying = frame; - frame = cframe.current_frame = dying->previous; - _PyEvalFrameClearAndPop(tstate, dying); - if (frame == &entry_frame) { - /* Restore previous cframe and exit */ - tstate->cframe = cframe.previous; - tstate->cframe->use_tracing = cframe.use_tracing; - assert(tstate->cframe->current_frame == frame->previous); - _Py_LeaveRecursiveCallTstate(tstate); - return NULL; - } - -resume_with_error: - SET_LOCALS_FROM_FRAME(); - goto error; - -} - -#undef TIER2_PROFILING -#undef INSTRUCTION_START -#undef TARGET -#undef GETITEM -#include "ceval_macros.h" - static void format_missing(PyThreadState *tstate, const char *kind, PyCodeObject *co, PyObject *names, PyObject *qualname) diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 1aa12383b748c6..7d601c71fde43b 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -47,10 +47,6 @@ #define OR_DTRACE_LINE #endif -#ifdef USE_COMPUTED_GOTOS - #undef USE_COMPUTED_GOTOS -#endif - #ifdef HAVE_COMPUTED_GOTOS #ifndef USE_COMPUTED_GOTOS #define USE_COMPUTED_GOTOS 1 @@ -63,56 +59,25 @@ #define USE_COMPUTED_GOTOS 0 #endif -#ifdef INSTRUCTION_START - #undef INSTRUCTION_START -#endif - -#ifndef TIER2_PROFILING - #ifdef Py_STATS - #define INSTRUCTION_START(op) \ - do { \ - frame->prev_instr = next_instr++; \ - OPCODE_EXE_INC(op); \ - if (_py_stats) _py_stats->opcode_stats[lastopcode].pair_count[op]++; \ - lastopcode = op; \ - } while (0) - #else - #define INSTRUCTION_START(op) (frame->prev_instr = next_instr++) - #endif +#ifdef Py_STATS +#define INSTRUCTION_START(op) \ + do { \ + frame->prev_instr = next_instr++; \ + OPCODE_EXE_INC(op); \ + if (_py_stats) _py_stats->opcode_stats[lastopcode].pair_count[op]++; \ + lastopcode = op; \ + } while (0) #else - #define INSTRUCTION_START(op) \ - do { \ - frame->prev_instr = next_instr++; \ - fprintf(stderr, "%d\n", op); \ - } while (0) -#endif /* TIER2_PROFILING */ - -#ifdef TARGET -#undef TARGET -#endif - -#ifdef DISPATCH_GOTO -#undef DISPATCH_GOTO +#define INSTRUCTION_START(op) (frame->prev_instr = next_instr++) #endif -#ifndef TIER2_PROFILING - #if USE_COMPUTED_GOTOS - # define TARGET(op) TARGET_##op: INSTRUCTION_START(op); - # define DISPATCH_GOTO() goto *opcode_targets[opcode] - #else - # define TARGET(op) case op: TARGET_##op: INSTRUCTION_START(op); - # define DISPATCH_GOTO() goto dispatch_opcode - #endif +#if USE_COMPUTED_GOTOS +# define TARGET(op) TARGET_##op: INSTRUCTION_START(op); +# define DISPATCH_GOTO() goto *opcode_targets[opcode] #else - #if USE_COMPUTED_GOTOS - # define TARGET(op) TARGET_TIER2_PROFILE_##op: INSTRUCTION_START(op); - # define DISPATCH_GOTO() goto *opcode_targets[opcode] - #else - # define TARGET(op) case op: TARGET_TIER2_PROFILE_##op: INSTRUCTION_START(op); - # define DISPATCH_GOTO() goto dispatch_opcode - #endif -#endif /* TIER2_PROFILING */ - +# define TARGET(op) case op: TARGET_##op: INSTRUCTION_START(op); +# define DISPATCH_GOTO() goto dispatch_opcode +#endif /* PRE_DISPATCH_GOTO() does lltrace if enabled. Normally a no-op */ #ifdef LLTRACE @@ -122,9 +87,6 @@ #define PRE_DISPATCH_GOTO() ((void)0) #endif -#ifdef DISPATCH -#undef DISPATCH -#endif /* Do interpreter dispatch accounting for tracing and instrumentation */ #define DISPATCH() \ @@ -136,10 +98,6 @@ DISPATCH_GOTO(); \ } -#ifdef DISPATCH_SAME_OPARG -#undef DISPATCH_SAME_OPARG -#endif - #define DISPATCH_SAME_OPARG() \ { \ opcode = _Py_OPCODE(*next_instr); \ @@ -148,10 +106,6 @@ DISPATCH_GOTO(); \ } -#ifdef DISPATCH_INLINED -#undef DISPATCH_INLINED -#endif - #define DISPATCH_INLINED(NEW_FRAME) \ do { \ _PyFrame_SetStackPointer(frame, stack_pointer); \ @@ -162,10 +116,6 @@ goto start_frame; \ } while (0) -#ifdef CHECK_EVAL_BREAKER -#undef CHECK_EVAL_BREAKER -#endif - #define CHECK_EVAL_BREAKER() \ _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); \ if (_Py_atomic_load_relaxed_int32(eval_breaker)) { \ @@ -175,12 +125,9 @@ /* Tuple access macros */ - #ifndef Py_DEBUG #define GETITEM(v, i) PyTuple_GET_ITEM((v), (i)) #else -#ifndef _GETITEM_DEF_H -#define _GETITEM_DEF_H static inline PyObject * GETITEM(PyObject *v, Py_ssize_t i) { assert(PyTuple_Check(v)); @@ -188,27 +135,10 @@ GETITEM(PyObject *v, Py_ssize_t i) { assert(i < PyTuple_GET_SIZE(v)); return PyTuple_GET_ITEM(v, i); } -#endif /* _GETITEM_DEF_H */ #endif /* Code access macros */ -#ifdef INSTR_OFFSET -#undef INSTR_OFFSET -#endif - -#ifdef NEXTOPARG -#undef NEXTOPARG -#endif - -#ifdef JUMPTO -#undef JUMPTO -#endif - -#ifdef JUMPBY -#undef JUMPBY -#endif - /* The integer overflow is checked by an assertion below. */ // TODO change this calculation when interpreter is bb aware. #define INSTR_OFFSET() ((int)(next_instr - _PyCode_CODE(frame->f_code))) @@ -246,23 +176,7 @@ GETITEM(PyObject *v, Py_ssize_t i) { */ -#ifdef PREDICT_ID -#undef PREDICT_ID -#endif - -#ifndef TIER2_PROFILING #define PREDICT_ID(op) PRED_##op -#else -#define PREDICT_ID(op) PRED_TIER2_PROFILING_##op -#endif - -#ifdef PREDICT -#undef PREDICT -#endif - -#ifdef PREDICTED -#undef PREDICTED -#endif #if USE_COMPUTED_GOTOS #define PREDICT(op) if (0) goto PREDICT_ID(op) @@ -337,7 +251,6 @@ GETITEM(PyObject *v, Py_ssize_t i) { GETLOCAL(i) = value; \ Py_XDECREF(tmp); } while (0) - #define GO_TO_INSTRUCTION(op) goto PREDICT_ID(op) #ifdef Py_STATS diff --git a/Python/compile.c b/Python/compile.c index df2dffb95bbd7e..bdc25ba9df9b4a 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1079,6 +1079,7 @@ stack_effect(int opcode, int oparg, int jump) case EXTENDED_ARG: case RESUME: case CACHE: + case BB_NEXT: return 0; /* Stack manipulation */ diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index ca6216218f03c2..605b9767417d3c 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -24,10 +24,7 @@ TARGET(RESUME) { if (cframe.use_tracing == 0) { - PyObject *retval = NULL; - if (_PyCode_Tier2Warmup(tstate, frame, throwflag, next_instr, stack_pointer, &retval)) { - return retval; - } + next_instr = _PyCode_Tier2Warmup(frame, next_instr); } GO_TO_INSTRUCTION(RESUME_QUICK); } @@ -2420,18 +2417,14 @@ TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - JUMPBY(-oparg); - CHECK_EVAL_BREAKER(); if (cframe.use_tracing == 0) { - PyObject *retval = NULL; - if (_PyCode_Tier2Warmup(tstate, frame, throwflag, next_instr, stack_pointer, &retval)) { - return retval; - } + next_instr = _PyCode_Tier2Warmup(frame, next_instr); } - DISPATCH(); + GO_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); } TARGET(JUMP_BACKWARD_QUICK) { + PREDICTED(JUMP_BACKWARD_QUICK); assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); CHECK_EVAL_BREAKER(); diff --git a/Python/tier2.c b/Python/tier2.c index ddb82526d7e719..a5a2ebc569eb0d 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -1,22 +1,16 @@ #include "Python.h" #include "pycore_code.h" #include "pycore_frame.h" -#include "pycore_interp.h" #include "opcode.h" -#include "pystate.h" -#include "pytypedefs.h" static _Py_CODEUNIT * _PyCode_Tier2Initialize(_PyInterpreterFrame *, _Py_CODEUNIT *); // Tier 2 warmup counter -int -_PyCode_Tier2Warmup(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag, _Py_CODEUNIT *next_instr, PyObject **stack_pointer, PyObject **retval) +_Py_CODEUNIT * +_PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) { - if (tstate->interp->eval_frame != NULL) { - return 0; - } PyCodeObject *code = frame->f_code; if (code->_tier2_warmup != 0) { code->_tier2_warmup++; @@ -24,22 +18,15 @@ _PyCode_Tier2Warmup(PyThreadState *tstate, _PyInterpreterFrame *frame, int throw // If it fails, due to lack of memory or whatever, // just fall back to the tier 1 interpreter. _Py_CODEUNIT *next = _PyCode_Tier2Initialize(frame, next_instr); - // Swap out the profiler to use the profiling eval loop. - frame->prev_instr = next_instr - 1; - _PyFrame_SetStackPointer(frame, stack_pointer); - // Do something with entry_frame here, maybe set the current frame to an entry - // frame and check for that in RETURN_VALUE? - *retval = _PyEval_EvalFrameTier2Profile(tstate, frame, throwflag); - PyObject_Print(*retval, stderr, Py_PRINT_RAW); - return 1; - + if (next != NULL) { + return next; + } } } - return 0; + return next_instr; } - static _PyTier2BBSpace * _PyTier2_CreateBBSpace(Py_ssize_t space_to_alloc) { @@ -70,6 +57,7 @@ static _Py_CODEUNIT * _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) { int curr = _Py_OPCODE(*(next_instr - 1)); + assert(curr == RESUME || curr == JUMP_BACKWARD); PyCodeObject *co = frame->f_code; assert(co->_bb_space == NULL); // 1. Initialize basic blocks space. From 46ee564fa9cfe4ff5d0eb97377fa0d1885562bcb Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 10 Feb 2023 21:18:28 +0800 Subject: [PATCH 020/280] Add functionality to detect BB from code objects --- Include/cpython/code.h | 13 +- Include/internal/pycore_frame.h | 3 +- Include/internal/pycore_opcode.h | 40 +-- .../internal/pycore_opcode_macro_to_micro.h | 2 +- Include/opcode.h | 250 +++++++++--------- Lib/opcode.py | 3 - Objects/codeobject.c | 16 +- Python/bytecodes.c | 7 - Python/compile.c | 1 - Python/generated_cases.c.h | 8 - Python/opcode_metadata.h | 17 +- Python/opcode_targets.h | 38 +-- Python/tier2.c | 225 +++++++++++++--- Tools/build/deepfreeze.py | 4 +- 14 files changed, 395 insertions(+), 232 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index f71a4a679e9098..9d6c29eee27a7e 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -45,10 +45,10 @@ typedef struct { // What the tier 2 interpreter executes typedef struct _PyTier2BB { - // Stores the start pointer in the tier 1 bytecode. - // So that when we exit the trace we can calculate where to return. - struct _PyTier2BB *bb_next; - _Py_CODEUNIT *tier1_start; + struct _PyTier2BB *successor_bb; + // Stores the end pointer in the tier 1 bytecode. + // So that when we exit the BB we can calculate where to return. + _Py_CODEUNIT *tier1_end; _Py_CODEUNIT u_code[1]; } _PyTier2BB; @@ -122,8 +122,11 @@ typedef struct _PyTier2BBSpace { int _co_firsttraceable; /* index of first traceable instruction */ \ char *_co_linearray; /* array of line offsets */ \ int _tier2_warmup; /* warmup counter for tier 2 */ \ - _PyTier2BB *_bb_next; /* the tier 2 basic block to execute (if any) */ \ + _PyTier2BB *_entry_bb; /* the tier 2 basic block to execute (if any) */ \ _PyTier2BBSpace *_bb_space; /* linked list storing basic blocks */ \ + int _jump_target_count; /* Number of entries in _jump_targets */ \ + /* sorted ascending offsets (from start of co_code_adaptive) for jump targets */ \ + int *_jump_targets; \ /* Scratch space for extra data relating to the code object. \ Type is a void* to keep the format private in codeobject.c to force \ people to go through the proper APIs. */ \ diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 1aff2dc6a6d065..ce87e2a428d8f0 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -121,7 +121,8 @@ _PyFrame_Initialize( frame->f_locals = locals; frame->stacktop = code->co_nlocalsplus; frame->frame_obj = NULL; - frame->prev_instr = (code->_bb_next == NULL ? _PyCode_CODE(code) - 1 : code->_bb_next->u_code - 1); + // @TODO CHANGE ME + frame->prev_instr = _PyCode_CODE(code); frame->yield_offset = 0; frame->owner = FRAME_OWNED_BY_THREAD; diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index a2a87853c6e128..eee13ed8962825 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -140,7 +140,6 @@ const uint8_t _PyOpcode_Deopt[256] = { [IS_OP] = IS_OP, [JUMP_BACKWARD] = JUMP_BACKWARD, [JUMP_BACKWARD_NO_INTERRUPT] = JUMP_BACKWARD_NO_INTERRUPT, - [JUMP_BACKWARD_QUICK] = JUMP_BACKWARD, [JUMP_FORWARD] = JUMP_FORWARD, [JUMP_IF_FALSE_OR_POP] = JUMP_IF_FALSE_OR_POP, [JUMP_IF_TRUE_OR_POP] = JUMP_IF_TRUE_OR_POP, @@ -237,17 +236,16 @@ static const char *const _PyOpcode_OpName[263] = { [INTERPRETER_EXIT] = "INTERPRETER_EXIT", [END_FOR] = "END_FOR", [RESUME_QUICK] = "RESUME_QUICK", - [JUMP_BACKWARD_QUICK] = "JUMP_BACKWARD_QUICK", [BINARY_OP_ADD_FLOAT] = "BINARY_OP_ADD_FLOAT", [BINARY_OP_ADD_INT] = "BINARY_OP_ADD_INT", - [NOP] = "NOP", [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE", + [NOP] = "NOP", + [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", [UNARY_NEGATIVE] = "UNARY_NEGATIVE", [UNARY_NOT] = "UNARY_NOT", - [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT", - [UNARY_INVERT] = "UNARY_INVERT", [BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT", + [UNARY_INVERT] = "UNARY_INVERT", [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT", [BINARY_OP_SUBTRACT_INT] = "BINARY_OP_SUBTRACT_INT", [BINARY_SUBSCR_DICT] = "BINARY_SUBSCR_DICT", @@ -256,20 +254,20 @@ static const char *const _PyOpcode_OpName[263] = { [BINARY_SUBSCR_TUPLE_INT] = "BINARY_SUBSCR_TUPLE_INT", [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS", [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", + [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", [BINARY_SUBSCR] = "BINARY_SUBSCR", [BINARY_SLICE] = "BINARY_SLICE", [STORE_SLICE] = "STORE_SLICE", - [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", [GET_LEN] = "GET_LEN", [MATCH_MAPPING] = "MATCH_MAPPING", [MATCH_SEQUENCE] = "MATCH_SEQUENCE", [MATCH_KEYS] = "MATCH_KEYS", - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", [PUSH_EXC_INFO] = "PUSH_EXC_INFO", [CHECK_EXC_MATCH] = "CHECK_EXC_MATCH", [CHECK_EG_MATCH] = "CHECK_EG_MATCH", - [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", [CALL_NO_KW_BUILTIN_O] = "CALL_NO_KW_BUILTIN_O", [CALL_NO_KW_ISINSTANCE] = "CALL_NO_KW_ISINSTANCE", @@ -280,6 +278,7 @@ static const char *const _PyOpcode_OpName[263] = { [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", + [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", [WITH_EXCEPT_START] = "WITH_EXCEPT_START", [GET_AITER] = "GET_AITER", [GET_ANEXT] = "GET_ANEXT", @@ -287,38 +286,38 @@ static const char *const _PyOpcode_OpName[263] = { [BEFORE_WITH] = "BEFORE_WITH", [END_ASYNC_FOR] = "END_ASYNC_FOR", [CLEANUP_THROW] = "CLEANUP_THROW", - [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", [COMPARE_AND_BRANCH_FLOAT] = "COMPARE_AND_BRANCH_FLOAT", [COMPARE_AND_BRANCH_INT] = "COMPARE_AND_BRANCH_INT", [COMPARE_AND_BRANCH_STR] = "COMPARE_AND_BRANCH_STR", + [FOR_ITER_LIST] = "FOR_ITER_LIST", [STORE_SUBSCR] = "STORE_SUBSCR", [DELETE_SUBSCR] = "DELETE_SUBSCR", - [FOR_ITER_LIST] = "FOR_ITER_LIST", [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", [FOR_ITER_RANGE] = "FOR_ITER_RANGE", [FOR_ITER_GEN] = "FOR_ITER_GEN", [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", + [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", [GET_ITER] = "GET_ITER", [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", - [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", - [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", + [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", + [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", [RETURN_GENERATOR] = "RETURN_GENERATOR", - [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", - [RETURN_VALUE] = "RETURN_VALUE", [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", - [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", + [RETURN_VALUE] = "RETURN_VALUE", [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", + [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", + [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", [PREP_RERAISE_STAR] = "PREP_RERAISE_STAR", [POP_EXCEPT] = "POP_EXCEPT", [STORE_NAME] = "STORE_NAME", @@ -344,7 +343,7 @@ static const char *const _PyOpcode_OpName[263] = { [JUMP_FORWARD] = "JUMP_FORWARD", [JUMP_IF_FALSE_OR_POP] = "JUMP_IF_FALSE_OR_POP", [JUMP_IF_TRUE_OR_POP] = "JUMP_IF_TRUE_OR_POP", - [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", + [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -374,7 +373,7 @@ static const char *const _PyOpcode_OpName[263] = { [JUMP_BACKWARD] = "JUMP_BACKWARD", [COMPARE_AND_BRANCH] = "COMPARE_AND_BRANCH", [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", - [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", + [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -384,23 +383,23 @@ static const char *const _PyOpcode_OpName[263] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", - [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", + [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", - [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", + [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", - [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", [BINARY_OP_ADD_INT_TYPE_CHECK] = "BINARY_OP_ADD_INT_TYPE_CHECK", [BINARY_OP_ADD_INT_REST] = "BINARY_OP_ADD_INT_REST", + [169] = "<169>", [170] = "<170>", [CALL] = "CALL", [KW_NAMES] = "KW_NAMES", @@ -499,6 +498,7 @@ static const char *const _PyOpcode_OpName[263] = { #define EXTRA_CASES \ + case 169: \ case 170: \ case 174: \ case 175: \ diff --git a/Include/internal/pycore_opcode_macro_to_micro.h b/Include/internal/pycore_opcode_macro_to_micro.h index 13d681be4afa83..bffa49d3ceefcb 100644 --- a/Include/internal/pycore_opcode_macro_to_micro.h +++ b/Include/internal/pycore_opcode_macro_to_micro.h @@ -54,6 +54,7 @@ extern const int _Py_MacroOpUOpCount[] = { [RAISE_VARARGS] = 1, [INTERPRETER_EXIT] = 1, [RETURN_VALUE] = 1, +[RETURN_CONST] = 1, [GET_AITER] = 1, [GET_ANEXT] = 1, [GET_AWAITABLE] = 1, @@ -124,7 +125,6 @@ extern const int _Py_MacroOpUOpCount[] = { [IMPORT_FROM] = 1, [JUMP_FORWARD] = 1, [JUMP_BACKWARD] = 1, -[JUMP_BACKWARD_QUICK] = 1, [POP_JUMP_IF_FALSE] = 1, [POP_JUMP_IF_TRUE] = 1, [POP_JUMP_IF_NOT_NONE] = 1, diff --git a/Include/opcode.h b/Include/opcode.h index 91662127552c56..b89441dc98e835 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -127,136 +127,134 @@ extern "C" { #define LOAD_METHOD 262 #define MAX_PSEUDO_OPCODE 262 #define RESUME_QUICK 5 -#define JUMP_BACKWARD_QUICK 6 -#define BINARY_OP_ADD_FLOAT 7 -#define BINARY_OP_ADD_INT 8 -#define BINARY_OP_ADD_UNICODE 10 -#define BINARY_OP_INPLACE_ADD_UNICODE 13 -#define BINARY_OP_MULTIPLY_FLOAT 14 -#define BINARY_OP_MULTIPLY_INT 16 -#define BINARY_OP_SUBTRACT_FLOAT 17 -#define BINARY_OP_SUBTRACT_INT 18 -#define BINARY_SUBSCR_DICT 19 -#define BINARY_SUBSCR_GETITEM 20 -#define BINARY_SUBSCR_LIST_INT 21 -#define BINARY_SUBSCR_TUPLE_INT 22 -#define CALL_PY_EXACT_ARGS 23 -#define CALL_PY_WITH_DEFAULTS 24 -#define CALL_BOUND_METHOD_EXACT_ARGS 28 -#define CALL_BUILTIN_CLASS 29 -#define CALL_BUILTIN_FAST_WITH_KEYWORDS 34 -#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 38 -#define CALL_NO_KW_BUILTIN_FAST 39 -#define CALL_NO_KW_BUILTIN_O 40 -#define CALL_NO_KW_ISINSTANCE 41 -#define CALL_NO_KW_LEN 42 -#define CALL_NO_KW_LIST_APPEND 43 -#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 44 -#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 45 -#define CALL_NO_KW_METHOD_DESCRIPTOR_O 46 -#define CALL_NO_KW_STR_1 47 -#define CALL_NO_KW_TUPLE_1 48 -#define CALL_NO_KW_TYPE_1 56 -#define COMPARE_AND_BRANCH_FLOAT 57 -#define COMPARE_AND_BRANCH_INT 58 -#define COMPARE_AND_BRANCH_STR 59 -#define FOR_ITER_LIST 62 -#define FOR_ITER_TUPLE 63 -#define FOR_ITER_RANGE 64 -#define FOR_ITER_GEN 65 -#define LOAD_ATTR_CLASS 66 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 67 -#define LOAD_ATTR_INSTANCE_VALUE 70 -#define LOAD_ATTR_MODULE 72 -#define LOAD_ATTR_PROPERTY 73 -#define LOAD_ATTR_SLOT 76 -#define LOAD_ATTR_WITH_HINT 77 -#define LOAD_ATTR_METHOD_LAZY_DICT 78 -#define LOAD_ATTR_METHOD_NO_DICT 79 -#define LOAD_ATTR_METHOD_WITH_VALUES 80 -#define LOAD_CONST__LOAD_FAST 81 -#define LOAD_FAST__LOAD_CONST 82 -#define LOAD_FAST__LOAD_FAST 84 -#define LOAD_GLOBAL_BUILTIN 86 -#define LOAD_GLOBAL_MODULE 87 -#define STORE_ATTR_INSTANCE_VALUE 113 -#define STORE_ATTR_SLOT 143 -#define STORE_ATTR_WITH_HINT 153 -#define STORE_FAST__LOAD_FAST 154 -#define STORE_FAST__STORE_FAST 158 -#define STORE_SUBSCR_DICT 159 -#define STORE_SUBSCR_LIST_INT 160 -#define UNPACK_SEQUENCE_LIST 161 -#define UNPACK_SEQUENCE_TUPLE 166 -#define UNPACK_SEQUENCE_TWO_TUPLE 167 +#define BINARY_OP_ADD_FLOAT 6 +#define BINARY_OP_ADD_INT 7 +#define BINARY_OP_ADD_UNICODE 8 +#define BINARY_OP_INPLACE_ADD_UNICODE 10 +#define BINARY_OP_MULTIPLY_FLOAT 13 +#define BINARY_OP_MULTIPLY_INT 14 +#define BINARY_OP_SUBTRACT_FLOAT 16 +#define BINARY_OP_SUBTRACT_INT 17 +#define BINARY_SUBSCR_DICT 18 +#define BINARY_SUBSCR_GETITEM 19 +#define BINARY_SUBSCR_LIST_INT 20 +#define BINARY_SUBSCR_TUPLE_INT 21 +#define CALL_PY_EXACT_ARGS 22 +#define CALL_PY_WITH_DEFAULTS 23 +#define CALL_BOUND_METHOD_EXACT_ARGS 24 +#define CALL_BUILTIN_CLASS 28 +#define CALL_BUILTIN_FAST_WITH_KEYWORDS 29 +#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 34 +#define CALL_NO_KW_BUILTIN_FAST 38 +#define CALL_NO_KW_BUILTIN_O 39 +#define CALL_NO_KW_ISINSTANCE 40 +#define CALL_NO_KW_LEN 41 +#define CALL_NO_KW_LIST_APPEND 42 +#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 43 +#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 44 +#define CALL_NO_KW_METHOD_DESCRIPTOR_O 45 +#define CALL_NO_KW_STR_1 46 +#define CALL_NO_KW_TUPLE_1 47 +#define CALL_NO_KW_TYPE_1 48 +#define COMPARE_AND_BRANCH_FLOAT 56 +#define COMPARE_AND_BRANCH_INT 57 +#define COMPARE_AND_BRANCH_STR 58 +#define FOR_ITER_LIST 59 +#define FOR_ITER_TUPLE 62 +#define FOR_ITER_RANGE 63 +#define FOR_ITER_GEN 64 +#define LOAD_ATTR_CLASS 65 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 66 +#define LOAD_ATTR_INSTANCE_VALUE 67 +#define LOAD_ATTR_MODULE 70 +#define LOAD_ATTR_PROPERTY 72 +#define LOAD_ATTR_SLOT 73 +#define LOAD_ATTR_WITH_HINT 76 +#define LOAD_ATTR_METHOD_LAZY_DICT 77 +#define LOAD_ATTR_METHOD_NO_DICT 78 +#define LOAD_ATTR_METHOD_WITH_VALUES 79 +#define LOAD_CONST__LOAD_FAST 80 +#define LOAD_FAST__LOAD_CONST 81 +#define LOAD_FAST__LOAD_FAST 82 +#define LOAD_GLOBAL_BUILTIN 84 +#define LOAD_GLOBAL_MODULE 86 +#define STORE_ATTR_INSTANCE_VALUE 87 +#define STORE_ATTR_SLOT 113 +#define STORE_ATTR_WITH_HINT 143 +#define STORE_FAST__LOAD_FAST 153 +#define STORE_FAST__STORE_FAST 154 +#define STORE_SUBSCR_DICT 158 +#define STORE_SUBSCR_LIST_INT 159 +#define UNPACK_SEQUENCE_LIST 160 +#define UNPACK_SEQUENCE_TUPLE 161 +#define UNPACK_SEQUENCE_TWO_TUPLE 166 #define DO_TRACING 255 // Tier 2 interpreter ops #define RESUME_QUICK 5 -#define JUMP_BACKWARD_QUICK 6 -#define BINARY_OP_ADD_FLOAT 7 -#define BINARY_OP_ADD_INT 8 -#define BINARY_OP_ADD_UNICODE 10 -#define BINARY_OP_INPLACE_ADD_UNICODE 13 -#define BINARY_OP_MULTIPLY_FLOAT 14 -#define BINARY_OP_MULTIPLY_INT 16 -#define BINARY_OP_SUBTRACT_FLOAT 17 -#define BINARY_OP_SUBTRACT_INT 18 -#define BINARY_SUBSCR_DICT 19 -#define BINARY_SUBSCR_GETITEM 20 -#define BINARY_SUBSCR_LIST_INT 21 -#define BINARY_SUBSCR_TUPLE_INT 22 -#define CALL_PY_EXACT_ARGS 23 -#define CALL_PY_WITH_DEFAULTS 24 -#define CALL_BOUND_METHOD_EXACT_ARGS 28 -#define CALL_BUILTIN_CLASS 29 -#define CALL_BUILTIN_FAST_WITH_KEYWORDS 34 -#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 38 -#define CALL_NO_KW_BUILTIN_FAST 39 -#define CALL_NO_KW_BUILTIN_O 40 -#define CALL_NO_KW_ISINSTANCE 41 -#define CALL_NO_KW_LEN 42 -#define CALL_NO_KW_LIST_APPEND 43 -#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 44 -#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 45 -#define CALL_NO_KW_METHOD_DESCRIPTOR_O 46 -#define CALL_NO_KW_STR_1 47 -#define CALL_NO_KW_TUPLE_1 48 -#define CALL_NO_KW_TYPE_1 56 -#define COMPARE_AND_BRANCH_FLOAT 57 -#define COMPARE_AND_BRANCH_INT 58 -#define COMPARE_AND_BRANCH_STR 59 -#define FOR_ITER_LIST 62 -#define FOR_ITER_TUPLE 63 -#define FOR_ITER_RANGE 64 -#define FOR_ITER_GEN 65 -#define LOAD_ATTR_CLASS 66 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 67 -#define LOAD_ATTR_INSTANCE_VALUE 70 -#define LOAD_ATTR_MODULE 72 -#define LOAD_ATTR_PROPERTY 73 -#define LOAD_ATTR_SLOT 76 -#define LOAD_ATTR_WITH_HINT 77 -#define LOAD_ATTR_METHOD_LAZY_DICT 78 -#define LOAD_ATTR_METHOD_NO_DICT 79 -#define LOAD_ATTR_METHOD_WITH_VALUES 80 -#define LOAD_CONST__LOAD_FAST 81 -#define LOAD_FAST__LOAD_CONST 82 -#define LOAD_FAST__LOAD_FAST 84 -#define LOAD_GLOBAL_BUILTIN 86 -#define LOAD_GLOBAL_MODULE 87 -#define STORE_ATTR_INSTANCE_VALUE 113 -#define STORE_ATTR_SLOT 143 -#define STORE_ATTR_WITH_HINT 153 -#define STORE_FAST__LOAD_FAST 154 -#define STORE_FAST__STORE_FAST 158 -#define STORE_SUBSCR_DICT 159 -#define STORE_SUBSCR_LIST_INT 160 -#define UNPACK_SEQUENCE_LIST 161 -#define UNPACK_SEQUENCE_TUPLE 166 -#define UNPACK_SEQUENCE_TWO_TUPLE 167 +#define BINARY_OP_ADD_FLOAT 6 +#define BINARY_OP_ADD_INT 7 +#define BINARY_OP_ADD_UNICODE 8 +#define BINARY_OP_INPLACE_ADD_UNICODE 10 +#define BINARY_OP_MULTIPLY_FLOAT 13 +#define BINARY_OP_MULTIPLY_INT 14 +#define BINARY_OP_SUBTRACT_FLOAT 16 +#define BINARY_OP_SUBTRACT_INT 17 +#define BINARY_SUBSCR_DICT 18 +#define BINARY_SUBSCR_GETITEM 19 +#define BINARY_SUBSCR_LIST_INT 20 +#define BINARY_SUBSCR_TUPLE_INT 21 +#define CALL_PY_EXACT_ARGS 22 +#define CALL_PY_WITH_DEFAULTS 23 +#define CALL_BOUND_METHOD_EXACT_ARGS 24 +#define CALL_BUILTIN_CLASS 28 +#define CALL_BUILTIN_FAST_WITH_KEYWORDS 29 +#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 34 +#define CALL_NO_KW_BUILTIN_FAST 38 +#define CALL_NO_KW_BUILTIN_O 39 +#define CALL_NO_KW_ISINSTANCE 40 +#define CALL_NO_KW_LEN 41 +#define CALL_NO_KW_LIST_APPEND 42 +#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 43 +#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 44 +#define CALL_NO_KW_METHOD_DESCRIPTOR_O 45 +#define CALL_NO_KW_STR_1 46 +#define CALL_NO_KW_TUPLE_1 47 +#define CALL_NO_KW_TYPE_1 48 +#define COMPARE_AND_BRANCH_FLOAT 56 +#define COMPARE_AND_BRANCH_INT 57 +#define COMPARE_AND_BRANCH_STR 58 +#define FOR_ITER_LIST 59 +#define FOR_ITER_TUPLE 62 +#define FOR_ITER_RANGE 63 +#define FOR_ITER_GEN 64 +#define LOAD_ATTR_CLASS 65 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 66 +#define LOAD_ATTR_INSTANCE_VALUE 67 +#define LOAD_ATTR_MODULE 70 +#define LOAD_ATTR_PROPERTY 72 +#define LOAD_ATTR_SLOT 73 +#define LOAD_ATTR_WITH_HINT 76 +#define LOAD_ATTR_METHOD_LAZY_DICT 77 +#define LOAD_ATTR_METHOD_NO_DICT 78 +#define LOAD_ATTR_METHOD_WITH_VALUES 79 +#define LOAD_CONST__LOAD_FAST 80 +#define LOAD_FAST__LOAD_CONST 81 +#define LOAD_FAST__LOAD_FAST 82 +#define LOAD_GLOBAL_BUILTIN 84 +#define LOAD_GLOBAL_MODULE 86 +#define STORE_ATTR_INSTANCE_VALUE 87 +#define STORE_ATTR_SLOT 113 +#define STORE_ATTR_WITH_HINT 143 +#define STORE_FAST__LOAD_FAST 153 +#define STORE_FAST__STORE_FAST 154 +#define STORE_SUBSCR_DICT 158 +#define STORE_SUBSCR_LIST_INT 159 +#define UNPACK_SEQUENCE_LIST 160 +#define UNPACK_SEQUENCE_TUPLE 161 +#define UNPACK_SEQUENCE_TWO_TUPLE 166 #define DO_TRACING 255 -#define BINARY_OP_ADD_INT_TYPE_CHECK 168 -#define BINARY_OP_ADD_INT_REST 169 +#define BINARY_OP_ADD_INT_TYPE_CHECK 167 +#define BINARY_OP_ADD_INT_REST 168 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/opcode.py b/Lib/opcode.py index afb1e4713a2718..a12b6568dace4d 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -284,9 +284,6 @@ def pseudo_op(name, op, real_ops): "RESUME": [ "RESUME_QUICK", ], - "JUMP_BACKWARD": [ - "JUMP_BACKWARD_QUICK", - ], "BINARY_OP": [ "BINARY_OP_ADD_FLOAT", "BINARY_OP_ADD_INT", diff --git a/Objects/codeobject.c b/Objects/codeobject.c index ba3c7bdce5a772..db3a7b6970bd31 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -410,8 +410,10 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con) co->_co_linearray_entry_size = 0; co->_co_linearray = NULL; co->_tier2_warmup = -64; - co->_bb_next = NULL; + co->_entry_bb = NULL; co->_bb_space = NULL; + co->_jump_target_count = 0; + co->_jump_targets = NULL; memcpy(_PyCode_CODE(co), PyBytes_AS_STRING(con->code), PyBytes_GET_SIZE(con->code)); int entry_point = 0; @@ -1708,7 +1710,8 @@ code_dealloc(PyCodeObject *co) if (co->_co_linearray) { PyMem_Free(co->_co_linearray); } - co->_bb_next = NULL; + co->_entry_bb = NULL; + co->_jump_target_count = 0; if (co->_bb_space != NULL) { // Traverse the linked list for (_PyTier2BBSpace *curr = co->_bb_space; curr != NULL;) { @@ -1718,6 +1721,9 @@ code_dealloc(PyCodeObject *co) } co->_bb_space = NULL; } + if (co->_jump_targets != NULL) { + PyMem_Free(co->_jump_targets); + } PyObject_Free(co); } @@ -2295,7 +2301,8 @@ _PyStaticCode_Fini(PyCodeObject *co) PyMem_Free(co->_co_cached); co->_co_cached = NULL; } - co->_bb_next = NULL; + co->_entry_bb = NULL; + co->_jump_target_count = 0; if (co->_bb_space != NULL) { // Traverse the linked list for (_PyTier2BBSpace *curr = co->_bb_space; curr != NULL;) { @@ -2305,6 +2312,9 @@ _PyStaticCode_Fini(PyCodeObject *co) } co->_bb_space = NULL; } + if (co->_jump_targets != NULL) { + PyMem_Free(co->_jump_targets); + } co->co_extra = NULL; if (co->co_weakreflist != NULL) { PyObject_ClearWeakRefs((PyObject *)co); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index c310802d577507..200708b67a46ac 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1881,13 +1881,6 @@ dummy_func( } inst(JUMP_BACKWARD, (--)) { - if (cframe.use_tracing == 0) { - next_instr = _PyCode_Tier2Warmup(frame, next_instr); - } - GO_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); - } - - inst(JUMP_BACKWARD_QUICK, (--)) { assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); CHECK_EVAL_BREAKER(); diff --git a/Python/compile.c b/Python/compile.c index bdc25ba9df9b4a..df2dffb95bbd7e 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1079,7 +1079,6 @@ stack_effect(int opcode, int oparg, int jump) case EXTENDED_ARG: case RESUME: case CACHE: - case BB_NEXT: return 0; /* Stack manipulation */ diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 605b9767417d3c..a93b444476b450 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2417,14 +2417,6 @@ TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); - if (cframe.use_tracing == 0) { - next_instr = _PyCode_Tier2Warmup(frame, next_instr); - } - GO_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); - } - - TARGET(JUMP_BACKWARD_QUICK) { - PREDICTED(JUMP_BACKWARD_QUICK); assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); CHECK_EVAL_BREAKER(); diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index de7be63ac6aeac..6551cd7807f128 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -10,6 +10,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 0; case RESUME: return 0; + case RESUME_QUICK: + return 0; case LOAD_CLOSURE: return 0; case LOAD_FAST_CHECK: @@ -56,12 +58,12 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 2; case BINARY_OP_ADD_FLOAT: return 2; + case BINARY_OP_ADD_INT: + return 2; case BINARY_OP_ADD_INT_TYPE_CHECK: return 2; case BINARY_OP_ADD_INT_REST: return 2; - case BINARY_OP_ADD_INT: - return 2; case BINARY_SUBSCR: return 2; case BINARY_SLICE: @@ -362,6 +364,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case RESUME: return 0; + case RESUME_QUICK: + return 0; case LOAD_CLOSURE: return 1; case LOAD_FAST_CHECK: @@ -408,12 +412,12 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case BINARY_OP_ADD_FLOAT: return 1; + case BINARY_OP_ADD_INT: + return 1; case BINARY_OP_ADD_INT_TYPE_CHECK: return 2; case BINARY_OP_ADD_INT_REST: return 1; - case BINARY_OP_ADD_INT: - return 1; case BINARY_SUBSCR: return 1; case BINARY_SLICE: @@ -715,7 +719,8 @@ struct opcode_metadata { enum InstructionFormat instr_format; } _PyOpcode_opcode_metadata[256] = { [NOP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [RESUME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [RESUME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [RESUME_QUICK] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [LOAD_CLOSURE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [LOAD_FAST_CHECK] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, @@ -740,6 +745,8 @@ struct opcode_metadata { [BINARY_OP_INPLACE_ADD_UNICODE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [BINARY_OP_ADD_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, [BINARY_OP_ADD_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, + [BINARY_OP_ADD_INT_TYPE_CHECK] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [BINARY_OP_ADD_INT_REST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [BINARY_SUBSCR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, [BINARY_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [STORE_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 839778d38beca9..1ec5cbbb9a0e4b 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -5,17 +5,16 @@ static void *opcode_targets[256] = { &&TARGET_INTERPRETER_EXIT, &&TARGET_END_FOR, &&TARGET_RESUME_QUICK, - &&TARGET_JUMP_BACKWARD_QUICK, &&TARGET_BINARY_OP_ADD_FLOAT, &&TARGET_BINARY_OP_ADD_INT, - &&TARGET_NOP, &&TARGET_BINARY_OP_ADD_UNICODE, + &&TARGET_NOP, + &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, &&TARGET_UNARY_NEGATIVE, &&TARGET_UNARY_NOT, - &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, &&TARGET_BINARY_OP_MULTIPLY_FLOAT, - &&TARGET_UNARY_INVERT, &&TARGET_BINARY_OP_MULTIPLY_INT, + &&TARGET_UNARY_INVERT, &&TARGET_BINARY_OP_SUBTRACT_FLOAT, &&TARGET_BINARY_OP_SUBTRACT_INT, &&TARGET_BINARY_SUBSCR_DICT, @@ -24,20 +23,20 @@ static void *opcode_targets[256] = { &&TARGET_BINARY_SUBSCR_TUPLE_INT, &&TARGET_CALL_PY_EXACT_ARGS, &&TARGET_CALL_PY_WITH_DEFAULTS, + &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, &&TARGET_BINARY_SUBSCR, &&TARGET_BINARY_SLICE, &&TARGET_STORE_SLICE, - &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, &&TARGET_CALL_BUILTIN_CLASS, + &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, &&TARGET_GET_LEN, &&TARGET_MATCH_MAPPING, &&TARGET_MATCH_SEQUENCE, &&TARGET_MATCH_KEYS, - &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, + &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, &&TARGET_PUSH_EXC_INFO, &&TARGET_CHECK_EXC_MATCH, &&TARGET_CHECK_EG_MATCH, - &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, &&TARGET_CALL_NO_KW_BUILTIN_FAST, &&TARGET_CALL_NO_KW_BUILTIN_O, &&TARGET_CALL_NO_KW_ISINSTANCE, @@ -48,6 +47,7 @@ static void *opcode_targets[256] = { &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, &&TARGET_CALL_NO_KW_STR_1, &&TARGET_CALL_NO_KW_TUPLE_1, + &&TARGET_CALL_NO_KW_TYPE_1, &&TARGET_WITH_EXCEPT_START, &&TARGET_GET_AITER, &&TARGET_GET_ANEXT, @@ -55,38 +55,38 @@ static void *opcode_targets[256] = { &&TARGET_BEFORE_WITH, &&TARGET_END_ASYNC_FOR, &&TARGET_CLEANUP_THROW, - &&TARGET_CALL_NO_KW_TYPE_1, &&TARGET_COMPARE_AND_BRANCH_FLOAT, &&TARGET_COMPARE_AND_BRANCH_INT, &&TARGET_COMPARE_AND_BRANCH_STR, + &&TARGET_FOR_ITER_LIST, &&TARGET_STORE_SUBSCR, &&TARGET_DELETE_SUBSCR, - &&TARGET_FOR_ITER_LIST, &&TARGET_FOR_ITER_TUPLE, &&TARGET_FOR_ITER_RANGE, &&TARGET_FOR_ITER_GEN, &&TARGET_LOAD_ATTR_CLASS, &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, + &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, - &&TARGET_LOAD_ATTR_INSTANCE_VALUE, - &&TARGET_LOAD_BUILD_CLASS, &&TARGET_LOAD_ATTR_MODULE, + &&TARGET_LOAD_BUILD_CLASS, &&TARGET_LOAD_ATTR_PROPERTY, + &&TARGET_LOAD_ATTR_SLOT, &&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_RETURN_GENERATOR, - &&TARGET_LOAD_ATTR_SLOT, &&TARGET_LOAD_ATTR_WITH_HINT, &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, &&TARGET_LOAD_ATTR_METHOD_NO_DICT, &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_LOAD_FAST__LOAD_CONST, - &&TARGET_RETURN_VALUE, &&TARGET_LOAD_FAST__LOAD_FAST, - &&TARGET_SETUP_ANNOTATIONS, + &&TARGET_RETURN_VALUE, &&TARGET_LOAD_GLOBAL_BUILTIN, + &&TARGET_SETUP_ANNOTATIONS, &&TARGET_LOAD_GLOBAL_MODULE, + &&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_PREP_RERAISE_STAR, &&TARGET_POP_EXCEPT, &&TARGET_STORE_NAME, @@ -112,7 +112,7 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_FORWARD, &&TARGET_JUMP_IF_FALSE_OR_POP, &&TARGET_JUMP_IF_TRUE_OR_POP, - &&TARGET_STORE_ATTR_INSTANCE_VALUE, + &&TARGET_STORE_ATTR_SLOT, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -142,7 +142,7 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_BACKWARD, &&TARGET_COMPARE_AND_BRANCH, &&TARGET_CALL_FUNCTION_EX, - &&TARGET_STORE_ATTR_SLOT, + &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,24 +152,24 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, - &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_STORE_FAST__LOAD_FAST, + &&TARGET_STORE_FAST__STORE_FAST, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, - &&TARGET_STORE_FAST__STORE_FAST, &&TARGET_STORE_SUBSCR_DICT, &&TARGET_STORE_SUBSCR_LIST_INT, &&TARGET_UNPACK_SEQUENCE_LIST, + &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, - &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, + &&_unknown_opcode, &&TARGET_CALL, &&TARGET_KW_NAMES, &&TARGET_CALL_INTRINSIC_1, diff --git a/Python/tier2.c b/Python/tier2.c index a5a2ebc569eb0d..80a51c6db7d193 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -1,4 +1,5 @@ #include "Python.h" +#include "stdlib.h" #include "pycore_code.h" #include "pycore_frame.h" @@ -18,6 +19,7 @@ _PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) // If it fails, due to lack of memory or whatever, // just fall back to the tier 1 interpreter. _Py_CODEUNIT *next = _PyCode_Tier2Initialize(frame, next_instr); + return next_instr; if (next != NULL) { return next; } @@ -26,7 +28,14 @@ _PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) return next_instr; } +// Gets end of the bytecode for a code object. +_Py_CODEUNIT * +_PyCode_GetEnd(PyCodeObject *co) +{ + return (_Py_CODEUNIT *)(co->co_code_adaptive + _PyCode_NBYTES(co)); +} +// Creates the overallocated array for the BBs. static _PyTier2BBSpace * _PyTier2_CreateBBSpace(Py_ssize_t space_to_alloc) { @@ -36,36 +45,190 @@ _PyTier2_CreateBBSpace(Py_ssize_t space_to_alloc) } bb_space->next = NULL; bb_space->water_level = 0; - bb_space->max_capacity = space_to_alloc - sizeof(_PyTier2BB); + assert((int)(space_to_alloc - sizeof(_PyTier2BB)) == (space_to_alloc - sizeof(_PyTier2BB))); + bb_space->max_capacity = (int)(space_to_alloc - sizeof(_PyTier2BB)); return bb_space; } /* Init a BB in BB space without any checks for waterlevel. */ static _PyTier2BB * -_PyTier2_InitBBNoCheck(_PyTier2BBSpace *bb_space, _Py_CODEUNIT *tier1_start, - const void *instr_bytes_src, Py_ssize_t instr_nbytes) +_PyTier2_InitBBNoCheck(_PyTier2BBSpace *bb_space, _Py_CODEUNIT *tier1_end, + _Py_CODEUNIT *instr_start, _Py_CODEUNIT *instr_end) { + Py_ssize_t nbytes = (instr_end - instr_start) * sizeof(_Py_CODEUNIT); _PyTier2BB *bb_ptr = &bb_space->bbs[bb_space->water_level]; - bb_ptr->tier1_start = tier1_start; - memcpy(bb_ptr->u_code, instr_bytes_src, instr_nbytes); - assert(bb_space->water_level + instr_nbytes == (int)(bb_space->water_level + instr_nbytes)); - bb_space->water_level += instr_nbytes; + bb_ptr->tier1_end = tier1_end; + memcpy(bb_ptr->u_code, (const void *)instr_start, nbytes); + assert(bb_space->water_level + nbytes == (int)nbytes); + bb_space->water_level += (int)nbytes; return bb_ptr; } + +/* Opcode detection functions. Keep in sync with compile.c and dis! */ + +// dis.hasjabs +static inline int +IS_JABS_OPCODE(int opcode) +{ + return 0; +} + +// dis.hasjrel +static inline int +IS_JREL_OPCODE(int opcode) +{ + switch (opcode) { + case FOR_ITER: + case JUMP_FORWARD: + case JUMP_IF_FALSE_OR_POP: + case JUMP_IF_TRUE_OR_POP: + case POP_JUMP_IF_FALSE: + case POP_JUMP_IF_TRUE: + case SEND: + case POP_JUMP_IF_NOT_NONE: + case POP_JUMP_IF_NONE: + case JUMP_BACKWARD_NO_INTERRUPT: + case JUMP_BACKWARD: + return 1; + default: + return 0; + + } +} + +// dis.hasjrel || dis.hasjabs +static inline int +IS_JUMP_OPCODE(int opcode) +{ + return IS_JREL_OPCODE(opcode) || IS_JABS_OPCODE(opcode); +} + + +static inline int +IS_SCOPE_EXIT_OPCODE(int opcode) +{ + switch (opcode) { + case RETURN_VALUE: + case RAISE_VARARGS: + case RERAISE: + return 1; + default: + return 0; + } +} + +// KEEP IN SYNC WITH COMPILE.c!!!! +static int +IS_TERMINATOR_OPCODE(int opcode) +{ + return IS_JUMP_OPCODE(opcode) || IS_SCOPE_EXIT_OPCODE(opcode); +} + +static int +compare_ints(const void *a, const void *b) +{ + const int a_num = *(int *)a; + const int b_num = *(int *)b; + return a_num - b_num; +} + +// Returns 1 on error, 0 on success. Populates the jump target offset +// array for a code object. +static int +_PyCode_Tier2FillJumpTargets(PyCodeObject *co) +{ + // Remove all the RESUME instructions. + // Count all the jump targets. + Py_ssize_t jump_target_count = 0; + for (Py_ssize_t i = 0; i < Py_SIZE(co); i++) { + _Py_CODEUNIT *instr_ptr = _PyCode_CODE(co) + i; + _Py_CODEUNIT instr = *instr_ptr; + switch (_Py_OPCODE(instr)) { + case RESUME: + _py_set_opcode(instr_ptr, RESUME_QUICK); + break; + default: + jump_target_count += IS_JUMP_OPCODE(_Py_OPCODE(instr)); + } + } + + // Find all the jump target instructions + _Py_CODEUNIT *end = _PyCode_GetEnd(co); + _Py_CODEUNIT *start = _PyCode_CODE(co); + _Py_CODEUNIT *curr = start; + + // Impossibly big. + if (jump_target_count != (int)jump_target_count) { + return 1; + } + // Impossibly big + if (end - start != (int)(end - start)) { + return 1; + } + co->_jump_target_count = (int)jump_target_count; + int *jump_targets = PyMem_Malloc(jump_target_count * sizeof(int)); + if (jump_targets == NULL) { + return 1; + } + int curr_i = 0; + while (curr <= end) { + _Py_CODEUNIT instr = *curr; + if (IS_JUMP_OPCODE(_Py_OPCODE(instr))) { + _Py_CODEUNIT *target = curr + _Py_OPARG(instr); + // (in terms of offset from start of co_code_adaptive) + jump_targets[curr_i] = (int)(target - start); + curr_i++; + } + curr++; + } + qsort(jump_targets, jump_target_count, sizeof(int), compare_ints); + co->_jump_targets = jump_targets; + return 0; +} + +// Detects a BB from the current instruction start to the end of the code object. +_Py_CODEUNIT * +_PyTier2_Code_DetectBB(PyCodeObject *co, _Py_CODEUNIT *start) +{ + // There are only two cases that a BB ends. + // 1. If there's a branch instruction / scope exit. + // 2. If the instruction is a jump target. + _Py_CODEUNIT *instr_end = _PyCode_GetEnd(co); + _Py_CODEUNIT *curr = start; + int *jump_target_offsets = co->_jump_targets; + int jump_target_count = co->_jump_target_count; + int curr_jump = 0; + while (curr < instr_end) { + _Py_CODEUNIT instr = *curr; + int opcode = _Py_OPCODE(instr); + if (IS_JUMP_OPCODE(opcode) || IS_SCOPE_EXIT_OPCODE(opcode)) { + return curr; + } + while (_PyCode_CODE(co) + jump_target_offsets[curr_jump] < curr) { + curr_jump++; + } + if (_PyCode_CODE(co) + jump_target_offsets[curr_jump] == curr) { + return curr; + } + curr++; + } + return instr_end; +} + static _Py_CODEUNIT * _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) { int curr = _Py_OPCODE(*(next_instr - 1)); - assert(curr == RESUME || curr == JUMP_BACKWARD); + assert(curr == RESUME); PyCodeObject *co = frame->f_code; assert(co->_bb_space == NULL); + // 0. Single pass: mark jump targets // 1. Initialize basic blocks space. - // 2. Copy over instructions to basic blocks. - // (For now, just have one basic block = on code object) - // @TODO split up code object into basic blocks. - // 3. Set the instruction pointer to correct one. + // 2. Create the entry BB (if it is, else the current BB). + // 3. Jump into that BB. fprintf(stderr, "INITIALIZING %ld\n", Py_SIZE(co)); + Py_ssize_t space_to_alloc = (sizeof(_PyTier2BB) + _PyCode_NBYTES(co)) * 2; _PyTier2BBSpace *bb_space = _PyTier2_CreateBBSpace(space_to_alloc); @@ -75,47 +238,45 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) co->_bb_space = bb_space; - _PyTier2BB *bb_ptr = _PyTier2_InitBBNoCheck(bb_space, _PyCode_CODE(co), - _PyCode_CODE(co), _PyCode_NBYTES(co)); + //_Py_CODEUNIT *entry_bb_end = _PyTier2_Code_DetectBB(co, _PyCode_CODE(co)); + _Py_CODEUNIT *entry_bb_end = _PyCode_GetEnd(co); - // Remove all the RESUME and JUMP_BACKWARDS instructions - for (Py_ssize_t i = 0; i < Py_SIZE(co); i++) { - _Py_CODEUNIT instr = bb_ptr->u_code[i]; - switch (_Py_OPCODE(instr)) { - case RESUME: - _py_set_opcode(&(bb_ptr->u_code[i]), RESUME_QUICK); - break; - case JUMP_BACKWARD: - _py_set_opcode(&(bb_ptr->u_code[i]), JUMP_BACKWARD); - break; - } + _PyTier2BB *bb_ptr = _PyTier2_InitBBNoCheck(bb_space, + entry_bb_end, + _PyCode_CODE(co), + entry_bb_end); + if (_PyCode_Tier2FillJumpTargets(co)) { + goto cleanup; } - - co->_bb_next = bb_ptr; + + co->_entry_bb = bb_ptr; // Set the instruction pointer to the next one in the bb Py_ssize_t offset_from_start = (frame->prev_instr - _PyCode_CODE(co)); assert(offset_from_start >= -1); frame->prev_instr = bb_ptr->u_code + offset_from_start; - // test to see we are working // _py_set_opcode(next_instr, CACHE); return bb_ptr->u_code + (next_instr - _PyCode_CODE(co)); + +cleanup: + PyMem_Free(bb_space); + return NULL; } -/* Allocates and initializes a new basic block. If not enough space in +/* Allocates and initializes a new basic block. If there's not enough space in the overallocated array, create a new array. Make sure to call _PyCode_Tier2Initialize before this! */ static _PyTier2BB * -_PyCode_Tier2BBNew(PyCodeObject *co, _Py_CODEUNIT *tier1_start, _Py_CODEUNIT *instr, Py_ssize_t code_size) +_PyCode_Tier2BBNew(PyCodeObject *co, _Py_CODEUNIT *instr_start, _Py_CODEUNIT *instr_end) { assert(co->_bb_space != NULL); _PyTier2BBSpace *bb_space = co->_bb_space; - Py_ssize_t amount_to_alloc = code_size + sizeof(_PyTier2BB); + Py_ssize_t amount_to_alloc = (instr_start - instr_end) * sizeof(_Py_CODEUNIT *) + sizeof(_PyTier2BB); assert(bb_space->water_level + amount_to_alloc == (int)(bb_space->water_level + amount_to_alloc)); // Need to allocate a new array. @@ -129,5 +290,5 @@ _PyCode_Tier2BBNew(PyCodeObject *co, _Py_CODEUNIT *tier1_start, _Py_CODEUNIT *in co->_bb_space = next_bb_space; bb_space = next_bb_space; } - return _PyTier2_InitBBNoCheck(bb_space, tier1_start, instr, code_size * sizeof(_Py_CODEUNIT)); + return _PyTier2_InitBBNoCheck(bb_space, _PyCode_GetEnd(co), instr_start, instr_end); } diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py index 7718bc95722138..88682395abf8c1 100644 --- a/Tools/build/deepfreeze.py +++ b/Tools/build/deepfreeze.py @@ -278,8 +278,10 @@ def generate_code(self, name: str, code: types.CodeType) -> str: self.write(f"._co_cached = NULL,") self.write("._co_linearray = NULL,") self.write("._tier2_warmup = -64,") - self.write("._bb_next = NULL,") + self.write("._entry_bb = NULL,") self.write("._bb_space = NULL,") + self.write("._jump_target_count = 0,") + self.write("._jump_targets = NULL,") self.write(f".co_code_adaptive = {co_code_adaptive},") for i, op in enumerate(code.co_code[::2]): if op == RESUME: From 3a796b5dd88b758a628c50a85c0e6ae749559a62 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 10 Feb 2023 21:58:30 +0800 Subject: [PATCH 021/280] Lazily allocate tier 2 information --- Include/cpython/code.h | 14 ++++--- Lib/importlib/_bootstrap_external.py | 2 +- Objects/codeobject.c | 61 +++++++++++++--------------- Python/bytecodes.c | 2 +- Python/generated_cases.c.h | 6 +-- Python/tier2.c | 29 ++++++++----- Tools/build/deepfreeze.py | 6 +-- 7 files changed, 63 insertions(+), 57 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 9d6c29eee27a7e..73d529b6f3dca0 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -61,6 +61,14 @@ typedef struct _PyTier2BBSpace { _PyTier2BB bbs[1]; } _PyTier2BBSpace; +typedef struct _PyTier2Info { + _PyTier2BB *_entry_bb; /* the tier 2 basic block to execute (if any) */ + _PyTier2BBSpace *_bb_space; /* linked list storing basic blocks */ + int _jump_target_count; /* Number of entries in _jump_targets */ + /* sorted ascending offsets (from start of co_code_adaptive) for jump targets */ + int *_jump_targets; +} _PyTier2Info; + // To avoid repeating ourselves in deepfreeze.py, all PyCodeObject members are // defined in this macro: #define _PyCode_DEF(SIZE) { \ @@ -122,11 +130,7 @@ typedef struct _PyTier2BBSpace { int _co_firsttraceable; /* index of first traceable instruction */ \ char *_co_linearray; /* array of line offsets */ \ int _tier2_warmup; /* warmup counter for tier 2 */ \ - _PyTier2BB *_entry_bb; /* the tier 2 basic block to execute (if any) */ \ - _PyTier2BBSpace *_bb_space; /* linked list storing basic blocks */ \ - int _jump_target_count; /* Number of entries in _jump_targets */ \ - /* sorted ascending offsets (from start of co_code_adaptive) for jump targets */ \ - int *_jump_targets; \ + _PyTier2Info *_tier2_info; /* info required for tier 2, lazily alloc */ \ /* Scratch space for extra data relating to the code object. \ Type is a void* to keep the format private in codeobject.c to force \ people to go through the proper APIs. */ \ diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 933c8c7d7e0590..33fad0ad9a1cab 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -444,7 +444,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3518).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3519).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Objects/codeobject.c b/Objects/codeobject.c index db3a7b6970bd31..6c4ae5b0b190db 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -410,10 +410,7 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con) co->_co_linearray_entry_size = 0; co->_co_linearray = NULL; co->_tier2_warmup = -64; - co->_entry_bb = NULL; - co->_bb_space = NULL; - co->_jump_target_count = 0; - co->_jump_targets = NULL; + co->_tier2_info = NULL; memcpy(_PyCode_CODE(co), PyBytes_AS_STRING(con->code), PyBytes_GET_SIZE(con->code)); int entry_point = 0; @@ -1668,6 +1665,30 @@ code_new_impl(PyTypeObject *type, int argcount, int posonlyargcount, return co; } +static void +code_tier2_fini(PyCodeObject *co) +{ + if (co->_tier2_info == NULL) { + return; + } + _PyTier2Info *t2_info = co->_tier2_info; + t2_info->_entry_bb = NULL; + t2_info->_jump_target_count = 0; + if (t2_info->_bb_space != NULL) { + // Traverse the linked list + for (_PyTier2BBSpace *curr = t2_info->_bb_space; curr != NULL;) { + _PyTier2BBSpace *prev = curr; + curr = curr->next; + PyMem_Free(prev); + } + t2_info->_bb_space = NULL; + } + if (t2_info->_jump_targets != NULL) { + PyMem_Free(t2_info->_jump_targets); + t2_info->_jump_targets = NULL; + } +} + static void code_dealloc(PyCodeObject *co) { @@ -1710,20 +1731,8 @@ code_dealloc(PyCodeObject *co) if (co->_co_linearray) { PyMem_Free(co->_co_linearray); } - co->_entry_bb = NULL; - co->_jump_target_count = 0; - if (co->_bb_space != NULL) { - // Traverse the linked list - for (_PyTier2BBSpace *curr = co->_bb_space; curr != NULL;) { - _PyTier2BBSpace *prev = curr; - curr = curr->next; - PyMem_Free(prev); - } - co->_bb_space = NULL; - } - if (co->_jump_targets != NULL) { - PyMem_Free(co->_jump_targets); - } + code_tier2_fini(co); + co->_tier2_info = NULL; PyObject_Free(co); } @@ -2301,20 +2310,8 @@ _PyStaticCode_Fini(PyCodeObject *co) PyMem_Free(co->_co_cached); co->_co_cached = NULL; } - co->_entry_bb = NULL; - co->_jump_target_count = 0; - if (co->_bb_space != NULL) { - // Traverse the linked list - for (_PyTier2BBSpace *curr = co->_bb_space; curr != NULL;) { - _PyTier2BBSpace *prev = curr; - curr = curr->next; - PyMem_Free(prev); - } - co->_bb_space = NULL; - } - if (co->_jump_targets != NULL) { - PyMem_Free(co->_jump_targets); - } + code_tier2_fini(co); + co->_tier2_info = NULL; co->co_extra = NULL; if (co->co_weakreflist != NULL) { PyObject_ClearWeakRefs((PyObject *)co); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 200708b67a46ac..3bf1bf3f18dbf4 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -296,7 +296,7 @@ dummy_func( U_INST(BINARY_OP_ADD_INT_REST); } - u_inst(BINARY_OP_ADD_INT_TYPE_CHECK, (left, right-- left : PyLong_Type, right: PyLong_Type)) { + u_inst(BINARY_OP_ADD_INT_TYPE_CHECK, (left, right -- left : PyLong_Type, right: PyLong_Type)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index a93b444476b450..d0bde190576225 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -23,9 +23,9 @@ } TARGET(RESUME) { - if (cframe.use_tracing == 0) { - next_instr = _PyCode_Tier2Warmup(frame, next_instr); - } + //if (cframe.use_tracing == 0) { + // next_instr = _PyCode_Tier2Warmup(frame, next_instr); + //} GO_TO_INSTRUCTION(RESUME_QUICK); } diff --git a/Python/tier2.c b/Python/tier2.c index 80a51c6db7d193..968db9c90f84fd 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -138,6 +138,7 @@ compare_ints(const void *a, const void *b) static int _PyCode_Tier2FillJumpTargets(PyCodeObject *co) { + assert(co->_tier2_info != NULL); // Remove all the RESUME instructions. // Count all the jump targets. Py_ssize_t jump_target_count = 0; @@ -166,7 +167,7 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) if (end - start != (int)(end - start)) { return 1; } - co->_jump_target_count = (int)jump_target_count; + co->_tier2_info->_jump_target_count = (int)jump_target_count; int *jump_targets = PyMem_Malloc(jump_target_count * sizeof(int)); if (jump_targets == NULL) { return 1; @@ -183,7 +184,7 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) curr++; } qsort(jump_targets, jump_target_count, sizeof(int), compare_ints); - co->_jump_targets = jump_targets; + co->_tier2_info->_jump_targets = jump_targets; return 0; } @@ -191,13 +192,14 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) _Py_CODEUNIT * _PyTier2_Code_DetectBB(PyCodeObject *co, _Py_CODEUNIT *start) { + assert(co->_tier2_info != NULL); // There are only two cases that a BB ends. // 1. If there's a branch instruction / scope exit. // 2. If the instruction is a jump target. _Py_CODEUNIT *instr_end = _PyCode_GetEnd(co); _Py_CODEUNIT *curr = start; - int *jump_target_offsets = co->_jump_targets; - int jump_target_count = co->_jump_target_count; + int *jump_target_offsets = co->_tier2_info->_jump_targets; + int jump_target_count = co->_tier2_info->_jump_target_count; int curr_jump = 0; while (curr < instr_end) { _Py_CODEUNIT instr = *curr; @@ -222,7 +224,12 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) int curr = _Py_OPCODE(*(next_instr - 1)); assert(curr == RESUME); PyCodeObject *co = frame->f_code; - assert(co->_bb_space == NULL); + assert(co->_tier2_info == NULL); + _PyTier2Info *t2_info = PyMem_Malloc(sizeof(_PyTier2Info)); + if (t2_info == NULL) { + return NULL; + } + co->_tier2_info = t2_info; // 0. Single pass: mark jump targets // 1. Initialize basic blocks space. // 2. Create the entry BB (if it is, else the current BB). @@ -233,10 +240,11 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) _PyTier2BBSpace *bb_space = _PyTier2_CreateBBSpace(space_to_alloc); if (bb_space == NULL) { + PyMem_Free(t2_info); return NULL; } - co->_bb_space = bb_space; + t2_info->_bb_space = bb_space; //_Py_CODEUNIT *entry_bb_end = _PyTier2_Code_DetectBB(co, _PyCode_CODE(co)); _Py_CODEUNIT *entry_bb_end = _PyCode_GetEnd(co); @@ -251,7 +259,7 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) } - co->_entry_bb = bb_ptr; + t2_info->_entry_bb = bb_ptr; // Set the instruction pointer to the next one in the bb Py_ssize_t offset_from_start = (frame->prev_instr - _PyCode_CODE(co)); @@ -273,9 +281,10 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) static _PyTier2BB * _PyCode_Tier2BBNew(PyCodeObject *co, _Py_CODEUNIT *instr_start, _Py_CODEUNIT *instr_end) { - assert(co->_bb_space != NULL); + assert(co->_tier2_info != NULL); + assert(co->_tier2_info->_bb_space != NULL); - _PyTier2BBSpace *bb_space = co->_bb_space; + _PyTier2BBSpace *bb_space = co->_tier2_info->_bb_space; Py_ssize_t amount_to_alloc = (instr_start - instr_end) * sizeof(_Py_CODEUNIT *) + sizeof(_PyTier2BB); assert(bb_space->water_level + amount_to_alloc == (int)(bb_space->water_level + amount_to_alloc)); @@ -287,7 +296,7 @@ _PyCode_Tier2BBNew(PyCodeObject *co, _Py_CODEUNIT *instr_start, _Py_CODEUNIT *in } next_bb_space->next = bb_space; // We want to make our bb_space point to the most recent one to get O(1) BB allocations. - co->_bb_space = next_bb_space; + co->_tier2_info->_bb_space = next_bb_space; bb_space = next_bb_space; } return _PyTier2_InitBBNoCheck(bb_space, _PyCode_GetEnd(co), instr_start, instr_end); diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py index 88682395abf8c1..57e0fdb05bfd64 100644 --- a/Tools/build/deepfreeze.py +++ b/Tools/build/deepfreeze.py @@ -278,11 +278,7 @@ def generate_code(self, name: str, code: types.CodeType) -> str: self.write(f"._co_cached = NULL,") self.write("._co_linearray = NULL,") self.write("._tier2_warmup = -64,") - self.write("._entry_bb = NULL,") - self.write("._bb_space = NULL,") - self.write("._jump_target_count = 0,") - self.write("._jump_targets = NULL,") - self.write(f".co_code_adaptive = {co_code_adaptive},") + self.write("._tier2_info = NULL,") for i, op in enumerate(code.co_code[::2]): if op == RESUME: self.write(f"._co_firsttraceable = {i},") From 1aab16d4805ca56d22a9a3eae9494290376f8ccf Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 10 Feb 2023 22:00:29 +0800 Subject: [PATCH 022/280] try fix bug --- Include/internal/pycore_frame.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index ce87e2a428d8f0..238eab5915ac4d 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -122,7 +122,7 @@ _PyFrame_Initialize( frame->stacktop = code->co_nlocalsplus; frame->frame_obj = NULL; // @TODO CHANGE ME - frame->prev_instr = _PyCode_CODE(code); + frame->prev_instr = _PyCode_CODE(code) - 1; frame->yield_offset = 0; frame->owner = FRAME_OWNED_BY_THREAD; From b0466bd47e0a055e4363ffba67edeb14d71ef5a2 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 10 Feb 2023 22:04:38 +0800 Subject: [PATCH 023/280] fix a bug for real this time --- Tools/build/deepfreeze.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py index 57e0fdb05bfd64..6718973702cdf0 100644 --- a/Tools/build/deepfreeze.py +++ b/Tools/build/deepfreeze.py @@ -279,6 +279,7 @@ def generate_code(self, name: str, code: types.CodeType) -> str: self.write("._co_linearray = NULL,") self.write("._tier2_warmup = -64,") self.write("._tier2_info = NULL,") + self.write(f".co_code_adaptive = {co_code_adaptive},") for i, op in enumerate(code.co_code[::2]): if op == RESUME: self.write(f"._co_firsttraceable = {i},") From 59a07ddca90bdce946f77af4cb8cd300c967558b Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sun, 12 Feb 2023 23:28:23 +0800 Subject: [PATCH 024/280] Part 1: Drive execution of BBs lazily --- Include/cpython/code.h | 43 +- Include/internal/pycore_interp.h | 6 + Include/internal/pycore_opcode.h | 25 +- .../internal/pycore_opcode_macro_to_micro.h | 6 +- Include/opcode.h | 11 +- Lib/opcode.py | 25 +- Objects/codeobject.c | 25 +- Python/bytecodes.c | 4 +- Python/generated_cases.c.h | 12 +- Python/opcode_metadata.h | 6 +- Python/pystate.c | 4 + Python/tier2.c | 708 +++++++++++++++--- 12 files changed, 729 insertions(+), 146 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 73d529b6f3dca0..4fd9705b9dff0f 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -43,30 +43,61 @@ typedef struct { } _PyCoCached; +//// Used to store intermediate code information for the tier 2 "translator". +//// This is eventually finally converted to _PyTier2BB s. +//// Code Object -> _PyTier2IntermediateCode -> _PyTier2BB s. +//typedef struct _PyTier2IntermediateCode { +// /* Number of entries in _jump_targets */ +// int _jump_target_count; +// /* sorted ascending offsets (from start of field code) for jump targets */ +// // The offsets are in number of _Py_CODEUNITs +// int *_jump_targets; +// int n_instrs; +// _Py_CODEUNIT code[1]; +//} _PyTier2IntermediateCode; + + // What the tier 2 interpreter executes typedef struct _PyTier2BB { - struct _PyTier2BB *successor_bb; - // Stores the end pointer in the tier 1 bytecode. - // So that when we exit the BB we can calculate where to return. + _Py_CODEUNIT *successor_bb; + // The other BB to go should BB_BRANCH fail. + _Py_CODEUNIT *alternate_bb; + // Array of types. This corresponds to the fast locals array. + int type_context_len; + PyTypeObject **type_context; + //// Stores the end pointer in the intermediate bytecode. + //// So that when we hit BB_BRANCH, we know what's the next + //// thing to generate. + //_Py_CODEUNIT *intermediate_code_end; _Py_CODEUNIT *tier1_end; + // There's extra memory at the end of this. + int n_instrs; _Py_CODEUNIT u_code[1]; } _PyTier2BB; +// Find the start of the BB from u_code. +#define _PyTier2BB_FROM_UCODE(code) (_PyTier2BB *)(((char *)code) - offsetof(_PyTier2BB, u_code)) + // Bump allocator for basic blocks (overallocated) typedef struct _PyTier2BBSpace { struct _PyTier2BBSpace *next; int max_capacity; // How much space has been consumed in bbs. int water_level; + // There's extra memory at the end of this. _PyTier2BB bbs[1]; } _PyTier2BBSpace; +// Tier 2 info stored in the code object. Lazily allocated. typedef struct _PyTier2Info { _PyTier2BB *_entry_bb; /* the tier 2 basic block to execute (if any) */ _PyTier2BBSpace *_bb_space; /* linked list storing basic blocks */ - int _jump_target_count; /* Number of entries in _jump_targets */ - /* sorted ascending offsets (from start of co_code_adaptive) for jump targets */ - int *_jump_targets; + //_PyTier2IntermediateCode *i_code; /* intermediate bytecode to generate tier 2 basic blocks */ + // Keeps track of offset of jump targets (in number of codeunits) + // from co_code_adaptive. + int jump_target_count; + int *jump_targets; + PyTypeObject **types_stack; } _PyTier2Info; // To avoid repeating ourselves in deepfreeze.py, all PyCodeObject members are diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 0e3d46852f2e6d..371e9071de67af 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -186,6 +186,12 @@ struct _is { struct _Py_interp_cached_objects cached_objects; struct _Py_interp_static_objects static_objects; + // TIER 2 INTERPRETER INFORMATION + + // Bytecode scratchspace when emitting tier 2 bytecode. + int tier2_bytecode_scratchsize; + _Py_CODEUNIT *tier2_bytecode_scratch; + /* The following fields are here to avoid allocation during init. The data is exposed through PyInterpreterState pointer fields. These fields should not be accessed directly outside of init. diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index eee13ed8962825..7e7908d543683b 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -397,18 +397,18 @@ static const char *const _PyOpcode_OpName[263] = { [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", - [BINARY_OP_ADD_INT_TYPE_CHECK] = "BINARY_OP_ADD_INT_TYPE_CHECK", - [BINARY_OP_ADD_INT_REST] = "BINARY_OP_ADD_INT_REST", - [169] = "<169>", - [170] = "<170>", + [BB_ENTER_FRAME] = "BB_ENTER_FRAME", + [BB_EXIT_FRAME] = "BB_EXIT_FRAME", + [BB_TYPE_BRANCH] = "BB_TYPE_BRANCH", + [BB_ITER] = "BB_ITER", [CALL] = "CALL", [KW_NAMES] = "KW_NAMES", [CALL_INTRINSIC_1] = "CALL_INTRINSIC_1", - [174] = "<174>", - [175] = "<175>", - [176] = "<176>", - [177] = "<177>", - [178] = "<178>", + [BB_BRANCH_OR_POP] = "BB_BRANCH_OR_POP", + [BB_POP_THEN_BRANCH] = "BB_POP_THEN_BRANCH", + [BB_POP_BRANCH] = "BB_POP_BRANCH", + [BINARY_CHECK_INT] = "BINARY_CHECK_INT", + [BINARY_OP_ADD_INT_REST] = "BINARY_OP_ADD_INT_REST", [179] = "<179>", [180] = "<180>", [181] = "<181>", @@ -498,13 +498,6 @@ static const char *const _PyOpcode_OpName[263] = { #define EXTRA_CASES \ - case 169: \ - case 170: \ - case 174: \ - case 175: \ - case 176: \ - case 177: \ - case 178: \ case 179: \ case 180: \ case 181: \ diff --git a/Include/internal/pycore_opcode_macro_to_micro.h b/Include/internal/pycore_opcode_macro_to_micro.h index bffa49d3ceefcb..ae2cc505738362 100644 --- a/Include/internal/pycore_opcode_macro_to_micro.h +++ b/Include/internal/pycore_opcode_macro_to_micro.h @@ -35,7 +35,7 @@ extern const int _Py_MacroOpUOpCount[] = { [BINARY_OP_INPLACE_ADD_UNICODE] = 1, [BINARY_OP_ADD_FLOAT] = 1, [BINARY_OP_ADD_INT] = 2, -[BINARY_OP_ADD_INT_TYPE_CHECK] = 1, +[BINARY_CHECK_INT] = 1, [BINARY_OP_ADD_INT_REST] = 1, [BINARY_SUBSCR] = 1, [BINARY_SLICE] = 1, @@ -183,10 +183,10 @@ extern const int _Py_MacroOpUOpCount[] = { }; extern const int _Py_MacroOpToUOp[][2] = { -[BINARY_OP_ADD_INT] = {BINARY_OP_ADD_INT_TYPE_CHECK, BINARY_OP_ADD_INT_REST}, +[BINARY_OP_ADD_INT] = {BINARY_CHECK_INT, BINARY_OP_ADD_INT_REST}, }; extern const PyTypeObject *_Py_UOpGuardTypes[][2] = { -[BINARY_OP_ADD_INT_TYPE_CHECK] = {&PyLong_Type, &PyLong_Type}, +[BINARY_CHECK_INT] = {&PyLong_Type, &PyLong_Type}, }; #ifdef __cplusplus } diff --git a/Include/opcode.h b/Include/opcode.h index b89441dc98e835..d8569fe97b31b9 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -253,8 +253,15 @@ extern "C" { #define UNPACK_SEQUENCE_TUPLE 161 #define UNPACK_SEQUENCE_TWO_TUPLE 166 #define DO_TRACING 255 -#define BINARY_OP_ADD_INT_TYPE_CHECK 167 -#define BINARY_OP_ADD_INT_REST 168 +#define BB_ENTER_FRAME 167 +#define BB_EXIT_FRAME 168 +#define BB_TYPE_BRANCH 169 +#define BB_ITER 170 +#define BB_BRANCH_OR_POP 174 +#define BB_POP_THEN_BRANCH 175 +#define BB_POP_BRANCH 176 +#define BINARY_CHECK_INT 177 +#define BINARY_OP_ADD_INT_REST 178 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/opcode.py b/Lib/opcode.py index a12b6568dace4d..be1c0dbf8fafe9 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -442,6 +442,29 @@ def pseudo_op(name, op, real_ops): 'BINARY_OP_ADD_INT', ] _uops = [ - 'BINARY_OP_ADD_INT_TYPE_CHECK', + # Tier 2 BB opcodes + 'BB_ENTER_FRAME', + 'BB_EXIT_FRAME', + ## These branches correspond to the jump instructions + 'BB_TYPE_BRANCH', + 'BB_ITER', # FOR_ITER + 'BB_BRANCH_OR_POP', # JUMP_IF_FALSE_OR_POP, JUMP_IF_TRUE_OR_POP + 'BB_POP_THEN_BRANCH', # POP_JUMP_IF_FALSE, POP_JUMP_IF_TRUE + 'BB_POP_BRANCH', # POP_JUMP_IF_NOT_NONE, POP_JUMP_IF_NONE + + # Common type checks + # These instructions check that one operand is a certain type. + # Their oparg is the offset from TOS to read. + # 'UNARY_CHECK_INT', + # 'UNARY_CHECK_FLOAT', + # 'UNARY_CHECK_STR', + + # These instructions check that both operands are a certain type. + # The benefit is that they save some dispatch overhead versus the + # single operand forms. + 'BINARY_CHECK_INT', + # 'BINARY_CHECK_FLOAT', + # 'BINARY_CHECK_STR', + # BINARY_OP_ADD_INT, 'BINARY_OP_ADD_INT_REST', ] diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 6c4ae5b0b190db..bdc31b6216304f 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1673,7 +1673,6 @@ code_tier2_fini(PyCodeObject *co) } _PyTier2Info *t2_info = co->_tier2_info; t2_info->_entry_bb = NULL; - t2_info->_jump_target_count = 0; if (t2_info->_bb_space != NULL) { // Traverse the linked list for (_PyTier2BBSpace *curr = t2_info->_bb_space; curr != NULL;) { @@ -1683,10 +1682,26 @@ code_tier2_fini(PyCodeObject *co) } t2_info->_bb_space = NULL; } - if (t2_info->_jump_targets != NULL) { - PyMem_Free(t2_info->_jump_targets); - t2_info->_jump_targets = NULL; - } + + if (t2_info->jump_target_count > 0 && + t2_info->jump_targets != NULL) { + PyMem_Free(t2_info->jump_targets); + t2_info->jump_targets = NULL; + } + if (t2_info->types_stack != NULL) { + PyMem_Free(t2_info->types_stack); + t2_info->types_stack = NULL; + } + t2_info->jump_target_count = 0; + PyMem_Free(t2_info); + //if (t2_info->i_code != NULL) { + // if (t2_info->i_code->_jump_targets != NULL) { + // PyMem_Free(t2_info->i_code->_jump_targets); + // t2_info->i_code->_jump_targets = NULL; + // } + // PyMem_Free(t2_info->i_code); + // t2_info->i_code = NULL; + //} } static void diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 3bf1bf3f18dbf4..9900ad02bd24b4 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -292,11 +292,11 @@ dummy_func( } macro_inst(BINARY_OP_ADD_INT, (unused/1, left, right -- sum)) { - U_INST(BINARY_OP_ADD_INT_TYPE_CHECK); + U_INST(BINARY_CHECK_INT); U_INST(BINARY_OP_ADD_INT_REST); } - u_inst(BINARY_OP_ADD_INT_TYPE_CHECK, (left, right -- left : PyLong_Type, right: PyLong_Type)) { + u_inst(BINARY_CHECK_INT, (left, right -- left : PyLong_Type, right: PyLong_Type)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index d0bde190576225..86125e4a5c3347 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2,7 +2,7 @@ // from Python\bytecodes.c // Do not edit! - #define UOP_BINARY_OP_ADD_INT_TYPE_CHECK() \ + #define UOP_BINARY_CHECK_INT() \ do { \ assert(cframe.use_tracing == 0);\ DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);\ @@ -23,9 +23,9 @@ } TARGET(RESUME) { - //if (cframe.use_tracing == 0) { - // next_instr = _PyCode_Tier2Warmup(frame, next_instr); - //} + if (cframe.use_tracing == 0) { + next_instr = _PyCode_Tier2Warmup(frame, next_instr); + } GO_TO_INSTRUCTION(RESUME_QUICK); } @@ -414,7 +414,7 @@ PyObject *right = PEEK(1); PyObject *left = PEEK(2); PyObject *sum; - UOP_BINARY_OP_ADD_INT_TYPE_CHECK(); + UOP_BINARY_CHECK_INT(); UOP_BINARY_OP_ADD_INT_REST(); STACK_SHRINK(1); POKE(1, sum); @@ -422,7 +422,7 @@ DISPATCH(); } - TARGET(BINARY_OP_ADD_INT_TYPE_CHECK) { + TARGET(BINARY_CHECK_INT) { PyObject *right = PEEK(1); PyObject *left = PEEK(2); assert(cframe.use_tracing == 0); diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 6551cd7807f128..d4ac2d2b43ecd2 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -60,7 +60,7 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 2; case BINARY_OP_ADD_INT: return 2; - case BINARY_OP_ADD_INT_TYPE_CHECK: + case BINARY_CHECK_INT: return 2; case BINARY_OP_ADD_INT_REST: return 2; @@ -414,7 +414,7 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 1; case BINARY_OP_ADD_INT: return 1; - case BINARY_OP_ADD_INT_TYPE_CHECK: + case BINARY_CHECK_INT: return 2; case BINARY_OP_ADD_INT_REST: return 1; @@ -745,7 +745,7 @@ struct opcode_metadata { [BINARY_OP_INPLACE_ADD_UNICODE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [BINARY_OP_ADD_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, [BINARY_OP_ADD_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_ADD_INT_TYPE_CHECK] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [BINARY_CHECK_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [BINARY_OP_ADD_INT_REST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [BINARY_SUBSCR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, [BINARY_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, diff --git a/Python/pystate.c b/Python/pystate.c index 1261092d1435fa..d79ba19bf09bff 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -643,6 +643,10 @@ init_interpreter(PyInterpreterState *interp, PyConfig_InitPythonConfig(&interp->config); _PyType_InitCache(interp); + // Tier 2 interpreter information + interp->tier2_bytecode_scratchsize = 0; + interp->tier2_bytecode_scratch = NULL; + interp->_initialized = 1; } diff --git a/Python/tier2.c b/Python/tier2.c index 968db9c90f84fd..d84582d8027db6 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -2,11 +2,22 @@ #include "stdlib.h" #include "pycore_code.h" #include "pycore_frame.h" +#include "pycore_opcode.h" +#include "pycore_pystate.h" #include "opcode.h" -static _Py_CODEUNIT * -_PyCode_Tier2Initialize(_PyInterpreterFrame *, _Py_CODEUNIT *); +#define BB_DEBUG 1 + +// Number of potential extra instructions at end of a BB, for branch or cleanup purposes. +// BB_BRANCH instruction: 1 +#define BB_EPILOG 1 + +static _Py_CODEUNIT *_PyCode_Tier2Initialize(_PyInterpreterFrame *, _Py_CODEUNIT *); + +static inline int IS_SCOPE_EXIT_OPCODE(int opcode); + +////////// CEVAL functions // Tier 2 warmup counter _Py_CODEUNIT * @@ -28,13 +39,71 @@ _PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) return next_instr; } +////////// Utility functions + +// Checks that we have enough scratch space for the current code object. Else allocate more. +static _Py_CODEUNIT * +_PyInterpreter_GetScratchSpace(PyCodeObject *co) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + int n_instrs = (int)Py_SIZE(co); + Py_ssize_t space_to_alloc = _PyCode_NBYTES(co); + int overalloc = 2; + if (interp->tier2_bytecode_scratchsize == 0 || + interp->tier2_bytecode_scratch == NULL) { + interp->tier2_bytecode_scratch = PyMem_Malloc(space_to_alloc * overalloc); + if (interp->tier2_bytecode_scratch == NULL) { + return NULL; + } + interp->tier2_bytecode_scratchsize = Py_SIZE(co) * overalloc; + return interp->tier2_bytecode_scratch; + } + if (interp->tier2_bytecode_scratchsize < n_instrs) { + PyMem_Free(interp->tier2_bytecode_scratch); + interp->tier2_bytecode_scratch = PyMem_Malloc(space_to_alloc * overalloc); + if (interp->tier2_bytecode_scratch == NULL) { + return NULL; + } + interp->tier2_bytecode_scratchsize = Py_SIZE(co) * overalloc; + } + return interp->tier2_bytecode_scratch; +} + // Gets end of the bytecode for a code object. _Py_CODEUNIT * _PyCode_GetEnd(PyCodeObject *co) { - return (_Py_CODEUNIT *)(co->co_code_adaptive + _PyCode_NBYTES(co)); + _Py_CODEUNIT *end = (_Py_CODEUNIT *)(co->co_code_adaptive + _PyCode_NBYTES(co)); + return end; +} + +// Gets end of actual bytecode executed. _PyCode_GetEnd might return a CACHE instruction. +_Py_CODEUNIT * +_PyCode_GetLogicalEnd(PyCodeObject *co) +{ + _Py_CODEUNIT *end = _PyCode_GetEnd(co); + while (_Py_OPCODE(*end) == CACHE) { + end--; + } +#if BB_DEBUG + if (!IS_SCOPE_EXIT_OPCODE(_Py_OPCODE(*end))) { + fprintf(stderr, "WRONG EXIT OPCODE: %d\n", _Py_OPCODE(*end)); + assert(0); + } +#endif + assert(IS_SCOPE_EXIT_OPCODE(_Py_OPCODE(*end))); + return end; +} + +// Gets end of the bytecode for a tier 2 BB. +_Py_CODEUNIT * +_PyTier2BB_UCodeEnd(_PyTier2BB *bb) +{ + return (_Py_CODEUNIT *)(bb->u_code + bb->n_instrs); } +////////// BB SPACE FUNCTIONS + // Creates the overallocated array for the BBs. static _PyTier2BBSpace * _PyTier2_CreateBBSpace(Py_ssize_t space_to_alloc) @@ -50,20 +119,57 @@ _PyTier2_CreateBBSpace(Py_ssize_t space_to_alloc) return bb_space; } +////////// TIER 2 BB FUNCTIONS + /* Init a BB in BB space without any checks for waterlevel. */ static _PyTier2BB * _PyTier2_InitBBNoCheck(_PyTier2BBSpace *bb_space, _Py_CODEUNIT *tier1_end, _Py_CODEUNIT *instr_start, _Py_CODEUNIT *instr_end) { - Py_ssize_t nbytes = (instr_end - instr_start) * sizeof(_Py_CODEUNIT); + Py_ssize_t ninstrs = (instr_end - instr_start) + BB_EPILOG; + assert(ninstrs == (int)ninstrs); + Py_ssize_t nbytes = ninstrs * sizeof(_Py_CODEUNIT); _PyTier2BB *bb_ptr = &bb_space->bbs[bb_space->water_level]; bb_ptr->tier1_end = tier1_end; + bb_ptr->n_instrs = (int)ninstrs; + bb_ptr->successor_bb = NULL; + bb_ptr->alternate_bb = NULL; + // @TODO, add type context. memcpy(bb_ptr->u_code, (const void *)instr_start, nbytes); assert(bb_space->water_level + nbytes == (int)nbytes); bb_space->water_level += (int)nbytes; return bb_ptr; } +/* Allocates and initializes a new basic block. If there's not enough space in + the overallocated array, create a new array. + + Make sure to call _PyCode_Tier2Initialize before this! +*/ +static _PyTier2BB * +_PyCode_Tier2BBNew(PyCodeObject *co, _Py_CODEUNIT *tier1_end, _Py_CODEUNIT *instr_start, _Py_CODEUNIT *instr_end) +{ + assert(co->_tier2_info != NULL); + assert(co->_tier2_info->_bb_space != NULL); + + _PyTier2BBSpace *bb_space = co->_tier2_info->_bb_space; + Py_ssize_t amount_to_alloc = (instr_start - instr_end) * sizeof(_Py_CODEUNIT *) + sizeof(_PyTier2BB); + assert(bb_space->water_level + amount_to_alloc == (int)(bb_space->water_level + amount_to_alloc)); + + // Need to allocate a new array. + if (bb_space->water_level + amount_to_alloc > bb_space->max_capacity) { + _PyTier2BBSpace *next_bb_space = _PyTier2_CreateBBSpace(bb_space->max_capacity + amount_to_alloc); + if (next_bb_space == NULL) { + return NULL; + } + next_bb_space->next = bb_space; + // We want to make our bb_space point to the most recent one to get O(1) BB allocations. + co->_tier2_info->_bb_space = next_bb_space; + bb_space = next_bb_space; + } + return _PyTier2_InitBBNoCheck(bb_space, tier1_end, instr_start, instr_end); +} + /* Opcode detection functions. Keep in sync with compile.c and dis! */ @@ -83,6 +189,7 @@ IS_JREL_OPCODE(int opcode) case JUMP_FORWARD: case JUMP_IF_FALSE_OR_POP: case JUMP_IF_TRUE_OR_POP: + // These two tend to be after a COMPARE_AND_BRANCH. case POP_JUMP_IF_FALSE: case POP_JUMP_IF_TRUE: case SEND: @@ -104,14 +211,22 @@ IS_JUMP_OPCODE(int opcode) return IS_JREL_OPCODE(opcode) || IS_JABS_OPCODE(opcode); } +// dis.hascompare +static inline int +IS_COMPARE_OPCODE(int opcode) +{ + return opcode == COMPARE_OP || opcode == COMPARE_AND_BRANCH; +} static inline int IS_SCOPE_EXIT_OPCODE(int opcode) { switch (opcode) { case RETURN_VALUE: + case RETURN_CONST: case RAISE_VARARGS: case RERAISE: + case INTERPRETER_EXIT: return 1; default: return 0; @@ -125,16 +240,357 @@ IS_TERMINATOR_OPCODE(int opcode) return IS_JUMP_OPCODE(opcode) || IS_SCOPE_EXIT_OPCODE(opcode); } +// Opcodes that we can't handle at the moment. If we see them, +// ditch tier 2 attempts. +static inline int +IS_FORBIDDEN_OPCODE(int opcode) +{ + switch (opcode) { + // Generators and coroutines + case SEND: + case YIELD_VALUE: + // Raise keyword + case RAISE_VARARGS: + // Exceptions, we could support these theoretically. + // Just too much work for now + case PUSH_EXC_INFO: + case RERAISE: + case POP_EXCEPT: + // Closures + case LOAD_DEREF: + case MAKE_CELL: + // @TODO backward jumps should be supported! + case JUMP_BACKWARD: + case JUMP_BACKWARD_NO_INTERRUPT: + return 1; + default: + return 0; + } +} + +static inline PyTypeObject * +INSTR_LOCAL_READ_TYPE(PyCodeObject *co, _Py_CODEUNIT instr, PyTypeObject **type_context) +{ + int opcode = _PyOpcode_Deopt[_Py_OPCODE(instr)]; + int oparg = _Py_OPARG(instr); + switch (opcode) { + case LOAD_CONST: + return Py_TYPE(PyTuple_GET_ITEM(co->co_consts, oparg)); + case LOAD_FAST: + return type_context[oparg]; + // Note: Don't bother with LOAD_NAME, because those exist only in the global + // scope. + default: + return NULL; + } +} + +/* +* This does multiple things: +* 1. Gets the result type of an instruction, if it can figure it out. + 2. Determines whether thet instruction has a corresponding macro/micro instruction + that acts a guard, and whether it needs it. + 3. How many guards it needs, and what are the guards. + 4. Finally, the corresponding specialised micro-op to operate on this type. + + Returns the inferred type of an operation. NULL if unknown. + + how_many_guards returns the number of guards (0, 1) + guards should be a opcode corresponding to the guard instruction to use. +*/ +static PyTypeObject * +BINARY_OP_RESULT_TYPE(PyCodeObject *co, _Py_CODEUNIT *instr, int n_typecontext, + PyTypeObject **type_context, int *how_many_guards, _Py_CODEUNIT *guard, _Py_CODEUNIT *action) +{ + int opcode = _PyOpcode_Deopt[_Py_OPCODE(*instr)]; + int oparg = _Py_OPARG(*instr); + switch (opcode) { + case BINARY_OP: + if (oparg == NB_ADD) { + // For BINARY OP, read the previous two load instructions + // to see what variables we need to type check. + PyTypeObject *lhs_type = INSTR_LOCAL_READ_TYPE(co, *(instr - 2), type_context); + PyTypeObject *rhs_type = INSTR_LOCAL_READ_TYPE(co, *(instr - 1), type_context); + // The two instruction types are known. + if (lhs_type == &PyLong_Type) { + if (rhs_type == &PyLong_Type) { + *how_many_guards = 0; + action->opcode = BINARY_OP_ADD_INT_REST; + return &PyLong_Type; + } + //// Right side unknown. Emit single check. + //else if (rhs_type == NULL) { + // *how_many_guards = 1; + // guard->opcode = + // return NULL; + //} + } + // We don't know anything, need to emit guard. + // @TODO + } + break; + } + return NULL; +} + +static inline _Py_CODEUNIT * +emit_type_guard(_Py_CODEUNIT *write_curr, _Py_CODEUNIT guard) +{ + *write_curr = guard; + write_curr++; + _py_set_opcode(write_curr, BB_TYPE_BRANCH); + write_curr++; + return write_curr; +} + +static inline _Py_CODEUNIT * +emit_logical_branch(_Py_CODEUNIT *write_curr, int branch) +{ + int opcode; + int oparg = 0; + // @TODO handle JUMP_BACKWARDS and JUMP_BACKWARDS_NO_INTERRUPT + switch (branch) { + case FOR_ITER: + opcode = BB_ITER; + break; + case JUMP_IF_FALSE_OR_POP: + oparg = 1; + case JUMP_IF_TRUE_OR_POP: + opcode = BB_BRANCH_OR_POP; + break; + case POP_JUMP_IF_FALSE: + oparg = 1; + case POP_JUMP_IF_TRUE: + opcode = BB_POP_THEN_BRANCH; + break; + case POP_JUMP_IF_NOT_NONE: + oparg = 1; + case POP_JUMP_IF_NONE: + opcode = BB_POP_BRANCH; + break; + default: + // Honestly shouldn't happen because branches that + // we can't handle are in IS_FORBIDDEN_OPCODE +#if BB_DEBUG + fprintf(stderr, "emit_logical_branch unreachable\n"); +#endif + Py_UNREACHABLE(); + } +#if BB_DEBUG + fprintf(stderr, "emitted logical branch\n"); +#endif + _py_set_opcode(write_curr, opcode); + write_curr->oparg = oparg; + write_curr++; + return write_curr; +} + +static inline _Py_CODEUNIT * +emit_scope_exit(_Py_CODEUNIT *write_curr, int exit) +{ + switch (exit) { + case RETURN_VALUE: + case RETURN_CONST: + case INTERPRETER_EXIT: +#if BB_DEBUG + fprintf(stderr, "emitted scope exit\n"); +#endif + // @TODO we can propogate and chain BBs across call boundaries + // Thanks to CPython's inlined call frames. + _py_set_opcode(write_curr, BB_EXIT_FRAME); + return write_curr + 1; + default: + // The rest are forbidden. +#if BB_DEBUG + fprintf(stderr, "emit_scope_exit unreachable %d\n", exit); +#endif + Py_UNREACHABLE(); + } +} + +static inline _Py_CODEUNIT * +emit_i(_Py_CODEUNIT *write_curr, int opcode, int oparg) +{ + _py_set_opcode(write_curr, opcode); + write_curr->oparg = oparg; + write_curr++; + return write_curr; +} + +static inline _Py_CODEUNIT * +copy_cache_entries(_Py_CODEUNIT *write_curr, _Py_CODEUNIT *cache, int n_entries) +{ + for (int i = 0; i < n_entries; i++) { + *write_curr = *cache; + cache++; + write_curr++; + } + return write_curr; +} + +// Detects a BB from the current instruction start to the end of the first basic block it sees. +// Then emits the instructions for a _PyTier2BB. +// +// Instructions emitted depend on the type_context. +// For example, if it sees a BINARY_ADD instruction, but it knows the two operands are already of +// type PyLongObject, a BINARY_ADD_INT_REST will be emitted without an type checks. +// +// However, if one of the operands are unknown, a logical chain of CHECK instructions will be emitted, +// and the basic block will end at the first of the chain. +// +// Note: a BB end also includes a type guard. +_PyTier2BB * +_PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _Py_CODEUNIT *start, + int n_typecontext, PyTypeObject **type_context) +{ +#define END() goto end; +#define JUMPBY(x) i += x + 1; continue; +#define BASIC_PUSH(v) (*stack_pointer++ = (v)) +#define BASIC_POP() (*--stack_pointer) +#define DISPATCH() write_i = emit_i(write_i, opcode, oparg); write_i = copy_cache_entries(write_i, curr+1, caches); break; + assert(co->_tier2_info != NULL); + // There are only two cases that a BB ends. + // 1. If there's a branch instruction / scope exit. + // 2. If the instruction is a jump target. + + // Make a copy of the type context + PyTypeObject **type_context_copy = PyMem_Malloc(n_typecontext * sizeof(PyTypeObject *)); + if (type_context_copy == NULL) { + return NULL; + } + memcpy(type_context_copy, type_context, n_typecontext * sizeof(PyTypeObject *)); + + _Py_CODEUNIT *start_i = _PyInterpreter_GetScratchSpace(co); + _Py_CODEUNIT *write_i = start_i; + PyTypeObject **stack_pointer = co->_tier2_info->types_stack; + int tos = -1; + + // A meta-interpreter for types. + Py_ssize_t i = 0; + for (; i < Py_SIZE(co); i++) { + _Py_CODEUNIT *curr = _PyCode_CODE(co) + i; + _Py_CODEUNIT instr = *curr; + int opcode = _PyOpcode_Deopt[_Py_OPCODE(instr)]; + int oparg = _Py_OPARG(instr); + int caches = _PyOpcode_Caches[opcode]; + + // Just because an instruction requires a guard doesn't mean it's the end of a BB. + // We need to check whether we can eliminate the guard based on the current type context. + int how_many_guards = 0; + _Py_CODEUNIT guard_instr; + _Py_CODEUNIT action; + + switch (opcode) { + //case LOAD_FAST: + // BASIC_PUSH(type_context[oparg]); + // DISPATCH(); + //case LOAD_NAME: + // BASIC_PUSH(NULL); + // DISPATCH(); + //case LOAD_CONST: { + // PyTypeObject *cont = Py_TYPE(PyTuple_GET_ITEM(co->co_consts, oparg)); + // BASIC_PUSH(cont); + // DISPATCH(); + //} + //case STORE_FAST: { + // type_context[oparg] = BASIC_POP(); + // DISPATCH(); + //} + //case STORE_NAME: + // BASIC_POP(); + // DISPATCH(); + //case BINARY_OP: { + // PyTypeObject *res = BINARY_OP_RESULT_TYPE(co, curr, n_typecontext, type_context, + // &how_many_guards, &guard_instr, &action); + // // We need a guard. So this is the end of the basic block. + // // @TODO in the future, support multiple guards. + // if (how_many_guards > 0) { + // // Emit the guard + // emit_type_guard(&write_i, guard_instr); + // END(); + // } + // else { + // BASIC_PUSH(res); + // // Don't need a guard, either is a micro op, or is a generic instruction + // // No type information known. Use a generic instruction. + // if (res == NULL) { + // DISPATCH(); + // } + // else { + // emit_i(&write_i, _Py_OPCODE(action), 0); + // break; + // } + // } + //} + default: + // These are definitely the end of a basic block. + if (IS_SCOPE_EXIT_OPCODE(opcode)) { + // Emit the scope exit instruction. + write_i = emit_scope_exit(write_i, opcode); + END(); + } + + // Jumps may be the end of a basic block if they are conditional (a branch). + if (IS_JUMP_OPCODE(opcode)) { + // Unconditional forward jump... continue with the BB without writing the jump. + if (opcode == JUMP_FORWARD) { + // JUMP offset (oparg) + current instruction + cache entries + JUMPBY(oparg); + } + write_i = emit_logical_branch(write_i, opcode); + END(); + } + DISPATCH(); + } + + i += caches; + + } +end: +//#if BB_DEBUG +// fprintf(stderr, "i is %Id\n", i); +//#endif + // Create the tier 2 BB + return _PyCode_Tier2BBNew(co, _PyCode_CODE(co) + i, start_i, write_i); +} + + +//// The exits of BBs need to use BB_BRANCH instruction. +//static void +//_PyTier2BB_RewriteExitBranch(_PyTier2BB *bb) +//{ +// _Py_CODEUNIT *last_instr = _PyTier2BB_UCodeEnd(bb) - BB_EPILOG; +// int op = _PyOpcode_Deopt[_Py_OPCODE(*last_instr)]; +// assert(IS_TERMINATOR_OPCODE(op)); +// if (IS_JUMP_OPCODE(op)) { +// _Py_CODEUNIT lasti = *last_instr; +// _py_set_opcode(last_instr, BB_BRANCH); +// // Write the original jump instruction after to know where +// // to start generating the next BB from. +// _Py_SET_OPCODE +// return; +// } +// assert(IS_SCOPE_EXIT_OPCODE(op)); +// assert(op == RETURN_VALUE || op == RETURN_CONST); +// // Need to FRAME_EXIT. +// +//} + + +////////// _PyTier2Info FUNCTIONS + static int compare_ints(const void *a, const void *b) { - const int a_num = *(int *)a; - const int b_num = *(int *)b; - return a_num - b_num; + return *(int *)a - *(int *)b; } // Returns 1 on error, 0 on success. Populates the jump target offset // array for a code object. +// NOTE TO SELF: WE MIGHT NOT EVEN NEED TO FILL UP JUMP TARGETS. +// JUMP TARGETS CONTINUE BEING PART OF THE BASIC BLOCK AS LONG +// AS NO BRANCH IS DETECTED. +// REMOVE IN THE FUTURE IF UNECESSARY. static int _PyCode_Tier2FillJumpTargets(PyCodeObject *co) { @@ -145,96 +601,172 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) for (Py_ssize_t i = 0; i < Py_SIZE(co); i++) { _Py_CODEUNIT *instr_ptr = _PyCode_CODE(co) + i; _Py_CODEUNIT instr = *instr_ptr; - switch (_Py_OPCODE(instr)) { + int opcode = _PyOpcode_Deopt[_Py_OPCODE(instr)]; + int oparg = _Py_OPARG(instr); + switch (opcode) { case RESUME: _py_set_opcode(instr_ptr, RESUME_QUICK); break; default: - jump_target_count += IS_JUMP_OPCODE(_Py_OPCODE(instr)); + // We want to track all guard instructions as + // jumps too. + jump_target_count += IS_JUMP_OPCODE(opcode); // + INSTR_HAS_GUARD(instr); } + i += _PyOpcode_Caches[opcode]; } - // Find all the jump target instructions - _Py_CODEUNIT *end = _PyCode_GetEnd(co); - _Py_CODEUNIT *start = _PyCode_CODE(co); - _Py_CODEUNIT *curr = start; - // Impossibly big. if (jump_target_count != (int)jump_target_count) { return 1; } - // Impossibly big - if (end - start != (int)(end - start)) { - return 1; + + // Find all the jump target instructions + // Don't allocate a zero byte space as this may be undefined behavior. + if (jump_target_count == 0) { + co->_tier2_info->jump_targets = NULL; + // Successful (no jump targets)! + co->_tier2_info->jump_target_count = (int)jump_target_count; + return 0; } - co->_tier2_info->_jump_target_count = (int)jump_target_count; int *jump_targets = PyMem_Malloc(jump_target_count * sizeof(int)); if (jump_targets == NULL) { return 1; } + _Py_CODEUNIT *start = _PyCode_CODE(co); int curr_i = 0; - while (curr <= end) { + for (Py_ssize_t i = 0; i < Py_SIZE(co); i++) { + _Py_CODEUNIT *curr = start + i; _Py_CODEUNIT instr = *curr; - if (IS_JUMP_OPCODE(_Py_OPCODE(instr))) { + int opcode = _PyOpcode_Deopt[_Py_OPCODE(instr)]; + int oparg = _Py_OPARG(instr); + //switch (opcode) { + //// KEEP IN SYNC WITH INSTR_HAS_GUARD + //case BINARY_OP: + // if (oparg == NB_ADD) { + // jump_targets[curr_i] = (int)(curr - start) + INLINE_CACHE_ENTRIES_BINARY_OP; + // curr_i++; + // } + // break; + //default: + if (IS_JUMP_OPCODE(opcode)) { _Py_CODEUNIT *target = curr + _Py_OPARG(instr); // (in terms of offset from start of co_code_adaptive) jump_targets[curr_i] = (int)(target - start); curr_i++; } - curr++; + //} + i += _PyOpcode_Caches[opcode]; } + assert(curr_i == jump_target_count); qsort(jump_targets, jump_target_count, sizeof(int), compare_ints); - co->_tier2_info->_jump_targets = jump_targets; +#if BB_DEBUG + fprintf(stderr, "JUMP TARGET COUNT: %lld\n", jump_target_count); + fprintf(stderr, "JUMP TARGET OFFSETS (FROM START OF CODE): "); + for (Py_ssize_t i = 0; i < jump_target_count; i++) { + fprintf(stderr, "%d ,", jump_targets[i]); + } + fprintf(stderr, "\n"); +#endif + co->_tier2_info->jump_target_count = (int)jump_target_count; + co->_tier2_info->jump_targets = jump_targets; return 0; } -// Detects a BB from the current instruction start to the end of the code object. -_Py_CODEUNIT * -_PyTier2_Code_DetectBB(PyCodeObject *co, _Py_CODEUNIT *start) +//static _PyTier2IntermediateCode * +//_PyIntermediateCode_Initialize(PyCodeObject *co) +//{ +// assert(co->_tier2_info != NULL); +// Py_ssize_t space_to_alloc = (sizeof(PyCodeObject) + _PyCode_NBYTES(co)) + BB_EPILOG; +// _PyTier2IntermediateCode *i_code = PyMem_Malloc(space_to_alloc); +// if (i_code == NULL) { +// return NULL; +// } +// +// // Copy over bytecode +// for (Py_ssize_t curr = 0; curr < Py_SIZE(co); curr++) { +// _Py_CODEUNIT *curr_instr = _PyCode_CODE(co) + curr; +// // NEED TO TRANSFORM BINARY OPS TO +// i_code->code[curr] = *curr_instr; +// } +// return i_code; +//} + + +static _PyTier2Info * +_PyTier2Info_Initialize(PyCodeObject *co) { - assert(co->_tier2_info != NULL); - // There are only two cases that a BB ends. - // 1. If there's a branch instruction / scope exit. - // 2. If the instruction is a jump target. - _Py_CODEUNIT *instr_end = _PyCode_GetEnd(co); - _Py_CODEUNIT *curr = start; - int *jump_target_offsets = co->_tier2_info->_jump_targets; - int jump_target_count = co->_tier2_info->_jump_target_count; - int curr_jump = 0; - while (curr < instr_end) { - _Py_CODEUNIT instr = *curr; - int opcode = _Py_OPCODE(instr); - if (IS_JUMP_OPCODE(opcode) || IS_SCOPE_EXIT_OPCODE(opcode)) { - return curr; - } - while (_PyCode_CODE(co) + jump_target_offsets[curr_jump] < curr) { - curr_jump++; - } - if (_PyCode_CODE(co) + jump_target_offsets[curr_jump] == curr) { - return curr; - } - curr++; + assert(co->_tier2_info == NULL); + _PyTier2Info *t2_info = PyMem_Malloc(sizeof(_PyTier2Info)); + if (t2_info == NULL) { + return NULL; + } + co->_tier2_info = t2_info; + + //if (_PyIntermediateCode_Initialize(co) == NULL) { + // PyMem_FREE(t2_info); + // return NULL; + //} + + // Next is to intitialize stack space for the tier 2 types meta-interpretr. + t2_info->types_stack = PyMem_Malloc(co->co_stacksize * sizeof(PyObject *)); + if (t2_info->types_stack == NULL) { + PyMem_Free(t2_info); + } + return t2_info; +} + +////////// TYPE CONTEXT FUNCTIONS + +static PyTypeObject ** +initialize_type_context(PyCodeObject *co) { + int nlocals = co->co_nlocals; + PyTypeObject **type_context = PyMem_Malloc(nlocals * sizeof(PyTypeObject *)); + if (type_context == NULL) { + return NULL; } - return instr_end; + // Initialize to uknown type. + for (int i = 0; i < nlocals; i++) { + type_context[i] = NULL; + } + return type_context; } +////////// OVERALL TIER2 FUNCTIONS + + +// 1. Initialize whatever we need. +// 2. Create the entry BB. +// 3. Jump into that BB. static _Py_CODEUNIT * _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) { - int curr = _Py_OPCODE(*(next_instr - 1)); - assert(curr == RESUME); + assert(_Py_OPCODE(*(next_instr - 1)) == RESUME); + + // First check for forbidden opcodes that we currently can't handle. PyCodeObject *co = frame->f_code; - assert(co->_tier2_info == NULL); - _PyTier2Info *t2_info = PyMem_Malloc(sizeof(_PyTier2Info)); + // Impossibly big. + if ((int)Py_SIZE(co) != Py_SIZE(co)) { + return NULL; + } + for (Py_ssize_t curr = 0; curr < Py_SIZE(co); curr++) { + _Py_CODEUNIT *curr_instr = _PyCode_CODE(co) + curr; + if (IS_FORBIDDEN_OPCODE(_PyOpcode_Deopt[_Py_OPCODE(*curr_instr)])) { + return NULL; + } + } + + if (_PyInterpreter_GetScratchSpace(co) == NULL) { + return NULL; + } + + _PyTier2Info *t2_info = _PyTier2Info_Initialize(co); if (t2_info == NULL) { return NULL; } - co->_tier2_info = t2_info; - // 0. Single pass: mark jump targets - // 1. Initialize basic blocks space. - // 2. Create the entry BB (if it is, else the current BB). - // 3. Jump into that BB. - fprintf(stderr, "INITIALIZING %ld\n", Py_SIZE(co)); + +#if BB_DEBUG + fprintf(stderr, "INITIALIZING\n"); +#endif Py_ssize_t space_to_alloc = (sizeof(_PyTier2BB) + _PyCode_NBYTES(co)) * 2; @@ -243,61 +775,33 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) PyMem_Free(t2_info); return NULL; } + if (_PyCode_Tier2FillJumpTargets(co)) { + goto cleanup; + } t2_info->_bb_space = bb_space; - //_Py_CODEUNIT *entry_bb_end = _PyTier2_Code_DetectBB(co, _PyCode_CODE(co)); - _Py_CODEUNIT *entry_bb_end = _PyCode_GetEnd(co); - - _PyTier2BB *bb_ptr = _PyTier2_InitBBNoCheck(bb_space, - entry_bb_end, - _PyCode_CODE(co), - entry_bb_end); - - if (_PyCode_Tier2FillJumpTargets(co)) { + PyTypeObject **type_context = initialize_type_context(co); + if (type_context == NULL) { goto cleanup; } + _PyTier2BB *bb_ptr = _PyTier2_Code_DetectAndEmitBB(co, _PyCode_CODE(co), co->co_nlocals, type_context); + if (bb_ptr == NULL) { + goto cleanup; + } +#if BB_DEBUG + fprintf(stderr, "ENTRY BB END IS: %d\n", (int)(bb_ptr->tier1_end - _PyCode_CODE(co))); +#endif t2_info->_entry_bb = bb_ptr; - // Set the instruction pointer to the next one in the bb - Py_ssize_t offset_from_start = (frame->prev_instr - _PyCode_CODE(co)); - assert(offset_from_start >= -1); - frame->prev_instr = bb_ptr->u_code + offset_from_start; - // _py_set_opcode(next_instr, CACHE); - return bb_ptr->u_code + (next_instr - _PyCode_CODE(co)); + // Set the starting instruction to the entry BB. + // frame->prev_instr = bb_ptr->u_code - 1; + return bb_ptr->u_code; cleanup: + PyMem_Free(t2_info); PyMem_Free(bb_space); return NULL; } - -/* Allocates and initializes a new basic block. If there's not enough space in - the overallocated array, create a new array. - - Make sure to call _PyCode_Tier2Initialize before this! -*/ -static _PyTier2BB * -_PyCode_Tier2BBNew(PyCodeObject *co, _Py_CODEUNIT *instr_start, _Py_CODEUNIT *instr_end) -{ - assert(co->_tier2_info != NULL); - assert(co->_tier2_info->_bb_space != NULL); - - _PyTier2BBSpace *bb_space = co->_tier2_info->_bb_space; - Py_ssize_t amount_to_alloc = (instr_start - instr_end) * sizeof(_Py_CODEUNIT *) + sizeof(_PyTier2BB); - assert(bb_space->water_level + amount_to_alloc == (int)(bb_space->water_level + amount_to_alloc)); - - // Need to allocate a new array. - if (bb_space->water_level + amount_to_alloc > bb_space->max_capacity) { - _PyTier2BBSpace *next_bb_space = _PyTier2_CreateBBSpace(bb_space->max_capacity + amount_to_alloc); - if (next_bb_space == NULL) { - return NULL; - } - next_bb_space->next = bb_space; - // We want to make our bb_space point to the most recent one to get O(1) BB allocations. - co->_tier2_info->_bb_space = next_bb_space; - bb_space = next_bb_space; - } - return _PyTier2_InitBBNoCheck(bb_space, _PyCode_GetEnd(co), instr_start, instr_end); -} From 2aaea4f81e41309b685290d5f1ffb0a019a67ee7 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 13 Feb 2023 16:04:57 +0800 Subject: [PATCH 025/280] Part 2: Drive execution of BBs lazily --- Include/cpython/code.h | 4 +- Include/internal/pycore_code.h | 4 + Lib/opcode.py | 2 +- Python/bytecodes.c | 146 +++++++++++++++++++++++++++++++++ Python/ceval.c | 1 + Python/tier2.c | 90 ++++++++++++++------ 6 files changed, 219 insertions(+), 28 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 4fd9705b9dff0f..592843eedc724b 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -59,9 +59,9 @@ typedef struct { // What the tier 2 interpreter executes typedef struct _PyTier2BB { - _Py_CODEUNIT *successor_bb; + struct _PyTier2BB *successor_bb; // The other BB to go should BB_BRANCH fail. - _Py_CODEUNIT *alternate_bb; + struct _PyTier2BB *alternate_bb; // Array of types. This corresponds to the fast locals array. int type_context_len; PyTypeObject **type_context; diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 392ea9cf83055a..35c958613cdaba 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -241,6 +241,7 @@ extern int _PyStaticCode_Init(PyCodeObject *co); /* Tier 2 interpreter */ extern _Py_CODEUNIT *_PyCode_Tier2Warmup(struct _PyInterpreterFrame *, _Py_CODEUNIT *); +extern _Py_CODEUNIT *_PyTier2BB_ExecuteNextBB(struct _PyInterpreterFrame *frame, _PyTier2BB **curr_bb, int direction); #ifdef Py_STATS @@ -500,6 +501,9 @@ extern uint32_t _Py_next_func_version; #define COMPARISON_NOT_EQUALS (COMPARISON_UNORDERED | COMPARISON_LESS_THAN | COMPARISON_GREATER_THAN) +#define BB_SUC 1 +#define BB_ALT 0 + #ifdef __cplusplus } #endif diff --git a/Lib/opcode.py b/Lib/opcode.py index be1c0dbf8fafe9..02384a86a8132c 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -447,7 +447,7 @@ def pseudo_op(name, op, real_ops): 'BB_EXIT_FRAME', ## These branches correspond to the jump instructions 'BB_TYPE_BRANCH', - 'BB_ITER', # FOR_ITER + 'BB_ITER', # FOR_ITER's null (iterator) check 'BB_BRANCH_OR_POP', # JUMP_IF_FALSE_OR_POP, JUMP_IF_TRUE_OR_POP 'BB_POP_THEN_BRANCH', # POP_JUMP_IF_FALSE, POP_JUMP_IF_TRUE 'BB_POP_BRANCH', # POP_JUMP_IF_NOT_NONE, POP_JUMP_IF_NONE diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 9900ad02bd24b4..8216d4fc636915 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1926,6 +1926,51 @@ dummy_func( } } + inst(BB_POP_THEN_BRANCH, (cond -- )) { + // POP_JUMP_IF_FALSE + if (oparg) { + if (Py_IsTrue(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_SUC); + } + else if (Py_IsFalse(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); + } + else { + int err = PyObject_IsTrue(cond); + Py_DECREF(cond); + if (err == 0) { + next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); + } + else { + ERROR_IF(err < 0, error); + } + } + } + // POP_JUMP_IF_TRUE + else { + if (Py_IsFalse(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_SUC); + } + else if (Py_IsTrue(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); + } + else { + int err = PyObject_IsTrue(cond); + Py_DECREF(cond); + if (err > 0) { + next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); + } + else { + ERROR_IF(err < 0, error); + } + } + } + } + inst(POP_JUMP_IF_NOT_NONE, (value -- )) { if (!Py_IsNone(value)) { Py_DECREF(value); @@ -1946,6 +1991,20 @@ dummy_func( } } + inst(BB_POP_BRANCH, (value--)) { + // oparg 1: POP_JUMP_IF_NOT_NONE + // oparg 0: POP_JUMP_IF_NONE + if (oparg - Py_IsNone(value)) { + Py_DECREF(value); + next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); + } + else { + Py_DECREF(value); + next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_SUC); + } + + } + inst(JUMP_IF_FALSE_OR_POP, (cond -- cond if (jump))) { bool jump = false; int err; @@ -1996,6 +2055,63 @@ dummy_func( } } + inst(BB_BRANCH_OR_POP, cond -- cond if (jump))) { + bool jump = false; + int err; + // JUMP_IF_FALSE_OR_POP + if (oparg) { + if (Py_IsTrue(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_SUC); + } + else if (Py_IsFalse(cond)) { + next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); + jump = true; + } + else { + err = PyObject_IsTrue(cond); + if (err > 0) { + Py_DECREF(cond); + next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_SUC); + } + else if (err == 0) { + next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); + jump = true; + } + else { + goto error; + } + } + + } + else { + // JUMP_IF_TRUE_OR_POP + if (Py_IsFalse(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_SUC); + } + else if (Py_IsTrue(cond)) { + next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); + jump = true; + } + else { + err = PyObject_IsTrue(cond); + if (err > 0) { + next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); + jump = true; + } + else if (err == 0) { + Py_DECREF(cond); + next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_SUC); + } + else { + goto error; + } + } + } + + } + inst(JUMP_BACKWARD_NO_INTERRUPT, (--)) { /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost @@ -2130,6 +2246,29 @@ dummy_func( // Common case: no jump, leave it to the code generator } + // FOR_ITER + inst(BB_ITER, (unused / 1, iter -- iter, next)) { + next = (*Py_TYPE(iter)->tp_iternext)(iter); + if (next == NULL) { + if (_PyErr_Occurred(tstate)) { + if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { + goto error; + } + else if (tstate->c_tracefunc != NULL) { + call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame); + } + _PyErr_Clear(tstate); + } + /* iterator ended normally */ + assert(_Py_OPCODE(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg]) == END_FOR); + Py_DECREF(iter); + STACK_SHRINK(1); + /* Jump forward oparg, then skip following END_FOR instruction */ + next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); + DISPATCH(); + } + } + inst(FOR_ITER_LIST, (unused/1, iter -- iter, next)) { assert(cframe.use_tracing == 0); DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); @@ -3150,6 +3289,13 @@ dummy_func( Py_UNREACHABLE(); } + //// TIER 2 BASIC BLOCK INSTRUCTIONS + //inst(BB_TYPE_BRANCH, (--)) { + // if (should_bb_branch) { + + // } + //} + // END BYTECODES // diff --git a/Python/ceval.c b/Python/ceval.c index a91f5baca8853e..adfc85a80c459b 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -732,6 +732,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int _PyCFrame cframe; _PyInterpreterFrame entry_frame; PyObject *kwnames = NULL; // Borrowed reference. Reset by CALL instructions. + bool should_bb_branch = false; /* WARNING: Because the _PyCFrame lives on the C stack, * but can be accessed from a heap allocated object (tstate) diff --git a/Python/tier2.c b/Python/tier2.c index d84582d8027db6..5407298fa79b0d 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -13,32 +13,10 @@ // BB_BRANCH instruction: 1 #define BB_EPILOG 1 -static _Py_CODEUNIT *_PyCode_Tier2Initialize(_PyInterpreterFrame *, _Py_CODEUNIT *); - static inline int IS_SCOPE_EXIT_OPCODE(int opcode); ////////// CEVAL functions -// Tier 2 warmup counter -_Py_CODEUNIT * -_PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) -{ - PyCodeObject *code = frame->f_code; - if (code->_tier2_warmup != 0) { - code->_tier2_warmup++; - if (code->_tier2_warmup == 0) { - // If it fails, due to lack of memory or whatever, - // just fall back to the tier 1 interpreter. - _Py_CODEUNIT *next = _PyCode_Tier2Initialize(frame, next_instr); - return next_instr; - if (next != NULL) { - return next; - } - } - } - return next_instr; -} - ////////// Utility functions // Checks that we have enough scratch space for the current code object. Else allocate more. @@ -417,6 +395,9 @@ emit_i(_Py_CODEUNIT *write_curr, int opcode, int oparg) return write_curr; } +// Note: we're copying over the actual caches to preserve information! +// This way instructions that we can't type propagate over still stay +// optimized. static inline _Py_CODEUNIT * copy_cache_entries(_Py_CODEUNIT *write_curr, _Py_CODEUNIT *cache, int n_entries) { @@ -447,7 +428,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _Py_CODEUNIT *start, #define JUMPBY(x) i += x + 1; continue; #define BASIC_PUSH(v) (*stack_pointer++ = (v)) #define BASIC_POP() (*--stack_pointer) -#define DISPATCH() write_i = emit_i(write_i, opcode, oparg); write_i = copy_cache_entries(write_i, curr+1, caches); break; +#define DISPATCH() write_i = emit_i(write_i, opcode, oparg); write_i = copy_cache_entries(write_i, curr+1, caches); i += caches; continue; assert(co->_tier2_info != NULL); // There are only two cases that a BB ends. // 1. If there's a branch instruction / scope exit. @@ -481,6 +462,9 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _Py_CODEUNIT *start, _Py_CODEUNIT action; switch (opcode) { + case COMPARE_AND_BRANCH: + opcode = COMPARE_OP; + DISPATCH(); //case LOAD_FAST: // BASIC_PUSH(type_context[oparg]); // DISPATCH(); @@ -543,8 +527,6 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _Py_CODEUNIT *start, DISPATCH(); } - i += caches; - } end: //#if BB_DEBUG @@ -805,3 +787,61 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) PyMem_Free(bb_space); return NULL; } + +////////// CEVAL FUNCTIONS + +// Tier 2 warmup counter +_Py_CODEUNIT * +_PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) +{ + PyCodeObject *code = frame->f_code; + if (code->_tier2_warmup != 0) { + code->_tier2_warmup++; + if (code->_tier2_warmup == 0) { + // If it fails, due to lack of memory or whatever, + // just fall back to the tier 1 interpreter. + _Py_CODEUNIT *next = _PyCode_Tier2Initialize(frame, next_instr); + return next_instr; + if (next != NULL) { + return next; + } + } + } + return next_instr; +} + +// Executes successor/alternate BB, depending on direction +// Lazily generates successive BBs when required. +// direction: 1 for successor, 0 for alternative. +_Py_CODEUNIT * +_PyTier2BB_ExecuteNextBB(_PyInterpreterFrame *frame, _PyTier2BB **curr_bb, int direction) +{ + PyCodeObject *co = frame->f_code; + _PyTier2BB *curr = *curr_bb; + if (BB_SUC) { + if (curr->successor_bb == NULL) { + _PyTier2BB *succ = _PyTier2_Code_DetectAndEmitBB(co, + curr->tier1_end, curr->type_context_len, curr->type_context); + curr->successor_bb = succ; + *curr_bb = succ; + return succ->u_code; + } + else { + *curr_bb = curr->successor_bb; + return curr->successor_bb->u_code; + } + } + else { + if (curr->alternate_bb == NULL) { + _PyTier2BB *alt = _PyTier2_Code_DetectAndEmitBB(co, + curr->tier1_end, curr->type_context_len, curr->type_context); + curr->alternate_bb = alt; + *curr_bb = alt; + return alt->u_code; + } + else { + *curr_bb = curr->alternate_bb; + return curr->alternate_bb->u_code; + } + } +} From c4399022930c203e27ec2041772eaef51081d531 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 15 Feb 2023 00:14:17 +0800 Subject: [PATCH 026/280] Part 2: Drive execution of the BBs --- Include/cpython/code.h | 36 +-- Include/internal/pycore_code.h | 7 +- Include/internal/pycore_interp.h | 5 - Include/internal/pycore_opcode.h | 29 +-- Include/opcode.h | 23 +- Lib/opcode.py | 35 ++- Objects/codeobject.c | 10 +- Python/bytecodes.c | 198 ++++++++-------- Python/ceval.c | 4 +- Python/generated_cases.c.h | 165 +++++++++++++ Python/opcode_metadata.h | 35 +++ Python/pystate.c | 4 - Python/tier2.c | 391 ++++++++++++++----------------- 13 files changed, 555 insertions(+), 387 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 592843eedc724b..ddae5db731a31a 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -57,46 +57,36 @@ typedef struct { //} _PyTier2IntermediateCode; -// What the tier 2 interpreter executes -typedef struct _PyTier2BB { - struct _PyTier2BB *successor_bb; - // The other BB to go should BB_BRANCH fail. - struct _PyTier2BB *alternate_bb; +// Tier 2 interpreter information +typedef struct _PyTier2BBMetadata { // Array of types. This corresponds to the fast locals array. int type_context_len; PyTypeObject **type_context; - //// Stores the end pointer in the intermediate bytecode. - //// So that when we hit BB_BRANCH, we know what's the next - //// thing to generate. - //_Py_CODEUNIT *intermediate_code_end; _Py_CODEUNIT *tier1_end; - // There's extra memory at the end of this. - int n_instrs; - _Py_CODEUNIT u_code[1]; -} _PyTier2BB; - -// Find the start of the BB from u_code. -#define _PyTier2BB_FROM_UCODE(code) (_PyTier2BB *)(((char *)code) - offsetof(_PyTier2BB, u_code)) +} _PyTier2BBMetadata; // Bump allocator for basic blocks (overallocated) typedef struct _PyTier2BBSpace { struct _PyTier2BBSpace *next; - int max_capacity; - // How much space has been consumed in bbs. - int water_level; + // (in bytes) + Py_ssize_t max_capacity; + // How much space has been consumed in bbs. (in bytes) + Py_ssize_t water_level; // There's extra memory at the end of this. - _PyTier2BB bbs[1]; + _Py_CODEUNIT u_code[1]; } _PyTier2BBSpace; +#define _PyTier2BBSpace_NBYTES_USED(space) sizeof(_PyTier2BBSpace) + space->max_capacity + // Tier 2 info stored in the code object. Lazily allocated. typedef struct _PyTier2Info { - _PyTier2BB *_entry_bb; /* the tier 2 basic block to execute (if any) */ + _Py_CODEUNIT *_entry_bb; /* the tier 2 basic block to execute (if any) */ _PyTier2BBSpace *_bb_space; /* linked list storing basic blocks */ //_PyTier2IntermediateCode *i_code; /* intermediate bytecode to generate tier 2 basic blocks */ // Keeps track of offset of jump targets (in number of codeunits) // from co_code_adaptive. - int jump_target_count; - int *jump_targets; + int backward_jump_count; + int *backward_jump_offsets; PyTypeObject **types_stack; } _PyTier2Info; diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 35c958613cdaba..37cbdaa65bc862 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -92,6 +92,12 @@ typedef struct { #define INLINE_CACHE_ENTRIES_FOR_ITER CACHE_ENTRIES(_PyForIterCache) +typedef struct { + uint16_t offset[2]; +} _PyBBBranchCache; + +#define INLINE_CACHE_ENTRIES_BB_BRANCH CACHE_ENTRIES(_PyBBBranchCache) + // Borrowed references to common callables: struct callable_cache { PyObject *isinstance; @@ -241,7 +247,6 @@ extern int _PyStaticCode_Init(PyCodeObject *co); /* Tier 2 interpreter */ extern _Py_CODEUNIT *_PyCode_Tier2Warmup(struct _PyInterpreterFrame *, _Py_CODEUNIT *); -extern _Py_CODEUNIT *_PyTier2BB_ExecuteNextBB(struct _PyInterpreterFrame *frame, _PyTier2BB **curr_bb, int direction); #ifdef Py_STATS diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 371e9071de67af..2c66da0f95d4bc 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -186,11 +186,6 @@ struct _is { struct _Py_interp_cached_objects cached_objects; struct _Py_interp_static_objects static_objects; - // TIER 2 INTERPRETER INFORMATION - - // Bytecode scratchspace when emitting tier 2 bytecode. - int tier2_bytecode_scratchsize; - _Py_CODEUNIT *tier2_bytecode_scratch; /* The following fields are here to avoid allocation during init. The data is exposed through PyInterpreterState pointer fields. diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 7e7908d543683b..e35db6f12e41e1 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -397,23 +397,23 @@ static const char *const _PyOpcode_OpName[263] = { [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", - [BB_ENTER_FRAME] = "BB_ENTER_FRAME", - [BB_EXIT_FRAME] = "BB_EXIT_FRAME", - [BB_TYPE_BRANCH] = "BB_TYPE_BRANCH", - [BB_ITER] = "BB_ITER", + [BB_BRANCH] = "BB_BRANCH", + [BB_BRANCH_IF_FLAG_UNSET] = "BB_BRANCH_IF_FLAG_UNSET", + [BB_BRANCH_IF_FLAG_SET] = "BB_BRANCH_IF_FLAG_SET", + [BB_TEST_ITER] = "BB_TEST_ITER", [CALL] = "CALL", [KW_NAMES] = "KW_NAMES", [CALL_INTRINSIC_1] = "CALL_INTRINSIC_1", - [BB_BRANCH_OR_POP] = "BB_BRANCH_OR_POP", - [BB_POP_THEN_BRANCH] = "BB_POP_THEN_BRANCH", - [BB_POP_BRANCH] = "BB_POP_BRANCH", + [BB_TEST_IF_FALSE_OR_POP] = "BB_TEST_IF_FALSE_OR_POP", + [BB_TEST_IF_TRUE_OR_POP] = "BB_TEST_IF_TRUE_OR_POP", + [BB_TEST_POP_IF_FALSE] = "BB_TEST_POP_IF_FALSE", + [BB_TEST_POP_IF_TRUE] = "BB_TEST_POP_IF_TRUE", + [BB_TEST_POP_IF_NOT_NONE] = "BB_TEST_POP_IF_NOT_NONE", + [BB_TEST_POP_IF_NONE] = "BB_TEST_POP_IF_NONE", + [BB_JUMP_BACKWARD] = "BB_JUMP_BACKWARD", + [BB_JUMP_BACKWARD_LAZY] = "BB_JUMP_BACKWARD_LAZY", [BINARY_CHECK_INT] = "BINARY_CHECK_INT", [BINARY_OP_ADD_INT_REST] = "BINARY_OP_ADD_INT_REST", - [179] = "<179>", - [180] = "<180>", - [181] = "<181>", - [182] = "<182>", - [183] = "<183>", [184] = "<184>", [185] = "<185>", [186] = "<186>", @@ -498,11 +498,6 @@ static const char *const _PyOpcode_OpName[263] = { #define EXTRA_CASES \ - case 179: \ - case 180: \ - case 181: \ - case 182: \ - case 183: \ case 184: \ case 185: \ case 186: \ diff --git a/Include/opcode.h b/Include/opcode.h index d8569fe97b31b9..45efe80f66bae6 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -253,15 +253,20 @@ extern "C" { #define UNPACK_SEQUENCE_TUPLE 161 #define UNPACK_SEQUENCE_TWO_TUPLE 166 #define DO_TRACING 255 -#define BB_ENTER_FRAME 167 -#define BB_EXIT_FRAME 168 -#define BB_TYPE_BRANCH 169 -#define BB_ITER 170 -#define BB_BRANCH_OR_POP 174 -#define BB_POP_THEN_BRANCH 175 -#define BB_POP_BRANCH 176 -#define BINARY_CHECK_INT 177 -#define BINARY_OP_ADD_INT_REST 178 +#define BB_BRANCH 167 +#define BB_BRANCH_IF_FLAG_UNSET 168 +#define BB_BRANCH_IF_FLAG_SET 169 +#define BB_TEST_ITER 170 +#define BB_TEST_IF_FALSE_OR_POP 174 +#define BB_TEST_IF_TRUE_OR_POP 175 +#define BB_TEST_POP_IF_FALSE 176 +#define BB_TEST_POP_IF_TRUE 177 +#define BB_TEST_POP_IF_NOT_NONE 178 +#define BB_TEST_POP_IF_NONE 179 +#define BB_JUMP_BACKWARD 180 +#define BB_JUMP_BACKWARD_LAZY 181 +#define BINARY_CHECK_INT 182 +#define BINARY_OP_ADD_INT_REST 183 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/opcode.py b/Lib/opcode.py index 02384a86a8132c..a04a3b0070d77a 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -443,14 +443,33 @@ def pseudo_op(name, op, real_ops): ] _uops = [ # Tier 2 BB opcodes - 'BB_ENTER_FRAME', - 'BB_EXIT_FRAME', - ## These branches correspond to the jump instructions - 'BB_TYPE_BRANCH', - 'BB_ITER', # FOR_ITER's null (iterator) check - 'BB_BRANCH_OR_POP', # JUMP_IF_FALSE_OR_POP, JUMP_IF_TRUE_OR_POP - 'BB_POP_THEN_BRANCH', # POP_JUMP_IF_FALSE, POP_JUMP_IF_TRUE - 'BB_POP_BRANCH', # POP_JUMP_IF_NOT_NONE, POP_JUMP_IF_NONE + # Frame creation + # 'BB_ENTER_FRAME', + # 'BB_EXIT_FRAME', + # Initial generic branching instruction. + 'BB_BRANCH', + # The BB_BRANCH transitions to one of these two. + # This happens when the fall through is generated, but not the other branch. + 'BB_BRANCH_IF_FLAG_UNSET', + 'BB_BRANCH_IF_FLAG_SET', + # The final form is that once both branches are generated, we can just + # override these instructions with a generic JUMP. + + # These tests correspond to the jump instructions + # FOR_ITER's null (iterator) check + 'BB_TEST_ITER', + # JUMP_IF_FALSE_OR_POP, JUMP_IF_TRUE_OR_POP + 'BB_TEST_IF_FALSE_OR_POP', + 'BB_TEST_IF_TRUE_OR_POP', + # POP_JUMP_IF_FALSE, POP_JUMP_IF_TRUE + 'BB_TEST_POP_IF_FALSE', + 'BB_TEST_POP_IF_TRUE', + # POP_JUMP_IF_NOT_NONE, POP_JUMP_IF_NONE + 'BB_TEST_POP_IF_NOT_NONE', + 'BB_TEST_POP_IF_NONE', + # JUMP_BACKWARD + 'BB_JUMP_BACKWARD', + 'BB_JUMP_BACKWARD_LAZY', # Common type checks # These instructions check that one operand is a certain type. diff --git a/Objects/codeobject.c b/Objects/codeobject.c index bdc31b6216304f..8e2b20e2dd7da4 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1683,16 +1683,16 @@ code_tier2_fini(PyCodeObject *co) t2_info->_bb_space = NULL; } - if (t2_info->jump_target_count > 0 && - t2_info->jump_targets != NULL) { - PyMem_Free(t2_info->jump_targets); - t2_info->jump_targets = NULL; + if (t2_info->backward_jump_count > 0 && + t2_info->backward_jump_offsets != NULL) { + PyMem_Free(t2_info->backward_jump_offsets); + t2_info->backward_jump_offsets = NULL; } if (t2_info->types_stack != NULL) { PyMem_Free(t2_info->types_stack); t2_info->types_stack = NULL; } - t2_info->jump_target_count = 0; + t2_info->backward_jump_count = 0; PyMem_Free(t2_info); //if (t2_info->i_code != NULL) { // if (t2_info->i_code->_jump_targets != NULL) { diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 8216d4fc636915..74cf30ba8b3cab 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1906,6 +1906,27 @@ dummy_func( } } + inst(BB_TEST_POP_IF_FALSE, (cond -- )) { + if (Py_IsTrue(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + bb_test = true; + } + else if (Py_IsFalse(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + bb_test = false; + } + else { + int err = PyObject_IsTrue(cond); + Py_DECREF(cond); + if (err == 0) { + bb_test = false; + } + else { + ERROR_IF(err < 0, error); + } + } + } + inst(POP_JUMP_IF_TRUE, (cond -- )) { if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); @@ -1926,51 +1947,28 @@ dummy_func( } } - inst(BB_POP_THEN_BRANCH, (cond -- )) { - // POP_JUMP_IF_FALSE - if (oparg) { - if (Py_IsTrue(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_SUC); - } - else if (Py_IsFalse(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); - } - else { - int err = PyObject_IsTrue(cond); - Py_DECREF(cond); - if (err == 0) { - next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); - } - else { - ERROR_IF(err < 0, error); - } - } + inst(BB_TEST_POP_IF_TRUE, (cond -- )) { + if (Py_IsFalse(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + bb_test = true; + } + else if (Py_IsTrue(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + bb_test = false; } - // POP_JUMP_IF_TRUE else { - if (Py_IsFalse(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_SUC); - } - else if (Py_IsTrue(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); + int err = PyObject_IsTrue(cond); + Py_DECREF(cond); + if (err > 0) { + bb_test = false; } else { - int err = PyObject_IsTrue(cond); - Py_DECREF(cond); - if (err > 0) { - next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); - } - else { - ERROR_IF(err < 0, error); - } + ERROR_IF(err < 0, error); } } } + inst(POP_JUMP_IF_NOT_NONE, (value -- )) { if (!Py_IsNone(value)) { Py_DECREF(value); @@ -1981,6 +1979,17 @@ dummy_func( } } + inst(BB_TEST_POP_IF_NOT_NONE, (value -- )) { + if (!Py_IsNone(value)) { + Py_DECREF(value); + bb_test = false; + } + else { + _Py_DECREF_NO_DEALLOC(value); + bb_test = true; + } + } + inst(POP_JUMP_IF_NONE, (value -- )) { if (Py_IsNone(value)) { _Py_DECREF_NO_DEALLOC(value); @@ -1991,18 +2000,15 @@ dummy_func( } } - inst(BB_POP_BRANCH, (value--)) { - // oparg 1: POP_JUMP_IF_NOT_NONE - // oparg 0: POP_JUMP_IF_NONE - if (oparg - Py_IsNone(value)) { - Py_DECREF(value); - next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); + inst(BB_TEST_POP_IF_NONE, (value -- )) { + if (Py_IsNone(value)) { + _Py_DECREF_NO_DEALLOC(value); + bb_test = false; } else { Py_DECREF(value); - next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_SUC); + bb_test = true; } - } inst(JUMP_IF_FALSE_OR_POP, (cond -- cond if (jump))) { @@ -2030,6 +2036,33 @@ dummy_func( } } + inst(BB_TEST_IF_FALSE_OR_POP, (cond -- cond if (jump))) { + bool jump = false; + int err; + if (Py_IsTrue(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + bb_test = true; + } + else if (Py_IsFalse(cond)) { + bb_test = false; + jump = true; + } + else { + err = PyObject_IsTrue(cond); + if (err > 0) { + bb_test = true; + Py_DECREF(cond); + } + else if (err == 0) { + bb_test = false; + jump = true; + } + else { + goto error; + } + } + } + inst(JUMP_IF_TRUE_OR_POP, (cond -- cond if (jump))) { bool jump = false; int err; @@ -2055,61 +2088,31 @@ dummy_func( } } - inst(BB_BRANCH_OR_POP, cond -- cond if (jump))) { + inst(BB_TEST_IF_TRUE_OR_POP, (cond -- cond if (jump))) { bool jump = false; int err; - // JUMP_IF_FALSE_OR_POP - if (oparg) { - if (Py_IsTrue(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_SUC); - } - else if (Py_IsFalse(cond)) { - next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); - jump = true; - } - else { - err = PyObject_IsTrue(cond); - if (err > 0) { - Py_DECREF(cond); - next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_SUC); - } - else if (err == 0) { - next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); - jump = true; - } - else { - goto error; - } - } - + if (Py_IsFalse(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + bb_test = true; + } + else if (Py_IsTrue(cond)) { + bb_test = false; + jump = true; } else { - // JUMP_IF_TRUE_OR_POP - if (Py_IsFalse(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_SUC); - } - else if (Py_IsTrue(cond)) { - next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); + err = PyObject_IsTrue(cond); + if (err > 0) { + bb_test = false; jump = true; } + else if (err == 0) { + bb_test = true; + Py_DECREF(cond); + } else { - err = PyObject_IsTrue(cond); - if (err > 0) { - next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); - jump = true; - } - else if (err == 0) { - Py_DECREF(cond); - next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_SUC); - } - else { - goto error; - } + goto error; } } - } inst(JUMP_BACKWARD_NO_INTERRUPT, (--)) { @@ -2247,7 +2250,7 @@ dummy_func( } // FOR_ITER - inst(BB_ITER, (unused / 1, iter -- iter, next)) { + inst(BB_TEST_ITER, (unused / 1, iter -- iter, next)) { next = (*Py_TYPE(iter)->tp_iternext)(iter); if (next == NULL) { if (_PyErr_Occurred(tstate)) { @@ -2263,10 +2266,9 @@ dummy_func( assert(_Py_OPCODE(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg]) == END_FOR); Py_DECREF(iter); STACK_SHRINK(1); - /* Jump forward oparg, then skip following END_FOR instruction */ - next_instr = _PyTier2BB_ExecuteNextBB(frame, &curr_bb, BB_ALT); - DISPATCH(); + bb_test = false; } + bb_test = true; } inst(FOR_ITER_LIST, (unused/1, iter -- iter, next)) { @@ -3289,12 +3291,6 @@ dummy_func( Py_UNREACHABLE(); } - //// TIER 2 BASIC BLOCK INSTRUCTIONS - //inst(BB_TYPE_BRANCH, (--)) { - // if (should_bb_branch) { - - // } - //} // END BYTECODES // diff --git a/Python/ceval.c b/Python/ceval.c index adfc85a80c459b..ca8f2705f688f9 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -732,7 +732,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int _PyCFrame cframe; _PyInterpreterFrame entry_frame; PyObject *kwnames = NULL; // Borrowed reference. Reset by CALL instructions. - bool should_bb_branch = false; + // true = successor + // false = alternate + bool bb_test = true; /* WARNING: Because the _PyCFrame lives on the C stack, * but can be accessed from a heap allocated object (tstate) diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 86125e4a5c3347..0fe44f7c663d40 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2447,6 +2447,30 @@ DISPATCH(); } + TARGET(BB_TEST_POP_IF_FALSE) { + PyObject *cond = PEEK(1); + if (Py_IsTrue(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + bb_test = true; + } + else if (Py_IsFalse(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + bb_test = false; + } + else { + int err = PyObject_IsTrue(cond); + Py_DECREF(cond); + if (err == 0) { + bb_test = false; + } + else { + if (err < 0) goto pop_1_error; + } + } + STACK_SHRINK(1); + DISPATCH(); + } + TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = PEEK(1); if (Py_IsFalse(cond)) { @@ -2470,6 +2494,30 @@ DISPATCH(); } + TARGET(BB_TEST_POP_IF_TRUE) { + PyObject *cond = PEEK(1); + if (Py_IsFalse(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + bb_test = true; + } + else if (Py_IsTrue(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + bb_test = false; + } + else { + int err = PyObject_IsTrue(cond); + Py_DECREF(cond); + if (err > 0) { + bb_test = false; + } + else { + if (err < 0) goto pop_1_error; + } + } + STACK_SHRINK(1); + DISPATCH(); + } + TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = PEEK(1); if (!Py_IsNone(value)) { @@ -2483,6 +2531,20 @@ DISPATCH(); } + TARGET(BB_TEST_POP_IF_NOT_NONE) { + PyObject *value = PEEK(1); + if (!Py_IsNone(value)) { + Py_DECREF(value); + bb_test = false; + } + else { + _Py_DECREF_NO_DEALLOC(value); + bb_test = true; + } + STACK_SHRINK(1); + DISPATCH(); + } + TARGET(POP_JUMP_IF_NONE) { PyObject *value = PEEK(1); if (Py_IsNone(value)) { @@ -2496,6 +2558,20 @@ DISPATCH(); } + TARGET(BB_TEST_POP_IF_NONE) { + PyObject *value = PEEK(1); + if (Py_IsNone(value)) { + _Py_DECREF_NO_DEALLOC(value); + bb_test = false; + } + else { + Py_DECREF(value); + bb_test = true; + } + STACK_SHRINK(1); + DISPATCH(); + } + TARGET(JUMP_IF_FALSE_OR_POP) { PyObject *cond = PEEK(1); bool jump = false; @@ -2525,6 +2601,37 @@ DISPATCH(); } + TARGET(BB_TEST_IF_FALSE_OR_POP) { + PyObject *cond = PEEK(1); + bool jump = false; + int err; + if (Py_IsTrue(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + bb_test = true; + } + else if (Py_IsFalse(cond)) { + bb_test = false; + jump = true; + } + else { + err = PyObject_IsTrue(cond); + if (err > 0) { + bb_test = true; + Py_DECREF(cond); + } + else if (err == 0) { + bb_test = false; + jump = true; + } + else { + goto error; + } + } + STACK_SHRINK(1); + STACK_GROW((jump ? 1 : 0)); + DISPATCH(); + } + TARGET(JUMP_IF_TRUE_OR_POP) { PyObject *cond = PEEK(1); bool jump = false; @@ -2554,6 +2661,37 @@ DISPATCH(); } + TARGET(BB_TEST_IF_TRUE_OR_POP) { + PyObject *cond = PEEK(1); + bool jump = false; + int err; + if (Py_IsFalse(cond)) { + _Py_DECREF_NO_DEALLOC(cond); + bb_test = true; + } + else if (Py_IsTrue(cond)) { + bb_test = false; + jump = true; + } + else { + err = PyObject_IsTrue(cond); + if (err > 0) { + bb_test = false; + jump = true; + } + else if (err == 0) { + bb_test = true; + Py_DECREF(cond); + } + else { + goto error; + } + } + STACK_SHRINK(1); + STACK_GROW((jump ? 1 : 0)); + DISPATCH(); + } + TARGET(JUMP_BACKWARD_NO_INTERRUPT) { /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost @@ -2721,6 +2859,33 @@ DISPATCH(); } + TARGET(BB_TEST_ITER) { + PyObject *iter = PEEK(1); + PyObject *next; + next = (*Py_TYPE(iter)->tp_iternext)(iter); + if (next == NULL) { + if (_PyErr_Occurred(tstate)) { + if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { + goto error; + } + else if (tstate->c_tracefunc != NULL) { + call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame); + } + _PyErr_Clear(tstate); + } + /* iterator ended normally */ + assert(_Py_OPCODE(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg]) == END_FOR); + Py_DECREF(iter); + STACK_SHRINK(1); + bb_test = false; + } + bb_test = true; + STACK_GROW(1); + POKE(1, next); + JUMPBY(1); + DISPATCH(); + } + TARGET(FOR_ITER_LIST) { PyObject *iter = PEEK(1); PyObject *next; diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index d4ac2d2b43ecd2..424f78f657bdaa 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -242,16 +242,28 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 0; case POP_JUMP_IF_FALSE: return 1; + case BB_TEST_POP_IF_FALSE: + return 1; case POP_JUMP_IF_TRUE: return 1; + case BB_TEST_POP_IF_TRUE: + return 1; case POP_JUMP_IF_NOT_NONE: return 1; + case BB_TEST_POP_IF_NOT_NONE: + return 1; case POP_JUMP_IF_NONE: return 1; + case BB_TEST_POP_IF_NONE: + return 1; case JUMP_IF_FALSE_OR_POP: return 1; + case BB_TEST_IF_FALSE_OR_POP: + return 1; case JUMP_IF_TRUE_OR_POP: return 1; + case BB_TEST_IF_TRUE_OR_POP: + return 1; case JUMP_BACKWARD_NO_INTERRUPT: return 0; case GET_LEN: @@ -270,6 +282,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 1; case FOR_ITER: return 1; + case BB_TEST_ITER: + return 1; case FOR_ITER_LIST: return 1; case FOR_ITER_TUPLE: @@ -596,16 +610,28 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case POP_JUMP_IF_FALSE: return 0; + case BB_TEST_POP_IF_FALSE: + return 0; case POP_JUMP_IF_TRUE: return 0; + case BB_TEST_POP_IF_TRUE: + return 0; case POP_JUMP_IF_NOT_NONE: return 0; + case BB_TEST_POP_IF_NOT_NONE: + return 0; case POP_JUMP_IF_NONE: return 0; + case BB_TEST_POP_IF_NONE: + return 0; case JUMP_IF_FALSE_OR_POP: return (jump ? 1 : 0); + case BB_TEST_IF_FALSE_OR_POP: + return (jump ? 1 : 0); case JUMP_IF_TRUE_OR_POP: return (jump ? 1 : 0); + case BB_TEST_IF_TRUE_OR_POP: + return (jump ? 1 : 0); case JUMP_BACKWARD_NO_INTERRUPT: return 0; case GET_LEN: @@ -624,6 +650,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 1; case FOR_ITER: return 2; + case BB_TEST_ITER: + return 2; case FOR_ITER_LIST: return 2; case FOR_ITER_TUPLE: @@ -836,11 +864,17 @@ struct opcode_metadata { [JUMP_FORWARD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [JUMP_BACKWARD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [POP_JUMP_IF_FALSE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [BB_TEST_POP_IF_FALSE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [POP_JUMP_IF_TRUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [BB_TEST_POP_IF_TRUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [POP_JUMP_IF_NOT_NONE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [BB_TEST_POP_IF_NOT_NONE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [POP_JUMP_IF_NONE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [BB_TEST_POP_IF_NONE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [JUMP_IF_FALSE_OR_POP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [BB_TEST_IF_FALSE_OR_POP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [JUMP_IF_TRUE_OR_POP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [BB_TEST_IF_TRUE_OR_POP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [JUMP_BACKWARD_NO_INTERRUPT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [GET_LEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [MATCH_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, @@ -850,6 +884,7 @@ struct opcode_metadata { [GET_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [GET_YIELD_FROM_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [FOR_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, + [BB_TEST_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, [FOR_ITER_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, [FOR_ITER_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, [FOR_ITER_RANGE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, diff --git a/Python/pystate.c b/Python/pystate.c index d79ba19bf09bff..1261092d1435fa 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -643,10 +643,6 @@ init_interpreter(PyInterpreterState *interp, PyConfig_InitPythonConfig(&interp->config); _PyType_InitCache(interp); - // Tier 2 interpreter information - interp->tier2_bytecode_scratchsize = 0; - interp->tier2_bytecode_scratch = NULL; - interp->_initialized = 1; } diff --git a/Python/tier2.c b/Python/tier2.c index 5407298fa79b0d..406cf340f10cd5 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -10,43 +10,29 @@ #define BB_DEBUG 1 // Number of potential extra instructions at end of a BB, for branch or cleanup purposes. -// BB_BRANCH instruction: 1 -#define BB_EPILOG 1 +#define BB_EPILOG 0 static inline int IS_SCOPE_EXIT_OPCODE(int opcode); -////////// CEVAL functions - -////////// Utility functions +////////// TYPE CONTEXT FUNCTIONS -// Checks that we have enough scratch space for the current code object. Else allocate more. -static _Py_CODEUNIT * -_PyInterpreter_GetScratchSpace(PyCodeObject *co) -{ - PyInterpreterState *interp = _PyInterpreterState_GET(); - int n_instrs = (int)Py_SIZE(co); - Py_ssize_t space_to_alloc = _PyCode_NBYTES(co); - int overalloc = 2; - if (interp->tier2_bytecode_scratchsize == 0 || - interp->tier2_bytecode_scratch == NULL) { - interp->tier2_bytecode_scratch = PyMem_Malloc(space_to_alloc * overalloc); - if (interp->tier2_bytecode_scratch == NULL) { - return NULL; - } - interp->tier2_bytecode_scratchsize = Py_SIZE(co) * overalloc; - return interp->tier2_bytecode_scratch; +static PyTypeObject ** +initialize_type_context(PyCodeObject *co, int *type_context_len) { + int nlocals = co->co_nlocals; + PyTypeObject **type_context = PyMem_Malloc(nlocals * sizeof(PyTypeObject *)); + if (type_context == NULL) { + return NULL; } - if (interp->tier2_bytecode_scratchsize < n_instrs) { - PyMem_Free(interp->tier2_bytecode_scratch); - interp->tier2_bytecode_scratch = PyMem_Malloc(space_to_alloc * overalloc); - if (interp->tier2_bytecode_scratch == NULL) { - return NULL; - } - interp->tier2_bytecode_scratchsize = Py_SIZE(co) * overalloc; + // Initialize to uknown type. + for (int i = 0; i < nlocals; i++) { + type_context[i] = NULL; } - return interp->tier2_bytecode_scratch; + *type_context_len = nlocals; + return type_context; } +////////// Utility functions + // Gets end of the bytecode for a code object. _Py_CODEUNIT * _PyCode_GetEnd(PyCodeObject *co) @@ -73,12 +59,12 @@ _PyCode_GetLogicalEnd(PyCodeObject *co) return end; } -// Gets end of the bytecode for a tier 2 BB. -_Py_CODEUNIT * -_PyTier2BB_UCodeEnd(_PyTier2BB *bb) -{ - return (_Py_CODEUNIT *)(bb->u_code + bb->n_instrs); -} +//// Gets end of the bytecode for a tier 2 BB. +//_Py_CODEUNIT * +//_PyTier2BB_UCodeEnd(_PyTier2BB *bb) +//{ +// return (_Py_CODEUNIT *)(bb->u_code + bb->n_instrs); +//} ////////// BB SPACE FUNCTIONS @@ -92,63 +78,60 @@ _PyTier2_CreateBBSpace(Py_ssize_t space_to_alloc) } bb_space->next = NULL; bb_space->water_level = 0; - assert((int)(space_to_alloc - sizeof(_PyTier2BB)) == (space_to_alloc - sizeof(_PyTier2BB))); - bb_space->max_capacity = (int)(space_to_alloc - sizeof(_PyTier2BB)); + bb_space->max_capacity = (space_to_alloc - sizeof(_PyTier2BBSpace)); return bb_space; } -////////// TIER 2 BB FUNCTIONS - -/* Init a BB in BB space without any checks for waterlevel. */ -static _PyTier2BB * -_PyTier2_InitBBNoCheck(_PyTier2BBSpace *bb_space, _Py_CODEUNIT *tier1_end, - _Py_CODEUNIT *instr_start, _Py_CODEUNIT *instr_end) -{ - Py_ssize_t ninstrs = (instr_end - instr_start) + BB_EPILOG; - assert(ninstrs == (int)ninstrs); - Py_ssize_t nbytes = ninstrs * sizeof(_Py_CODEUNIT); - _PyTier2BB *bb_ptr = &bb_space->bbs[bb_space->water_level]; - bb_ptr->tier1_end = tier1_end; - bb_ptr->n_instrs = (int)ninstrs; - bb_ptr->successor_bb = NULL; - bb_ptr->alternate_bb = NULL; - // @TODO, add type context. - memcpy(bb_ptr->u_code, (const void *)instr_start, nbytes); - assert(bb_space->water_level + nbytes == (int)nbytes); - bb_space->water_level += (int)nbytes; - return bb_ptr; -} - -/* Allocates and initializes a new basic block. If there's not enough space in - the overallocated array, create a new array. - - Make sure to call _PyCode_Tier2Initialize before this! -*/ -static _PyTier2BB * -_PyCode_Tier2BBNew(PyCodeObject *co, _Py_CODEUNIT *tier1_end, _Py_CODEUNIT *instr_start, _Py_CODEUNIT *instr_end) +static _PyTier2BBSpace * +_PyTier2_BBSpaceCheckAndReallocIfNeeded(PyCodeObject *co, Py_ssize_t space_requested) { assert(co->_tier2_info != NULL); assert(co->_tier2_info->_bb_space != NULL); - - _PyTier2BBSpace *bb_space = co->_tier2_info->_bb_space; - Py_ssize_t amount_to_alloc = (instr_start - instr_end) * sizeof(_Py_CODEUNIT *) + sizeof(_PyTier2BB); - assert(bb_space->water_level + amount_to_alloc == (int)(bb_space->water_level + amount_to_alloc)); - - // Need to allocate a new array. - if (bb_space->water_level + amount_to_alloc > bb_space->max_capacity) { - _PyTier2BBSpace *next_bb_space = _PyTier2_CreateBBSpace(bb_space->max_capacity + amount_to_alloc); - if (next_bb_space == NULL) { + _PyTier2BBSpace *curr = co->_tier2_info->_bb_space; + // Note: overallocate + Py_ssize_t new_size = sizeof(_PyTier2BBSpace) + (curr->water_level + space_requested) * 2; + // Overflow or over max capacity + if (new_size < 0 || curr->water_level + space_requested > curr->max_capacity) { + // Try realloc first + if (PyMem_Realloc(curr, new_size) == NULL) { + // Too much trouble. just fall back to tier 1 + //// Try malloc then memcpy if realloc fails (which it might for a large reallocation) + //_PyTier2BBSpace *new_space = PyMem_Malloc(new_size); + //if (new_space == NULL) { + // return NULL; + //} + //memcpy(new_space, curr, _PyTier2BBSpace_NBYTES_USED(curr)); + //PyMem_Free(curr); + //co->_tier2_info->_bb_space = new_space; + //return new_space; return NULL; } - next_bb_space->next = bb_space; - // We want to make our bb_space point to the most recent one to get O(1) BB allocations. - co->_tier2_info->_bb_space = next_bb_space; - bb_space = next_bb_space; } - return _PyTier2_InitBBNoCheck(bb_space, tier1_end, instr_start, instr_end); + return curr; } +static _PyTier2BBMetadata * +_PyTier2_AllocateBBMetaData(PyCodeObject *co, _Py_CODEUNIT *tier1_end) +{ + int type_context_len = 0; + PyTypeObject **type_context = initialize_type_context(co, &type_context_len); + if (type_context == NULL) { + return NULL; + } + + _PyTier2BBMetadata *metadata = PyMem_Malloc(sizeof(_PyTier2BBMetadata)); + if (metadata == NULL) { + PyMem_Free(type_context); + return NULL; + } + + metadata->tier1_end = tier1_end; + metadata->type_context = type_context; + metadata->type_context_len = type_context_len; + return metadata; +} + /* Opcode detection functions. Keep in sync with compile.c and dis! */ // dis.hasjabs @@ -182,6 +165,13 @@ IS_JREL_OPCODE(int opcode) } } +static inline int +IS_JUMP_BACKWARDS_OPCODE(int opcode) +{ + return opcode == JUMP_BACKWARD_NO_INTERRUPT || opcode == JUMP_BACKWARD; +} + + // dis.hasjrel || dis.hasjabs static inline int IS_JUMP_OPCODE(int opcode) @@ -316,35 +306,44 @@ emit_type_guard(_Py_CODEUNIT *write_curr, _Py_CODEUNIT guard) { *write_curr = guard; write_curr++; - _py_set_opcode(write_curr, BB_TYPE_BRANCH); + _py_set_opcode(write_curr, BB_BRANCH); write_curr++; return write_curr; } static inline _Py_CODEUNIT * -emit_logical_branch(_Py_CODEUNIT *write_curr, int branch) +emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int code_offset) { int opcode; - int oparg = 0; + int oparg = _Py_OPARG(branch); // @TODO handle JUMP_BACKWARDS and JUMP_BACKWARDS_NO_INTERRUPT - switch (branch) { + switch (_Py_OPCODE(branch)) { + case JUMP_BACKWARD: + // The initial backwards jump needs to find the right basic block. + // Subsequent jumps don't need to check this anymore. They can just + // jump directly with BB_JUMP_BACKWARD. + opcode = BB_JUMP_BACKWARD_LAZY; + break; case FOR_ITER: - opcode = BB_ITER; + opcode = BB_TEST_ITER; break; case JUMP_IF_FALSE_OR_POP: - oparg = 1; + opcode = BB_TEST_IF_FALSE_OR_POP; + break; case JUMP_IF_TRUE_OR_POP: - opcode = BB_BRANCH_OR_POP; + opcode = BB_TEST_IF_TRUE_OR_POP; break; case POP_JUMP_IF_FALSE: - oparg = 1; + opcode = BB_TEST_POP_IF_FALSE; + break; case POP_JUMP_IF_TRUE: - opcode = BB_POP_THEN_BRANCH; + opcode = BB_TEST_POP_IF_TRUE; break; case POP_JUMP_IF_NOT_NONE: - oparg = 1; + opcode = BB_TEST_POP_IF_NOT_NONE; + break; case POP_JUMP_IF_NONE: - opcode = BB_POP_BRANCH; + opcode = BB_TEST_POP_IF_NONE; break; default: // Honestly shouldn't happen because branches that @@ -357,30 +356,46 @@ emit_logical_branch(_Py_CODEUNIT *write_curr, int branch) #if BB_DEBUG fprintf(stderr, "emitted logical branch\n"); #endif + // We prefix with an empty EXTENDED_ARG, just in case the future jumps + // are not large enough to handle the bytecode format. + _py_set_opcode(write_curr, EXTENDED_ARG); + write_curr->oparg = 0; + write_curr++; _py_set_opcode(write_curr, opcode); write_curr->oparg = oparg; write_curr++; + // Each guard also holds 2 CACHE entries. This stores an int32 of the + // offset from start of the code object (in _Py_CODEUNITs) that the current guard + // can generate the basic block from. + _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; + _py_set_opcode(write_curr, CACHE); + write_curr++; + _py_set_opcode(write_curr, CACHE); + write_curr++; + write_u32(cache->offset, (uint32_t)code_offset); return write_curr; } static inline _Py_CODEUNIT * -emit_scope_exit(_Py_CODEUNIT *write_curr, int exit) +emit_scope_exit(_Py_CODEUNIT *write_curr, _Py_CODEUNIT exit) { - switch (exit) { + switch (_Py_OPCODE(exit)) { case RETURN_VALUE: case RETURN_CONST: case INTERPRETER_EXIT: #if BB_DEBUG fprintf(stderr, "emitted scope exit\n"); #endif - // @TODO we can propogate and chain BBs across call boundaries - // Thanks to CPython's inlined call frames. - _py_set_opcode(write_curr, BB_EXIT_FRAME); - return write_curr + 1; + //// @TODO we can propogate and chain BBs across call boundaries + //// Thanks to CPython's inlined call frames. + //_py_set_opcode(write_curr, BB_EXIT_FRAME); + *write_curr = exit; + write_curr++; + return write_curr; default: // The rest are forbidden. #if BB_DEBUG - fprintf(stderr, "emit_scope_exit unreachable %d\n", exit); + fprintf(stderr, "emit_scope_exit unreachable %d\n", _Py_OPCODE(exit)); #endif Py_UNREACHABLE(); } @@ -410,7 +425,7 @@ copy_cache_entries(_Py_CODEUNIT *write_curr, _Py_CODEUNIT *cache, int n_entries) } // Detects a BB from the current instruction start to the end of the first basic block it sees. -// Then emits the instructions for a _PyTier2BB. +// Then emits the instructions into the bb space. // // Instructions emitted depend on the type_context. // For example, if it sees a BINARY_ADD instruction, but it knows the two operands are already of @@ -420,9 +435,9 @@ copy_cache_entries(_Py_CODEUNIT *write_curr, _Py_CODEUNIT *cache, int n_entries) // and the basic block will end at the first of the chain. // // Note: a BB end also includes a type guard. -_PyTier2BB * +_PyTier2BBMetadata * _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _Py_CODEUNIT *start, - int n_typecontext, PyTypeObject **type_context) + int n_typecontext, PyTypeObject **type_context, _Py_CODEUNIT *t2_start) { #define END() goto end; #define JUMPBY(x) i += x + 1; continue; @@ -439,9 +454,10 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _Py_CODEUNIT *start, if (type_context_copy == NULL) { return NULL; } + memcpy(type_context_copy, type_context, n_typecontext * sizeof(PyTypeObject *)); - _Py_CODEUNIT *start_i = _PyInterpreter_GetScratchSpace(co); + _Py_CODEUNIT *start_i = t2_start; _Py_CODEUNIT *write_i = start_i; PyTypeObject **stack_pointer = co->_tier2_info->types_stack; int tos = -1; @@ -462,9 +478,9 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _Py_CODEUNIT *start, _Py_CODEUNIT action; switch (opcode) { - case COMPARE_AND_BRANCH: - opcode = COMPARE_OP; - DISPATCH(); + //case COMPARE_AND_BRANCH: + // opcode = COMPARE_OP; + // DISPATCH(); //case LOAD_FAST: // BASIC_PUSH(type_context[oparg]); // DISPATCH(); @@ -510,7 +526,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _Py_CODEUNIT *start, // These are definitely the end of a basic block. if (IS_SCOPE_EXIT_OPCODE(opcode)) { // Emit the scope exit instruction. - write_i = emit_scope_exit(write_i, opcode); + write_i = emit_scope_exit(write_i, instr); END(); } @@ -521,7 +537,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _Py_CODEUNIT *start, // JUMP offset (oparg) + current instruction + cache entries JUMPBY(oparg); } - write_i = emit_logical_branch(write_i, opcode); + write_i = emit_logical_branch(write_i, instr, i); END(); } DISPATCH(); @@ -533,32 +549,10 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _Py_CODEUNIT *start, // fprintf(stderr, "i is %Id\n", i); //#endif // Create the tier 2 BB - return _PyCode_Tier2BBNew(co, _PyCode_CODE(co) + i, start_i, write_i); + return _PyTier2_AllocateBBMetaData(co, _PyCode_CODE(co) + i); } -//// The exits of BBs need to use BB_BRANCH instruction. -//static void -//_PyTier2BB_RewriteExitBranch(_PyTier2BB *bb) -//{ -// _Py_CODEUNIT *last_instr = _PyTier2BB_UCodeEnd(bb) - BB_EPILOG; -// int op = _PyOpcode_Deopt[_Py_OPCODE(*last_instr)]; -// assert(IS_TERMINATOR_OPCODE(op)); -// if (IS_JUMP_OPCODE(op)) { -// _Py_CODEUNIT lasti = *last_instr; -// _py_set_opcode(last_instr, BB_BRANCH); -// // Write the original jump instruction after to know where -// // to start generating the next BB from. -// _Py_SET_OPCODE -// return; -// } -// assert(IS_SCOPE_EXIT_OPCODE(op)); -// assert(op == RETURN_VALUE || op == RETURN_CONST); -// // Need to FRAME_EXIT. -// -//} - - ////////// _PyTier2Info FUNCTIONS static int @@ -579,7 +573,7 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) assert(co->_tier2_info != NULL); // Remove all the RESUME instructions. // Count all the jump targets. - Py_ssize_t jump_target_count = 0; + Py_ssize_t backwards_jump_count = 0; for (Py_ssize_t i = 0; i < Py_SIZE(co); i++) { _Py_CODEUNIT *instr_ptr = _PyCode_CODE(co) + i; _Py_CODEUNIT instr = *instr_ptr; @@ -592,26 +586,26 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) default: // We want to track all guard instructions as // jumps too. - jump_target_count += IS_JUMP_OPCODE(opcode); // + INSTR_HAS_GUARD(instr); + backwards_jump_count += IS_JUMP_BACKWARDS_OPCODE(opcode); // + INSTR_HAS_GUARD(instr); } i += _PyOpcode_Caches[opcode]; } // Impossibly big. - if (jump_target_count != (int)jump_target_count) { + if (backwards_jump_count != (int)backwards_jump_count) { return 1; } // Find all the jump target instructions // Don't allocate a zero byte space as this may be undefined behavior. - if (jump_target_count == 0) { - co->_tier2_info->jump_targets = NULL; + if (backwards_jump_count == 0) { + co->_tier2_info->backward_jump_offsets = NULL; // Successful (no jump targets)! - co->_tier2_info->jump_target_count = (int)jump_target_count; + co->_tier2_info->backward_jump_count = (int)backwards_jump_count; return 0; } - int *jump_targets = PyMem_Malloc(jump_target_count * sizeof(int)); - if (jump_targets == NULL) { + int *backward_jump_offsets = PyMem_Malloc(backwards_jump_count * sizeof(int)); + if (backward_jump_offsets == NULL) { return 1; } _Py_CODEUNIT *start = _PyCode_CODE(co); @@ -621,36 +615,27 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) _Py_CODEUNIT instr = *curr; int opcode = _PyOpcode_Deopt[_Py_OPCODE(instr)]; int oparg = _Py_OPARG(instr); - //switch (opcode) { - //// KEEP IN SYNC WITH INSTR_HAS_GUARD - //case BINARY_OP: - // if (oparg == NB_ADD) { - // jump_targets[curr_i] = (int)(curr - start) + INLINE_CACHE_ENTRIES_BINARY_OP; - // curr_i++; - // } - // break; - //default: - if (IS_JUMP_OPCODE(opcode)) { + if (IS_JUMP_BACKWARDS_OPCODE(opcode)) { _Py_CODEUNIT *target = curr + _Py_OPARG(instr); // (in terms of offset from start of co_code_adaptive) - jump_targets[curr_i] = (int)(target - start); + backward_jump_offsets[curr_i] = (int)(target - start); curr_i++; } //} i += _PyOpcode_Caches[opcode]; } - assert(curr_i == jump_target_count); - qsort(jump_targets, jump_target_count, sizeof(int), compare_ints); + assert(curr_i == backwards_jump_count); + qsort(backward_jump_offsets, backwards_jump_count, sizeof(int), compare_ints); #if BB_DEBUG - fprintf(stderr, "JUMP TARGET COUNT: %lld\n", jump_target_count); - fprintf(stderr, "JUMP TARGET OFFSETS (FROM START OF CODE): "); - for (Py_ssize_t i = 0; i < jump_target_count; i++) { - fprintf(stderr, "%d ,", jump_targets[i]); + fprintf(stderr, "BACKWARD JUMP COUNNT : %Id\n", backwards_jump_count); + fprintf(stderr, "BACKWARD JUMP TARGET OFFSETS (FROM START OF CODE): "); + for (Py_ssize_t i = 0; i < backwards_jump_count; i++) { + fprintf(stderr, "%d ,", backward_jump_offsets[i]); } fprintf(stderr, "\n"); #endif - co->_tier2_info->jump_target_count = (int)jump_target_count; - co->_tier2_info->jump_targets = jump_targets; + co->_tier2_info->backward_jump_count = (int)backwards_jump_count; + co->_tier2_info->backward_jump_offsets = backward_jump_offsets; return 0; } @@ -697,21 +682,6 @@ _PyTier2Info_Initialize(PyCodeObject *co) return t2_info; } -////////// TYPE CONTEXT FUNCTIONS - -static PyTypeObject ** -initialize_type_context(PyCodeObject *co) { - int nlocals = co->co_nlocals; - PyTypeObject **type_context = PyMem_Malloc(nlocals * sizeof(PyTypeObject *)); - if (type_context == NULL) { - return NULL; - } - // Initialize to uknown type. - for (int i = 0; i < nlocals; i++) { - type_context[i] = NULL; - } - return type_context; -} ////////// OVERALL TIER2 FUNCTIONS @@ -737,10 +707,6 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) } } - if (_PyInterpreter_GetScratchSpace(co) == NULL) { - return NULL; - } - _PyTier2Info *t2_info = _PyTier2Info_Initialize(co); if (t2_info == NULL) { return NULL; @@ -750,7 +716,7 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) fprintf(stderr, "INITIALIZING\n"); #endif - Py_ssize_t space_to_alloc = (sizeof(_PyTier2BB) + _PyCode_NBYTES(co)) * 2; + Py_ssize_t space_to_alloc = (_PyCode_NBYTES(co)) * 3; _PyTier2BBSpace *bb_space = _PyTier2_CreateBBSpace(space_to_alloc); if (bb_space == NULL) { @@ -763,24 +729,27 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) t2_info->_bb_space = bb_space; - PyTypeObject **type_context = initialize_type_context(co); + int type_context_len = 0; + PyTypeObject **type_context = initialize_type_context(co, &type_context_len); if (type_context == NULL) { goto cleanup; } - _PyTier2BB *bb_ptr = _PyTier2_Code_DetectAndEmitBB(co, _PyCode_CODE(co), co->co_nlocals, type_context); - if (bb_ptr == NULL) { + _Py_CODEUNIT *t2_code = bb_space->u_code; + _PyTier2BBMetadata *meta = _PyTier2_Code_DetectAndEmitBB( + co, _PyCode_CODE(co), type_context_len, type_context, t2_code); + if (meta == NULL) { goto cleanup; } #if BB_DEBUG - fprintf(stderr, "ENTRY BB END IS: %d\n", (int)(bb_ptr->tier1_end - _PyCode_CODE(co))); + fprintf(stderr, "ENTRY BB END IS: %d\n", (int)(meta->tier1_end - _PyCode_CODE(co))); #endif - t2_info->_entry_bb = bb_ptr; + t2_info->_entry_bb = t2_code; // Set the starting instruction to the entry BB. // frame->prev_instr = bb_ptr->u_code - 1; - return bb_ptr->u_code; + return t2_code; cleanup: PyMem_Free(t2_info); @@ -810,38 +779,34 @@ _PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) return next_instr; } -// Executes successor/alternate BB, depending on direction -// Lazily generates successive BBs when required. -// direction: 1 for successor, 0 for alternative. +//// Executes successor/alternate BB +//// Lazily generates successive BBs when required. + _Py_CODEUNIT * -_PyTier2BB_ExecuteNextBB(_PyInterpreterFrame *frame, _PyTier2BB **curr_bb, int direction) +_PyTier2_GenerateNextBB(_PyInterpreterFrame *frame, _Py_CODEUNIT *curr_tier1, + _Py_CODEUNIT *curr_tier2) { - PyCodeObject *co = frame->f_code; - _PyTier2BB *curr = *curr_bb; - if (BB_SUC) { - if (curr->successor_bb == NULL) { - _PyTier2BB *succ = _PyTier2_Code_DetectAndEmitBB(co, - curr->tier1_end, curr->type_context_len, curr->type_context); - curr->successor_bb = succ; - *curr_bb = succ; - return succ->u_code; - } - else { - *curr_bb = curr->successor_bb; - return curr->successor_bb->u_code; - } + // Be a pessimist and assume we need to write the entire code into the BB. + _PyTier2BBSpace *space = _PyTier2_BBSpaceCheckAndReallocIfNeeded( + frame->f_code, _PyCode_NBYTES(frame->f_code)); + if (space == NULL) { + // DEOPTIMIZE TO TIER 1? + return NULL; } - else { - if (curr->alternate_bb == NULL) { - _PyTier2BB *alt = _PyTier2_Code_DetectAndEmitBB(co, - curr->tier1_end, curr->type_context_len, curr->type_context); - curr->alternate_bb = alt; - *curr_bb = alt; - return alt->u_code; - } - else { - *curr_bb = curr->alternate_bb; - return curr->alternate_bb->u_code; - } + // Write to the top of the space. That is automatically where the next instruction + // should execute. + // start writing at curr_tier2 + int type_context_len = 0; + PyTypeObject **type_context = initialize_type_context(frame->f_code, &type_context_len); + if (type_context == NULL) { + return NULL; + } + _PyTier2BBMetadata *metadata = _PyTier2_Code_DetectAndEmitBB( + frame->f_code, curr_tier1, type_context_len, + type_context, curr_tier2); + if (metadata == NULL) { + PyMem_Free(type_context); + return NULL; } + return curr_tier2; } From 94d89252bbe4a682de121b56dc7ea6cc6be6b52a Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 15 Feb 2023 22:49:21 +0800 Subject: [PATCH 027/280] Part 3: Add BB IDs --- Include/cpython/code.h | 23 +++- Include/internal/pycore_code.h | 4 +- Objects/codeobject.c | 5 + Python/tier2.c | 200 +++++++++++++++++++++++++-------- 4 files changed, 184 insertions(+), 48 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index ddae5db731a31a..7cbadba66b1dd1 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -59,10 +59,15 @@ typedef struct { // Tier 2 interpreter information typedef struct _PyTier2BBMetadata { + // Index into _PyTier2Info->bb_data + int id; // Array of types. This corresponds to the fast locals array. int type_context_len; PyTypeObject **type_context; + _Py_CODEUNIT *tier2_start; _Py_CODEUNIT *tier1_end; + // Type stack state + PyTypeObject **types_stack; } _PyTier2BBMetadata; // Bump allocator for basic blocks (overallocated) @@ -80,14 +85,26 @@ typedef struct _PyTier2BBSpace { // Tier 2 info stored in the code object. Lazily allocated. typedef struct _PyTier2Info { - _Py_CODEUNIT *_entry_bb; /* the tier 2 basic block to execute (if any) */ - _PyTier2BBSpace *_bb_space; /* linked list storing basic blocks */ - //_PyTier2IntermediateCode *i_code; /* intermediate bytecode to generate tier 2 basic blocks */ + /* the tier 2 basic block to execute (if any) */ + _Py_CODEUNIT *_entry_bb; + _PyTier2BBSpace *_bb_space; // Keeps track of offset of jump targets (in number of codeunits) // from co_code_adaptive. int backward_jump_count; int *backward_jump_offsets; + // Each backward jump offset will have a corresponding array of _PyTier2BBMetadata * + // This allows us to find a suitable BB on a backward jump. + // So backward jump offset [1, 2, 3 ,4] + // will have [[BB_ID1, BB_ID2], [BB_ID3,], [], []] + // etc. + int *backward_jump_target_bb_ids; PyTypeObject **types_stack; + // Max len of bb_data + int bb_data_len; + // Current index to write into in bb_data. Incremented after each write. + // This also assigns the BB ID. + int bb_data_curr; + _PyTier2BBMetadata **bb_data; } _PyTier2Info; // To avoid repeating ourselves in deepfreeze.py, all PyCodeObject members are diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 37cbdaa65bc862..87b1ae5b7ef72f 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -93,7 +93,9 @@ typedef struct { #define INLINE_CACHE_ENTRIES_FOR_ITER CACHE_ENTRIES(_PyForIterCache) typedef struct { - uint16_t offset[2]; + // Unique ID (for this code object) for this basic block. This indexes into + // the PyTier2Info bb_data field. + uint16_t bb_id; } _PyBBBranchCache; #define INLINE_CACHE_ENTRIES_BB_BRANCH CACHE_ENTRIES(_PyBBBranchCache) diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 8e2b20e2dd7da4..0a03fc44daff1a 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -418,6 +418,7 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con) _Py_OPCODE(_PyCode_CODE(co)[entry_point]) != RESUME) { entry_point++; } + co->_co_firsttraceable = entry_point; _PyCode_Quicken(co); notify_code_watchers(PY_CODE_EVENT_CREATE, co); @@ -1693,6 +1694,10 @@ code_tier2_fini(PyCodeObject *co) t2_info->types_stack = NULL; } t2_info->backward_jump_count = 0; + if (t2_info->bb_data != NULL && t2_info->bb_data_len > 0) { + PyMem_Free(t2_info->bb_data); + } + t2_info->bb_data_len = 0; PyMem_Free(t2_info); //if (t2_info->i_code != NULL) { // if (t2_info->i_code->_jump_targets != NULL) { diff --git a/Python/tier2.c b/Python/tier2.c index 406cf340f10cd5..4de86144270312 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -14,6 +14,7 @@ static inline int IS_SCOPE_EXIT_OPCODE(int opcode); + ////////// TYPE CONTEXT FUNCTIONS static PyTypeObject ** @@ -90,48 +91,90 @@ _PyTier2_BBSpaceCheckAndReallocIfNeeded(PyCodeObject *co, Py_ssize_t space_reque _PyTier2BBSpace *curr = co->_tier2_info->_bb_space; // Note: overallocate Py_ssize_t new_size = sizeof(_PyTier2BBSpace) + (curr->water_level + space_requested) * 2; - // Overflow or over max capacity - if (new_size < 0 || curr->water_level + space_requested > curr->max_capacity) { - // Try realloc first - if (PyMem_Realloc(curr, new_size) == NULL) { - // Too much trouble. just fall back to tier 1 - //// Try malloc then memcpy if realloc fails (which it might for a large reallocation) - //_PyTier2BBSpace *new_space = PyMem_Malloc(new_size); - //if (new_space == NULL) { - // return NULL; - //} - //memcpy(new_space, curr, _PyTier2BBSpace_NBYTES_USED(curr)); - //PyMem_Free(curr); - //co->_tier2_info->_bb_space = new_space; - //return new_space; + // Over max capacity + if (curr->water_level + space_requested > curr->max_capacity) { + _PyTier2BBSpace *new_space = PyMem_Realloc(curr, new_size); + if (new_space == NULL) { return NULL; } } return curr; } +// BB METADATA FUNCTIONS static _PyTier2BBMetadata * -_PyTier2_AllocateBBMetaData(PyCodeObject *co, _Py_CODEUNIT *tier1_end) +allocate_bb_metadata(PyCodeObject *co, _Py_CODEUNIT *tier2_start, + _Py_CODEUNIT *tier1_end, int type_context_len, + PyTypeObject **type_context) { - int type_context_len = 0; - PyTypeObject **type_context = initialize_type_context(co, &type_context_len); - if (type_context == NULL) { - return NULL; - } - _PyTier2BBMetadata *metadata = PyMem_Malloc(sizeof(_PyTier2BBMetadata)); if (metadata == NULL) { - PyMem_Free(type_context); return NULL; } + metadata->tier2_start = tier2_start; metadata->tier1_end = tier1_end; metadata->type_context = type_context; metadata->type_context_len = type_context_len; return metadata; } +static int +update_backward_jump_target_bb_ids(PyCodeObject *co, _PyTier2BBMetadata *metadata) +{ + assert(co->_tier2_info != NULL); + +} + +// Writes BB metadata to code object's tier2info bb_data field. +// 0 on success, 1 on error. +static int +write_bb_metadata(PyCodeObject *co, _PyTier2BBMetadata *metadata) +{ + assert(co->_tier2_info != NULL); + // Not enough space left in bb_data, allocate new one. + if (co->_tier2_info->bb_data == NULL || + co->_tier2_info->bb_data_curr >= co->_tier2_info->bb_data_len) { + int new_len = (co->_tier2_info->bb_data_len + 1) * 2; + Py_ssize_t new_space = new_len * sizeof(_PyTier2BBMetadata *); + // Overflow + if (new_len < 0) { + return 1; + } + _PyTier2BBMetadata **new_data = PyMem_Realloc(co->_tier2_info->bb_data, new_space); + if (new_data == NULL) { + return 1; + } + co->_tier2_info->bb_data = new_data; + co->_tier2_info->bb_data_len = new_len; + } + int id = co->_tier2_info->bb_data_curr; + co->_tier2_info->bb_data[id] = metadata; + metadata->id = id; + co->_tier2_info->bb_data_curr++; + return 0; +} + +static _PyTier2BBMetadata * +_PyTier2_AllocateBBMetaData(PyCodeObject *co, _Py_CODEUNIT *tier2_start, + _Py_CODEUNIT *tier1_end, int type_context_len, + PyTypeObject **type_context) +{ + _PyTier2BBMetadata *meta = allocate_bb_metadata(co, + tier2_start, tier1_end, type_context_len, type_context); + if (meta == NULL) { + return NULL; + } + if (write_bb_metadata(co, meta)) { + PyMem_Free(meta); + return NULL; + } + + return meta; + +} + /* Opcode detection functions. Keep in sync with compile.c and dis! */ // dis.hasjabs @@ -312,7 +355,7 @@ emit_type_guard(_Py_CODEUNIT *write_curr, _Py_CODEUNIT guard) } static inline _Py_CODEUNIT * -emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int code_offset) +emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) { int opcode; int oparg = _Py_OPARG(branch); @@ -368,11 +411,12 @@ emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int code_offs // offset from start of the code object (in _Py_CODEUNITs) that the current guard // can generate the basic block from. _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; - _py_set_opcode(write_curr, CACHE); - write_curr++; - _py_set_opcode(write_curr, CACHE); - write_curr++; - write_u32(cache->offset, (uint32_t)code_offset); + for (int i = 0; i < INLINE_CACHE_ENTRIES_BB_BRANCH; i++) { + _py_set_opcode(write_curr, CACHE); + write_curr++; + } + assert((uint16_t)(bb_id) == bb_id); + cache->bb_id = (uint16_t)(bb_id); return write_curr; } @@ -424,6 +468,24 @@ copy_cache_entries(_Py_CODEUNIT *write_curr, _Py_CODEUNIT *cache, int n_entries) return write_curr; } + + +static int +IS_BACKWARDS_JUMP_TARGET(PyCodeObject *co, _Py_CODEUNIT *curr) +{ + assert(co->_tier2_info != NULL); + int backward_jump_count = co->_tier2_info->backward_jump_count; + int *backward_jump_offsets = co->_tier2_info->backward_jump_offsets; + _Py_CODEUNIT *start = _PyCode_CODE(co); + // TODO: CHANGE TO BINARY SEARCH WHEN i > 40. For smaller values, linear search is quicker. + for (int i = 0; i < backward_jump_count; i++) { + if (curr == start + backward_jump_offsets[i]) { + return 1; + } + } + return 0; +} + // Detects a BB from the current instruction start to the end of the first basic block it sees. // Then emits the instructions into the bb space. // @@ -455,10 +517,12 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _Py_CODEUNIT *start, return NULL; } + _PyTier2BBMetadata *meta = NULL; + + memcpy(type_context_copy, type_context, n_typecontext * sizeof(PyTypeObject *)); - _Py_CODEUNIT *start_i = t2_start; - _Py_CODEUNIT *write_i = start_i; + _Py_CODEUNIT *write_i = t2_start; PyTypeObject **stack_pointer = co->_tier2_info->types_stack; int tos = -1; @@ -478,9 +542,10 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _Py_CODEUNIT *start, _Py_CODEUNIT action; switch (opcode) { - //case COMPARE_AND_BRANCH: - // opcode = COMPARE_OP; - // DISPATCH(); + // We need to rewrite the pseudo-branch instruction. + case COMPARE_AND_BRANCH: + opcode = COMPARE_OP; + DISPATCH(); //case LOAD_FAST: // BASIC_PUSH(type_context[oparg]); // DISPATCH(); @@ -523,6 +588,24 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _Py_CODEUNIT *start, // } //} default: + if (IS_BACKWARDS_JUMP_TARGET(co, curr)) { + // Indicates it's the start a new basic block. That's fine. Just continue. + if (write_i == t2_start) { + DISPATCH(); + } + // Not a start of a new basic block, we need to log this as a basic block + // and start a new BB for the sake of JUMP_BACKWARD. + i--; + meta = _PyTier2_AllocateBBMetaData(co, t2_start, _PyCode_CODE(co) + i, n_typecontext, type_context_copy); + if (meta == NULL) { + PyMem_Free(type_context_copy); + return NULL; + } + // Set the new start + t2_start = write_i; + // Don't increment, just fall through and let the new BB start with this + // instruction. + } // These are definitely the end of a basic block. if (IS_SCOPE_EXIT_OPCODE(opcode)) { // Emit the scope exit instruction. @@ -530,6 +613,8 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _Py_CODEUNIT *start, END(); } + + // Jumps may be the end of a basic block if they are conditional (a branch). if (IS_JUMP_OPCODE(opcode)) { // Unconditional forward jump... continue with the BB without writing the jump. @@ -537,7 +622,9 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _Py_CODEUNIT *start, // JUMP offset (oparg) + current instruction + cache entries JUMPBY(oparg); } - write_i = emit_logical_branch(write_i, instr, i); + // Get the BB ID without incrementing it. + // AllocateBBMetaData will increment. + write_i = emit_logical_branch(write_i, instr, co->_tier2_info->bb_data_curr); END(); } DISPATCH(); @@ -549,7 +636,9 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _Py_CODEUNIT *start, // fprintf(stderr, "i is %Id\n", i); //#endif // Create the tier 2 BB - return _PyTier2_AllocateBBMetaData(co, _PyCode_CODE(co) + i); + meta = _PyTier2_AllocateBBMetaData(co, t2_start, _PyCode_CODE(co) + i, n_typecontext, type_context_copy); + return meta; + } @@ -608,6 +697,14 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) if (backward_jump_offsets == NULL) { return 1; } + int *backward_jump_target_bb_ids = PyMem_Malloc(backwards_jump_count * sizeof(int)); + if (backward_jump_target_bb_ids == NULL) { + PyMem_Free(backward_jump_offsets); + return 1; + } + for (int i = 0; i < backwards_jump_count; i++) { + backward_jump_target_bb_ids[i] = -1; + } _Py_CODEUNIT *start = _PyCode_CODE(co); int curr_i = 0; for (Py_ssize_t i = 0; i < Py_SIZE(co); i++) { @@ -627,7 +724,7 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) assert(curr_i == backwards_jump_count); qsort(backward_jump_offsets, backwards_jump_count, sizeof(int), compare_ints); #if BB_DEBUG - fprintf(stderr, "BACKWARD JUMP COUNNT : %Id\n", backwards_jump_count); + fprintf(stderr, "BACKWARD JUMP COUNT : %Id\n", backwards_jump_count); fprintf(stderr, "BACKWARD JUMP TARGET OFFSETS (FROM START OF CODE): "); for (Py_ssize_t i = 0; i < backwards_jump_count; i++) { fprintf(stderr, "%d ,", backward_jump_offsets[i]); @@ -636,6 +733,7 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) #endif co->_tier2_info->backward_jump_count = (int)backwards_jump_count; co->_tier2_info->backward_jump_offsets = backward_jump_offsets; + co->_tier2_info->backward_jump_target_bb_ids = backward_jump_target_bb_ids; return 0; } @@ -667,18 +765,32 @@ _PyTier2Info_Initialize(PyCodeObject *co) if (t2_info == NULL) { return NULL; } - co->_tier2_info = t2_info; - - //if (_PyIntermediateCode_Initialize(co) == NULL) { - // PyMem_FREE(t2_info); - // return NULL; - //} // Next is to intitialize stack space for the tier 2 types meta-interpretr. - t2_info->types_stack = PyMem_Malloc(co->co_stacksize * sizeof(PyObject *)); - if (t2_info->types_stack == NULL) { + PyTypeObject **types_stack = PyMem_Malloc(co->co_stacksize * sizeof(PyObject *)); + if (types_stack == NULL) { + PyMem_Free(t2_info); + return NULL; + } + t2_info->types_stack = types_stack; + t2_info->backward_jump_count = 0; + t2_info->backward_jump_offsets = NULL; + + // Initialize BB data array + t2_info->bb_data_len = 0; + t2_info->bb_data = NULL; + t2_info->bb_data_curr = 0; + int bb_data_len = (Py_SIZE(co) / 5 + 1); + _PyTier2Info **bb_data = PyMem_Malloc(bb_data_len * sizeof(_PyTier2Info *)); + if (bb_data == NULL) { PyMem_Free(t2_info); + PyMem_Free(types_stack); + return NULL; } + t2_info->bb_data_len = bb_data_len; + t2_info->bb_data = bb_data; + co->_tier2_info = t2_info; + return t2_info; } From c7324b536984c3e688bbe5c0dd478ecad5da7d92 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu, 16 Feb 2023 01:39:39 +0800 Subject: [PATCH 028/280] Part 3.5: Cleanup and bugfixes --- Include/cpython/code.h | 1 - Include/internal/pycore_opcode.h | 3 +- Include/opcode.h | 7 ++- Lib/opcode.py | 1 - Objects/codeobject.c | 8 ---- Python/tier2.c | 82 +++++++++++++------------------- 6 files changed, 39 insertions(+), 63 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 7cbadba66b1dd1..096552524d3089 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -72,7 +72,6 @@ typedef struct _PyTier2BBMetadata { // Bump allocator for basic blocks (overallocated) typedef struct _PyTier2BBSpace { - struct _PyTier2BBSpace *next; // (in bytes) Py_ssize_t max_capacity; // How much space has been consumed in bbs. (in bytes) diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index e35db6f12e41e1..64b9c8ad6a3139 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -410,10 +410,10 @@ static const char *const _PyOpcode_OpName[263] = { [BB_TEST_POP_IF_TRUE] = "BB_TEST_POP_IF_TRUE", [BB_TEST_POP_IF_NOT_NONE] = "BB_TEST_POP_IF_NOT_NONE", [BB_TEST_POP_IF_NONE] = "BB_TEST_POP_IF_NONE", - [BB_JUMP_BACKWARD] = "BB_JUMP_BACKWARD", [BB_JUMP_BACKWARD_LAZY] = "BB_JUMP_BACKWARD_LAZY", [BINARY_CHECK_INT] = "BINARY_CHECK_INT", [BINARY_OP_ADD_INT_REST] = "BINARY_OP_ADD_INT_REST", + [183] = "<183>", [184] = "<184>", [185] = "<185>", [186] = "<186>", @@ -498,6 +498,7 @@ static const char *const _PyOpcode_OpName[263] = { #define EXTRA_CASES \ + case 183: \ case 184: \ case 185: \ case 186: \ diff --git a/Include/opcode.h b/Include/opcode.h index 45efe80f66bae6..bc02847eb1b460 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -263,10 +263,9 @@ extern "C" { #define BB_TEST_POP_IF_TRUE 177 #define BB_TEST_POP_IF_NOT_NONE 178 #define BB_TEST_POP_IF_NONE 179 -#define BB_JUMP_BACKWARD 180 -#define BB_JUMP_BACKWARD_LAZY 181 -#define BINARY_CHECK_INT 182 -#define BINARY_OP_ADD_INT_REST 183 +#define BB_JUMP_BACKWARD_LAZY 180 +#define BINARY_CHECK_INT 181 +#define BINARY_OP_ADD_INT_REST 182 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/opcode.py b/Lib/opcode.py index a04a3b0070d77a..f1b27532e3c4dc 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -468,7 +468,6 @@ def pseudo_op(name, op, real_ops): 'BB_TEST_POP_IF_NOT_NONE', 'BB_TEST_POP_IF_NONE', # JUMP_BACKWARD - 'BB_JUMP_BACKWARD', 'BB_JUMP_BACKWARD_LAZY', # Common type checks diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 0a03fc44daff1a..5e3d1cd8e1c75b 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1699,14 +1699,6 @@ code_tier2_fini(PyCodeObject *co) } t2_info->bb_data_len = 0; PyMem_Free(t2_info); - //if (t2_info->i_code != NULL) { - // if (t2_info->i_code->_jump_targets != NULL) { - // PyMem_Free(t2_info->i_code->_jump_targets); - // t2_info->i_code->_jump_targets = NULL; - // } - // PyMem_Free(t2_info->i_code); - // t2_info->i_code = NULL; - //} } static void diff --git a/Python/tier2.c b/Python/tier2.c index 4de86144270312..1674de666a0aeb 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -60,12 +60,6 @@ _PyCode_GetLogicalEnd(PyCodeObject *co) return end; } -//// Gets end of the bytecode for a tier 2 BB. -//_Py_CODEUNIT * -//_PyTier2BB_UCodeEnd(_PyTier2BB *bb) -//{ -// return (_Py_CODEUNIT *)(bb->u_code + bb->n_instrs); -//} ////////// BB SPACE FUNCTIONS @@ -77,27 +71,34 @@ _PyTier2_CreateBBSpace(Py_ssize_t space_to_alloc) if (bb_space == NULL) { return NULL; } - bb_space->next = NULL; bb_space->water_level = 0; bb_space->max_capacity = (space_to_alloc - sizeof(_PyTier2BBSpace)); return bb_space; } +// Checks if there's enough space in the BBSpace for space_requested. +// Reallocates if neccessary. +// DOES NOT ADJUST THE WATER LEVEL AS THIS IS JUST A CHECK. ONLY ADJUSTS THE MAX SPACE. static _PyTier2BBSpace * _PyTier2_BBSpaceCheckAndReallocIfNeeded(PyCodeObject *co, Py_ssize_t space_requested) { assert(co->_tier2_info != NULL); assert(co->_tier2_info->_bb_space != NULL); _PyTier2BBSpace *curr = co->_tier2_info->_bb_space; - // Note: overallocate - Py_ssize_t new_size = sizeof(_PyTier2BBSpace) + (curr->water_level + space_requested) * 2; // Over max capacity if (curr->water_level + space_requested > curr->max_capacity) { + // Note: overallocate + Py_ssize_t new_size = sizeof(_PyTier2BBSpace) + (curr->water_level + space_requested) * 2; _PyTier2BBSpace *new_space = PyMem_Realloc(curr, new_size); if (new_space == NULL) { return NULL; } + co->_tier2_info->_bb_space = new_space; + new_space->max_capacity = new_size; + PyMem_Free(curr); + return new_space; } + // We have enouogh space. Don't do anything, j return curr; } @@ -354,6 +355,7 @@ emit_type_guard(_Py_CODEUNIT *write_curr, _Py_CODEUNIT guard) return write_curr; } +// Converts the tier 1 branch bytecode to tier 2 branch bytecode. static inline _Py_CODEUNIT * emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) { @@ -364,7 +366,7 @@ emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) case JUMP_BACKWARD: // The initial backwards jump needs to find the right basic block. // Subsequent jumps don't need to check this anymore. They can just - // jump directly with BB_JUMP_BACKWARD. + // jump directly with JUMP_BACKWARD. opcode = BB_JUMP_BACKWARD_LAZY; break; case FOR_ITER: @@ -498,8 +500,9 @@ IS_BACKWARDS_JUMP_TARGET(PyCodeObject *co, _Py_CODEUNIT *curr) // // Note: a BB end also includes a type guard. _PyTier2BBMetadata * -_PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _Py_CODEUNIT *start, - int n_typecontext, PyTypeObject **type_context, _Py_CODEUNIT *t2_start) +_PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, + _Py_CODEUNIT *start, + int n_typecontext, PyTypeObject **type_context) { #define END() goto end; #define JUMPBY(x) i += x + 1; continue; @@ -522,6 +525,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _Py_CODEUNIT *start, memcpy(type_context_copy, type_context, n_typecontext * sizeof(PyTypeObject *)); + _Py_CODEUNIT *t2_start = (_Py_CODEUNIT *)(((char *)bb_space->u_code) + bb_space->water_level); _Py_CODEUNIT *write_i = t2_start; PyTypeObject **stack_pointer = co->_tier2_info->types_stack; int tos = -1; @@ -637,6 +641,8 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _Py_CODEUNIT *start, //#endif // Create the tier 2 BB meta = _PyTier2_AllocateBBMetaData(co, t2_start, _PyCode_CODE(co) + i, n_typecontext, type_context_copy); + // Tell BB space the number of bytes we wrote. + bb_space->water_level += (write_i - t2_start) * sizeof(_Py_CODEUNIT); return meta; } @@ -650,12 +656,8 @@ compare_ints(const void *a, const void *b) return *(int *)a - *(int *)b; } -// Returns 1 on error, 0 on success. Populates the jump target offset -// array for a code object. -// NOTE TO SELF: WE MIGHT NOT EVEN NEED TO FILL UP JUMP TARGETS. -// JUMP TARGETS CONTINUE BEING PART OF THE BASIC BLOCK AS LONG -// AS NO BRANCH IS DETECTED. -// REMOVE IN THE FUTURE IF UNECESSARY. +// Returns 1 on error, 0 on success. Populates the backwards jump target offset +// array for a code object.. static int _PyCode_Tier2FillJumpTargets(PyCodeObject *co) { @@ -718,11 +720,11 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) backward_jump_offsets[curr_i] = (int)(target - start); curr_i++; } - //} i += _PyOpcode_Caches[opcode]; } assert(curr_i == backwards_jump_count); - qsort(backward_jump_offsets, backwards_jump_count, sizeof(int), compare_ints); + qsort(backward_jump_offsets,backwards_jump_count, + sizeof(int), compare_ints); #if BB_DEBUG fprintf(stderr, "BACKWARD JUMP COUNT : %Id\n", backwards_jump_count); fprintf(stderr, "BACKWARD JUMP TARGET OFFSETS (FROM START OF CODE): "); @@ -737,24 +739,6 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) return 0; } -//static _PyTier2IntermediateCode * -//_PyIntermediateCode_Initialize(PyCodeObject *co) -//{ -// assert(co->_tier2_info != NULL); -// Py_ssize_t space_to_alloc = (sizeof(PyCodeObject) + _PyCode_NBYTES(co)) + BB_EPILOG; -// _PyTier2IntermediateCode *i_code = PyMem_Malloc(space_to_alloc); -// if (i_code == NULL) { -// return NULL; -// } -// -// // Copy over bytecode -// for (Py_ssize_t curr = 0; curr < Py_SIZE(co); curr++) { -// _Py_CODEUNIT *curr_instr = _PyCode_CODE(co) + curr; -// // NEED TO TRANSFORM BINARY OPS TO -// i_code->code[curr] = *curr_instr; -// } -// return i_code; -//} static _PyTier2Info * @@ -846,10 +830,11 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) if (type_context == NULL) { goto cleanup; } - _Py_CODEUNIT *t2_code = bb_space->u_code; _PyTier2BBMetadata *meta = _PyTier2_Code_DetectAndEmitBB( - co, _PyCode_CODE(co), type_context_len, type_context, t2_code); + co, bb_space, + _PyCode_CODE(co), type_context_len, type_context); if (meta == NULL) { + PyMem_Free(type_context); goto cleanup; } #if BB_DEBUG @@ -857,11 +842,11 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) #endif - t2_info->_entry_bb = t2_code; + t2_info->_entry_bb = meta->tier2_start; // Set the starting instruction to the entry BB. // frame->prev_instr = bb_ptr->u_code - 1; - return t2_code; + return meta->tier2_start; cleanup: PyMem_Free(t2_info); @@ -891,14 +876,15 @@ _PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) return next_instr; } -//// Executes successor/alternate BB -//// Lazily generates successive BBs when required. - +// Lazily generates successive BBs when required. +// The first basic block created will always be directly after the current tier 2 code. +// The second basic block created will always require a jump. _Py_CODEUNIT * _PyTier2_GenerateNextBB(_PyInterpreterFrame *frame, _Py_CODEUNIT *curr_tier1, _Py_CODEUNIT *curr_tier2) { // Be a pessimist and assume we need to write the entire code into the BB. + // The size of the BB generated will definitely be equal to or smaller than this. _PyTier2BBSpace *space = _PyTier2_BBSpaceCheckAndReallocIfNeeded( frame->f_code, _PyCode_NBYTES(frame->f_code)); if (space == NULL) { @@ -914,11 +900,11 @@ _PyTier2_GenerateNextBB(_PyInterpreterFrame *frame, _Py_CODEUNIT *curr_tier1, return NULL; } _PyTier2BBMetadata *metadata = _PyTier2_Code_DetectAndEmitBB( - frame->f_code, curr_tier1, type_context_len, - type_context, curr_tier2); + frame->f_code, space, curr_tier1, type_context_len, + type_context); if (metadata == NULL) { PyMem_Free(type_context); return NULL; } - return curr_tier2; + return metadata->tier2_start; } From 31504ad5262f24e0964dc0dfd6a1d62b4cfa03d2 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 17 Feb 2023 13:53:36 +0800 Subject: [PATCH 029/280] Fix bugs from upstream merge --- Include/internal/pycore_opcode_macro_to_micro.h | 12 ++++++++++-- Tools/cases_generator/generate_cases.py | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Include/internal/pycore_opcode_macro_to_micro.h b/Include/internal/pycore_opcode_macro_to_micro.h index ae2cc505738362..8131e548a5c578 100644 --- a/Include/internal/pycore_opcode_macro_to_micro.h +++ b/Include/internal/pycore_opcode_macro_to_micro.h @@ -51,6 +51,7 @@ extern const int _Py_MacroOpUOpCount[] = { [STORE_SUBSCR_DICT] = 1, [DELETE_SUBSCR] = 1, [CALL_INTRINSIC_1] = 1, +[CALL_INTRINSIC_2] = 1, [RAISE_VARARGS] = 1, [INTERPRETER_EXIT] = 1, [RETURN_VALUE] = 1, @@ -59,10 +60,10 @@ extern const int _Py_MacroOpUOpCount[] = { [GET_ANEXT] = 1, [GET_AWAITABLE] = 1, [SEND] = 1, +[SEND_GEN] = 1, [YIELD_VALUE] = 1, [POP_EXCEPT] = 1, [RERAISE] = 1, -[PREP_RERAISE_STAR] = 1, [END_ASYNC_FOR] = 1, [CLEANUP_THROW] = 1, [LOAD_ASSERTION_ERROR] = 1, @@ -126,11 +127,17 @@ extern const int _Py_MacroOpUOpCount[] = { [JUMP_FORWARD] = 1, [JUMP_BACKWARD] = 1, [POP_JUMP_IF_FALSE] = 1, +[BB_TEST_POP_IF_FALSE] = 1, [POP_JUMP_IF_TRUE] = 1, +[BB_TEST_POP_IF_TRUE] = 1, [POP_JUMP_IF_NOT_NONE] = 1, +[BB_TEST_POP_IF_NOT_NONE] = 1, [POP_JUMP_IF_NONE] = 1, +[BB_TEST_POP_IF_NONE] = 1, [JUMP_IF_FALSE_OR_POP] = 1, +[BB_TEST_IF_FALSE_OR_POP] = 1, [JUMP_IF_TRUE_OR_POP] = 1, +[BB_TEST_IF_TRUE_OR_POP] = 1, [JUMP_BACKWARD_NO_INTERRUPT] = 1, [GET_LEN] = 1, [MATCH_CLASS] = 1, @@ -140,6 +147,7 @@ extern const int _Py_MacroOpUOpCount[] = { [GET_ITER] = 1, [GET_YIELD_FROM_ITER] = 1, [FOR_ITER] = 1, +[BB_TEST_ITER] = 1, [FOR_ITER_LIST] = 1, [FOR_ITER_TUPLE] = 1, [FOR_ITER_RANGE] = 1, @@ -151,9 +159,9 @@ extern const int _Py_MacroOpUOpCount[] = { [LOAD_ATTR_METHOD_WITH_VALUES] = 1, [LOAD_ATTR_METHOD_NO_DICT] = 1, [LOAD_ATTR_METHOD_LAZY_DICT] = 1, -[CALL_BOUND_METHOD_EXACT_ARGS] = 1, [KW_NAMES] = 1, [CALL] = 1, +[CALL_BOUND_METHOD_EXACT_ARGS] = 1, [CALL_PY_EXACT_ARGS] = 1, [CALL_PY_WITH_DEFAULTS] = 1, [CALL_NO_KW_TYPE_1] = 1, diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 4aee9ac9580a2c..71bfa55e38aa6f 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -1338,6 +1338,7 @@ def main(): sys.exit(f"Found {a.errors} errors") a.write_instructions() # Raises OSError if output can't be written a.write_metadata() + a.output_filename = TIER2_MACRO_TO_MICRO_MAP_OUTPUT a.write_macromap_and_typedata() From 0b29290922b6346d7d446cd43770bf9a9c603cb4 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 17 Feb 2023 13:53:53 +0800 Subject: [PATCH 030/280] Handle EXTENDED_ARG --- Lib/opcode.py | 6 +++--- Python/tier2.c | 42 +++++++++++++++++++++++++++++------------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/Lib/opcode.py b/Lib/opcode.py index c3672e09a5b040..7eb00d7f9e2e04 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -453,11 +453,11 @@ def pseudo_op(name, op, real_ops): # 'BB_ENTER_FRAME', # 'BB_EXIT_FRAME', # Initial generic branching instruction. - 'BB_BRANCH', + 'BB_BRANCH', # When both exits have not been generated. # The BB_BRANCH transitions to one of these two. # This happens when the fall through is generated, but not the other branch. - 'BB_BRANCH_IF_FLAG_UNSET', - 'BB_BRANCH_IF_FLAG_SET', + 'BB_BRANCH_IF_FLAG_UNSET', # When alternate exit is not yet generated. + 'BB_BRANCH_IF_FLAG_SET', # When successor exit is not yet generated. # The final form is that once both branches are generated, we can just # override these instructions with a generic JUMP. diff --git a/Python/tier2.c b/Python/tier2.c index 1674de666a0aeb..6b0e7b7b980bdc 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -271,10 +271,11 @@ IS_FORBIDDEN_OPCODE(int opcode) // Closures case LOAD_DEREF: case MAKE_CELL: - // @TODO backward jumps should be supported! - case JUMP_BACKWARD: - case JUMP_BACKWARD_NO_INTERRUPT: + // DELETE_FAST + case DELETE_FAST: + // TODO: Pattern matching add here return 1; + default: return 0; } @@ -402,16 +403,14 @@ emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) fprintf(stderr, "emitted logical branch\n"); #endif // We prefix with an empty EXTENDED_ARG, just in case the future jumps - // are not large enough to handle the bytecode format. + // are not large enough to handle the bytecode format when jumping to + // the 2nd bb. _py_set_opcode(write_curr, EXTENDED_ARG); write_curr->oparg = 0; write_curr++; _py_set_opcode(write_curr, opcode); write_curr->oparg = oparg; write_curr++; - // Each guard also holds 2 CACHE entries. This stores an int32 of the - // offset from start of the code object (in _Py_CODEUNITs) that the current guard - // can generate the basic block from. _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; for (int i = 0; i < INLINE_CACHE_ENTRIES_BB_BRANCH; i++) { _py_set_opcode(write_curr, CACHE); @@ -508,7 +507,13 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, #define JUMPBY(x) i += x + 1; continue; #define BASIC_PUSH(v) (*stack_pointer++ = (v)) #define BASIC_POP() (*--stack_pointer) -#define DISPATCH() write_i = emit_i(write_i, opcode, oparg); write_i = copy_cache_entries(write_i, curr+1, caches); i += caches; continue; +#define DISPATCH() write_i = emit_i(write_i, opcode, oparg); \ + write_i = copy_cache_entries(write_i, curr+1, caches); \ + i += caches; \ + continue; +#define DISPATCH_GOTO() goto dispatch_opcode; + + assert(co->_tier2_info != NULL); // There are only two cases that a BB ends. // 1. If there's a branch instruction / scope exit. @@ -530,13 +535,14 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, PyTypeObject **stack_pointer = co->_tier2_info->types_stack; int tos = -1; + // A meta-interpreter for types. Py_ssize_t i = 0; for (; i < Py_SIZE(co); i++) { _Py_CODEUNIT *curr = _PyCode_CODE(co) + i; - _Py_CODEUNIT instr = *curr; - int opcode = _PyOpcode_Deopt[_Py_OPCODE(instr)]; - int oparg = _Py_OPARG(instr); + _Py_CODEUNIT *next_instr = curr + 1; + int opcode = _PyOpcode_Deopt[_Py_OPCODE(*curr)]; + int oparg = _Py_OPARG(*curr); int caches = _PyOpcode_Caches[opcode]; // Just because an instruction requires a guard doesn't mean it's the end of a BB. @@ -545,7 +551,16 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, _Py_CODEUNIT guard_instr; _Py_CODEUNIT action; + dispatch_opcode: switch (opcode) { + case EXTENDED_ARG: + write_i = emit_i(write_i, EXTENDED_ARG, _Py_OPARG(*curr)); + curr++; + next_instr++; + oparg = oparg << 8 | _Py_OPARG(*curr); + opcode = _Py_OPCODE(*curr); + caches = _PyOpcode_Caches[opcode]; + DISPATCH_GOTO(); // We need to rewrite the pseudo-branch instruction. case COMPARE_AND_BRANCH: opcode = COMPARE_OP; @@ -613,7 +628,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // These are definitely the end of a basic block. if (IS_SCOPE_EXIT_OPCODE(opcode)) { // Emit the scope exit instruction. - write_i = emit_scope_exit(write_i, instr); + write_i = emit_scope_exit(write_i, *curr); END(); } @@ -628,7 +643,8 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, } // Get the BB ID without incrementing it. // AllocateBBMetaData will increment. - write_i = emit_logical_branch(write_i, instr, co->_tier2_info->bb_data_curr); + write_i = emit_logical_branch(write_i, *curr, + co->_tier2_info->bb_data_curr); END(); } DISPATCH(); From cc8bf6b0a60929aa0517bed6bd8046da729c05ca Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 21 Feb 2023 15:31:47 +0800 Subject: [PATCH 031/280] Part 4: handle backwards jumps --- Include/cpython/code.h | 3 +- Include/internal/pycore_code.h | 10 +- Include/internal/pycore_frame.h | 7 +- .../internal/pycore_opcode_macro_to_micro.h | 4 + Objects/codeobject.c | 13 +- Python/bytecodes.c | 103 ++++++++- Python/generated_cases.c.h | 107 ++++++++- Python/opcode_metadata.h | 20 ++ Python/tier2.c | 207 ++++++++++++++---- 9 files changed, 425 insertions(+), 49 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 096552524d3089..b0683b86f8d33e 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -65,6 +65,7 @@ typedef struct _PyTier2BBMetadata { int type_context_len; PyTypeObject **type_context; _Py_CODEUNIT *tier2_start; + // Note, this is the first tier 1 instruction to execute AFTER the BB ends. _Py_CODEUNIT *tier1_end; // Type stack state PyTypeObject **types_stack; @@ -85,7 +86,7 @@ typedef struct _PyTier2BBSpace { // Tier 2 info stored in the code object. Lazily allocated. typedef struct _PyTier2Info { /* the tier 2 basic block to execute (if any) */ - _Py_CODEUNIT *_entry_bb; + _PyTier2BBMetadata *_entry_bb; _PyTier2BBSpace *_bb_space; // Keeps track of offset of jump targets (in number of codeunits) // from co_code_adaptive. diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 37f309f9b15643..d5612e5c5be40b 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -255,7 +255,15 @@ extern void _PyStaticCode_Fini(PyCodeObject *co); extern int _PyStaticCode_Init(PyCodeObject *co); /* Tier 2 interpreter */ -extern _Py_CODEUNIT *_PyCode_Tier2Warmup(struct _PyInterpreterFrame *, _Py_CODEUNIT *); +extern _Py_CODEUNIT *_PyCode_Tier2Warmup(struct _PyInterpreterFrame *, + _Py_CODEUNIT *); +extern _Py_CODEUNIT *_PyTier2_GenerateNextBB( + struct _PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, + _Py_CODEUNIT **tier1_fallback); +extern _Py_CODEUNIT *_PyTier2_LocateJumpBackwardsBB( + struct _PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, + _Py_CODEUNIT **tier1_fallback); + #ifdef Py_STATS diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 609cee8ef54fd5..d9d4f7c4e1322e 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -120,7 +120,12 @@ _PyFrame_Initialize( frame->stacktop = code->co_nlocalsplus; frame->frame_obj = NULL; // @TODO CHANGE ME - frame->prev_instr = _PyCode_CODE(code) - 1; + if (code->_tier2_info != NULL) { + frame->prev_instr = code->_tier2_info->_entry_bb->tier2_start - 1; + } + else { + frame->prev_instr = _PyCode_CODE(code) - 1; + } frame->yield_offset = 0; frame->owner = FRAME_OWNED_BY_THREAD; diff --git a/Include/internal/pycore_opcode_macro_to_micro.h b/Include/internal/pycore_opcode_macro_to_micro.h index 8131e548a5c578..9b9fe6117725b3 100644 --- a/Include/internal/pycore_opcode_macro_to_micro.h +++ b/Include/internal/pycore_opcode_macro_to_micro.h @@ -188,6 +188,10 @@ extern const int _Py_MacroOpUOpCount[] = { [SWAP] = 1, [EXTENDED_ARG] = 1, [CACHE] = 1, +[BB_BRANCH] = 1, +[BB_BRANCH_IF_FLAG_UNSET] = 1, +[BB_BRANCH_IF_FLAG_SET] = 1, +[BB_JUMP_BACKWARD_LAZY] = 1, }; extern const int _Py_MacroOpToUOp[][2] = { diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 5e3d1cd8e1c75b..d9259cff23a2d9 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -843,7 +843,7 @@ PyCode_Addr2Line(PyCodeObject *co, int addrq) if (addrq < 0) { return co->co_firstlineno; } - assert(addrq >= 0 && addrq < _PyCode_NBYTES(co)); + // assert(addrq >= 0 && addrq < _PyCode_NBYTES(co)); if (co->_co_linearray) { return _PyCode_LineNumberFromArray(co, addrq / sizeof(_Py_CODEUNIT)); } @@ -1676,11 +1676,12 @@ code_tier2_fini(PyCodeObject *co) t2_info->_entry_bb = NULL; if (t2_info->_bb_space != NULL) { // Traverse the linked list - for (_PyTier2BBSpace *curr = t2_info->_bb_space; curr != NULL;) { - _PyTier2BBSpace *prev = curr; - curr = curr->next; - PyMem_Free(prev); - } + //for (_PyTier2BBSpace *curr = t2_info->_bb_space; curr != NULL;) { + // _PyTier2BBSpace *prev = curr; + // curr = curr->next; + // PyMem_Free(prev); + //} + PyMem_Free(t2_info->_bb_space); t2_info->_bb_space = NULL; } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 1c79e5d20dbc91..44947aba44660e 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3272,7 +3272,7 @@ dummy_func( } inst(EXTENDED_ARG, (--)) { - assert(oparg); + // assert(oparg); assert(cframe.use_tracing == 0); opcode = _Py_OPCODE(*next_instr); oparg = oparg << 8 | _Py_OPARG(*next_instr); @@ -3284,6 +3284,107 @@ dummy_func( Py_UNREACHABLE(); } + // Tier 2 instructions + inst(BB_BRANCH, (--)) { + _Py_CODEUNIT *t2_nextinstr = NULL; + _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; + _Py_CODEUNIT *tier1_fallback = NULL; + if (bb_test) { + // Rewrite self + _py_set_opcode(next_instr - 1, BB_BRANCH_IF_FLAG_UNSET); + // Generate consequent. + t2_nextinstr = _PyTier2_GenerateNextBB( + frame, cache->bb_id, 0, &tier1_fallback); + if (t2_nextinstr == NULL) { + // Fall back to tier 1. + next_instr = tier1_fallback; + } + } + else { + // Rewrite self + _py_set_opcode(next_instr - 1, BB_BRANCH_IF_FLAG_SET); + // Generate predicate. + t2_nextinstr = _PyTier2_GenerateNextBB( + frame, cache->bb_id, oparg, &tier1_fallback); + if (t2_nextinstr == NULL) { + // Fall back to tier 1. + next_instr = tier1_fallback + oparg; + } + } + JUMPBY(INLINE_CACHE_ENTRIES_BB_BRANCH); + // Their addresses should be the same. Because + // The first BB should be generated right after the previous one. + if (next_instr != t2_nextinstr) { + fprintf(stderr, "next: %p, t2 next: %p\n", next_instr, t2_nextinstr); + } + assert(next_instr == t2_nextinstr); + next_instr = t2_nextinstr; + } + + inst(BB_BRANCH_IF_FLAG_UNSET, (--)) { + if (!bb_test) { + _Py_CODEUNIT *t2_nextinstr = NULL; + _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; + _Py_CODEUNIT *tier1_fallback = NULL; + + // @TODO: Rewrite TEST Instruction to a JUMP above. + + t2_nextinstr = _PyTier2_GenerateNextBB( + frame, cache->bb_id, oparg, &tier1_fallback); + if (t2_nextinstr == NULL) { + // Fall back to tier 1. + next_instr = tier1_fallback; + } + next_instr = t2_nextinstr; + } + else { + JUMPBY(INLINE_CACHE_ENTRIES_BB_BRANCH); + } + } + + inst(BB_BRANCH_IF_FLAG_SET, (--)) { + if (bb_test) { + _Py_CODEUNIT *t2_nextinstr = NULL; + _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; + _Py_CODEUNIT *tier1_fallback = NULL; + + // @TODO: Rewrite TEST Instruction to a JUMP above. + + t2_nextinstr = _PyTier2_GenerateNextBB( + frame, cache->bb_id, oparg, &tier1_fallback); + if (t2_nextinstr == NULL) { + // Fall back to tier 1. + next_instr = tier1_fallback; + } + next_instr = t2_nextinstr; + } + else { + JUMPBY(INLINE_CACHE_ENTRIES_BB_BRANCH); + } + } + + inst(BB_JUMP_BACKWARD_LAZY, (--)) { + _Py_CODEUNIT *t2_nextinstr = NULL; + _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; + _Py_CODEUNIT *tier1_fallback = NULL; + + t2_nextinstr = _PyTier2_LocateJumpBackwardsBB( + frame, cache->bb_id, oparg, &tier1_fallback); + if (t2_nextinstr == NULL) { + // Fall back to tier 1. + next_instr = tier1_fallback; + } + // Rewrite self + _Py_CODEUNIT *curr = next_instr - 1; + _Py_CODEUNIT *prev = curr - 1; + assert(_Py_OPCODE(*prev) == EXTENDED_ARG); + int op_arg = (int)(t2_nextinstr - next_instr); + assert(op_arg <= INT16_MAX); + _py_set_opcode(curr, JUMP_BACKWARD); + prev->oparg = (op_arg >> 8) & 0xFF; + curr->oparg = op_arg & 0xFF; + next_instr = t2_nextinstr; + } // END BYTECODES // diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index b4de8d1feffb65..4e12ce60e89f7e 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -4107,7 +4107,7 @@ } TARGET(EXTENDED_ARG) { - assert(oparg); + // assert(oparg); assert(cframe.use_tracing == 0); opcode = _Py_OPCODE(*next_instr); oparg = oparg << 8 | _Py_OPARG(*next_instr); @@ -4118,3 +4118,108 @@ TARGET(CACHE) { Py_UNREACHABLE(); } + + TARGET(BB_BRANCH) { + _Py_CODEUNIT *t2_nextinstr = NULL; + _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; + _Py_CODEUNIT *tier1_fallback = NULL; + if (bb_test) { + // Rewrite self + _py_set_opcode(next_instr - 1, BB_BRANCH_IF_FLAG_UNSET); + // Generate consequent. + t2_nextinstr = _PyTier2_GenerateNextBB( + frame, cache->bb_id, 0, &tier1_fallback); + if (t2_nextinstr == NULL) { + // Fall back to tier 1. + next_instr = tier1_fallback; + } + } + else { + // Rewrite self + _py_set_opcode(next_instr - 1, BB_BRANCH_IF_FLAG_SET); + // Generate predicate. + t2_nextinstr = _PyTier2_GenerateNextBB( + frame, cache->bb_id, oparg, &tier1_fallback); + if (t2_nextinstr == NULL) { + // Fall back to tier 1. + next_instr = tier1_fallback + oparg; + } + } + JUMPBY(INLINE_CACHE_ENTRIES_BB_BRANCH); + // Their addresses should be the same. Because + // The first BB should be generated right after the previous one. + if (next_instr != t2_nextinstr) { + fprintf(stderr, "next: %p, t2 next: %p\n", next_instr, t2_nextinstr); + } + assert(next_instr == t2_nextinstr); + next_instr = t2_nextinstr; + DISPATCH(); + } + + TARGET(BB_BRANCH_IF_FLAG_UNSET) { + if (!bb_test) { + _Py_CODEUNIT *t2_nextinstr = NULL; + _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; + _Py_CODEUNIT *tier1_fallback = NULL; + + // @TODO: Rewrite TEST Instruction to a JUMP above. + + t2_nextinstr = _PyTier2_GenerateNextBB( + frame, cache->bb_id, oparg, &tier1_fallback); + if (t2_nextinstr == NULL) { + // Fall back to tier 1. + next_instr = tier1_fallback; + } + next_instr = t2_nextinstr; + } + else { + JUMPBY(INLINE_CACHE_ENTRIES_BB_BRANCH); + } + DISPATCH(); + } + + TARGET(BB_BRANCH_IF_FLAG_SET) { + if (bb_test) { + _Py_CODEUNIT *t2_nextinstr = NULL; + _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; + _Py_CODEUNIT *tier1_fallback = NULL; + + // @TODO: Rewrite TEST Instruction to a JUMP above. + + t2_nextinstr = _PyTier2_GenerateNextBB( + frame, cache->bb_id, oparg, &tier1_fallback); + if (t2_nextinstr == NULL) { + // Fall back to tier 1. + next_instr = tier1_fallback; + } + next_instr = t2_nextinstr; + } + else { + JUMPBY(INLINE_CACHE_ENTRIES_BB_BRANCH); + } + DISPATCH(); + } + + TARGET(BB_JUMP_BACKWARD_LAZY) { + _Py_CODEUNIT *t2_nextinstr = NULL; + _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; + _Py_CODEUNIT *tier1_fallback = NULL; + + t2_nextinstr = _PyTier2_GenerateNextBB( + frame, cache->bb_id, oparg, &tier1_fallback); + if (t2_nextinstr == NULL) { + // Fall back to tier 1. + next_instr = tier1_fallback; + } + // Rewrite self + _Py_CODEUNIT *curr = next_instr - 1; + _Py_CODEUNIT *prev = curr - 1; + assert(_Py_OPCODE(*prev) == EXTENDED_ARG); + int op_arg = (int)(t2_nextinstr - next_instr); + assert(op_arg <= INT16_MAX); + _py_set_opcode(curr, JUMP_BACKWARD); + prev->oparg = (op_arg >> 8) & 0xFF; + curr->oparg = op_arg & 0xFF; + next_instr = t2_nextinstr; + DISPATCH(); + } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 579851dcf09ab4..45de8827a0398e 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -368,6 +368,14 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 0; case CACHE: return 0; + case BB_BRANCH: + return 0; + case BB_BRANCH_IF_FLAG_UNSET: + return 0; + case BB_BRANCH_IF_FLAG_SET: + return 0; + case BB_JUMP_BACKWARD_LAZY: + return 0; default: return -1; } @@ -740,6 +748,14 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case CACHE: return 0; + case BB_BRANCH: + return 0; + case BB_BRANCH_IF_FLAG_UNSET: + return 0; + case BB_BRANCH_IF_FLAG_SET: + return 0; + case BB_JUMP_BACKWARD_LAZY: + return 0; default: return -1; } @@ -940,5 +956,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [SWAP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [EXTENDED_ARG] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [CACHE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [BB_BRANCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [BB_BRANCH_IF_FLAG_UNSET] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [BB_BRANCH_IF_FLAG_SET] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [BB_JUMP_BACKWARD_LAZY] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, }; #endif diff --git a/Python/tier2.c b/Python/tier2.c index 6b0e7b7b980bdc..c99ef86cec6245 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -273,7 +273,13 @@ IS_FORBIDDEN_OPCODE(int opcode) case MAKE_CELL: // DELETE_FAST case DELETE_FAST: - // TODO: Pattern matching add here + // Pattern matching + case MATCH_MAPPING: + case MATCH_SEQUENCE: + case MATCH_KEYS: + // Too large arguments, we can handle this, just + // increases complexity + case EXTENDED_ARG: return 1; default: @@ -347,12 +353,30 @@ BINARY_OP_RESULT_TYPE(PyCodeObject *co, _Py_CODEUNIT *instr, int n_typecontext, } static inline _Py_CODEUNIT * -emit_type_guard(_Py_CODEUNIT *write_curr, _Py_CODEUNIT guard) +emit_cache_entries(_Py_CODEUNIT *write_curr, int cache_entries) +{ + for (int i = 0; i < cache_entries; i++) { + _py_set_opcode(write_curr, CACHE); + write_curr++; + } + return write_curr; +} + +static inline _Py_CODEUNIT * +emit_type_guard(_Py_CODEUNIT *write_curr, _Py_CODEUNIT guard, int bb_id) { *write_curr = guard; write_curr++; + _py_set_opcode(write_curr, EXTENDED_ARG); + write_curr->oparg = 0; + write_curr++; _py_set_opcode(write_curr, BB_BRANCH); + write_curr->oparg = 0; write_curr++; + _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; + write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_BB_BRANCH); + assert((uint16_t)(bb_id) == bb_id); + cache->bb_id = (uint16_t)(bb_id); return write_curr; } @@ -363,7 +387,7 @@ emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) int opcode; int oparg = _Py_OPARG(branch); // @TODO handle JUMP_BACKWARDS and JUMP_BACKWARDS_NO_INTERRUPT - switch (_Py_OPCODE(branch)) { + switch (_PyOpcode_Deopt[_Py_OPCODE(branch)]) { case JUMP_BACKWARD: // The initial backwards jump needs to find the right basic block. // Subsequent jumps don't need to check this anymore. They can just @@ -395,30 +419,51 @@ emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) // Honestly shouldn't happen because branches that // we can't handle are in IS_FORBIDDEN_OPCODE #if BB_DEBUG - fprintf(stderr, "emit_logical_branch unreachable\n"); + fprintf(stderr, + "emit_logical_branch unreachable opcode %d\n", _Py_OPCODE(branch)); #endif Py_UNREACHABLE(); } #if BB_DEBUG - fprintf(stderr, "emitted logical branch\n"); + fprintf(stderr, "emitted logical branch %p %d\n", write_curr, + _Py_OPCODE(branch)); #endif - // We prefix with an empty EXTENDED_ARG, just in case the future jumps - // are not large enough to handle the bytecode format when jumping to - // the 2nd bb. - _py_set_opcode(write_curr, EXTENDED_ARG); - write_curr->oparg = 0; - write_curr++; - _py_set_opcode(write_curr, opcode); - write_curr->oparg = oparg; - write_curr++; - _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; - for (int i = 0; i < INLINE_CACHE_ENTRIES_BB_BRANCH; i++) { - _py_set_opcode(write_curr, CACHE); + // Backwards jumps should be handled specially. + if (opcode == BB_JUMP_BACKWARD_LAZY) { + _py_set_opcode(write_curr, EXTENDED_ARG); + write_curr->oparg = (oparg >> 8) & 0xFF; write_curr++; + // We don't need to recalculate the backward jump, because that only needs to be done + // when it locates the next BB in JUMP_BACKWARD_LAZY. + _py_set_opcode(write_curr, BB_JUMP_BACKWARD_LAZY); + write_curr->oparg = oparg & 0xFF; + write_curr++; + _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; + write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_BB_BRANCH); + assert((uint16_t)(bb_id) == bb_id); + cache->bb_id = (uint16_t)(bb_id); + return write_curr; + } + else { + //_Py_CODEUNIT *start = write_curr; + _py_set_opcode(write_curr, opcode); + write_curr->oparg = oparg; + write_curr++; + // We prefix with an empty EXTENDED_ARG, just in case the future jumps + // are not large enough to handle the bytecode format when jumping to + // the 2nd bb. + _py_set_opcode(write_curr, EXTENDED_ARG); + write_curr->oparg = (oparg >> 8) & 0xFF; + write_curr++; + _py_set_opcode(write_curr, BB_BRANCH); + write_curr->oparg = oparg & 0xFF; + write_curr++; + _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; + write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_BB_BRANCH); + assert((uint16_t)(bb_id) == bb_id); + cache->bb_id = (uint16_t)(bb_id); + return write_curr; } - assert((uint16_t)(bb_id) == bb_id); - cache->bb_id = (uint16_t)(bb_id); - return write_curr; } static inline _Py_CODEUNIT * @@ -500,7 +545,7 @@ IS_BACKWARDS_JUMP_TARGET(PyCodeObject *co, _Py_CODEUNIT *curr) // Note: a BB end also includes a type guard. _PyTier2BBMetadata * _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, - _Py_CODEUNIT *start, + _Py_CODEUNIT *tier1_start, int n_typecontext, PyTypeObject **type_context) { #define END() goto end; @@ -537,7 +582,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // A meta-interpreter for types. - Py_ssize_t i = 0; + Py_ssize_t i = (tier1_start - _PyCode_CODE(co)); for (; i < Py_SIZE(co); i++) { _Py_CODEUNIT *curr = _PyCode_CODE(co) + i; _Py_CODEUNIT *next_instr = curr + 1; @@ -550,7 +595,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, int how_many_guards = 0; _Py_CODEUNIT guard_instr; _Py_CODEUNIT action; - + dispatch_opcode: switch (opcode) { case EXTENDED_ARG: @@ -565,6 +610,8 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, case COMPARE_AND_BRANCH: opcode = COMPARE_OP; DISPATCH(); + // FOR_ITER must be handled separately from other opcodes as it has + // CACHE entries following it. //case LOAD_FAST: // BASIC_PUSH(type_context[oparg]); // DISPATCH(); @@ -645,6 +692,9 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // AllocateBBMetaData will increment. write_i = emit_logical_branch(write_i, *curr, co->_tier2_info->bb_data_curr); + // Mainly for FOR_ITER + write_i = emit_cache_entries(write_i, caches); + i += caches; END(); } DISPATCH(); @@ -656,9 +706,15 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // fprintf(stderr, "i is %Id\n", i); //#endif // Create the tier 2 BB - meta = _PyTier2_AllocateBBMetaData(co, t2_start, _PyCode_CODE(co) + i, n_typecontext, type_context_copy); + meta = _PyTier2_AllocateBBMetaData(co, t2_start, + // + 1 because we want to start with the NEXT instruction for the scan + _PyCode_CODE(co) + i + 1, n_typecontext, type_context_copy); // Tell BB space the number of bytes we wrote. - bb_space->water_level += (write_i - t2_start) * sizeof(_Py_CODEUNIT); + // -1 becaues write_i points to the instruction AFTER the end + bb_space->water_level += (write_i - t2_start - 1) * sizeof(_Py_CODEUNIT); +#if BB_DEBUG + fprintf(stderr, "Generated BB T2 Start: %p\n", meta->tier2_start); +#endif return meta; } @@ -780,14 +836,15 @@ _PyTier2Info_Initialize(PyCodeObject *co) t2_info->bb_data_len = 0; t2_info->bb_data = NULL; t2_info->bb_data_curr = 0; - int bb_data_len = (Py_SIZE(co) / 5 + 1); - _PyTier2Info **bb_data = PyMem_Malloc(bb_data_len * sizeof(_PyTier2Info *)); + Py_ssize_t bb_data_len = (Py_SIZE(co) / 5 + 1); + assert((int)bb_data_len == bb_data_len); + _PyTier2BBMetadata **bb_data = PyMem_Malloc(bb_data_len * sizeof(_PyTier2Info *)); if (bb_data == NULL) { PyMem_Free(t2_info); PyMem_Free(types_stack); return NULL; } - t2_info->bb_data_len = bb_data_len; + t2_info->bb_data_len = (int)bb_data_len; t2_info->bb_data = bb_data; co->_tier2_info = t2_info; @@ -798,6 +855,29 @@ _PyTier2Info_Initialize(PyCodeObject *co) ////////// OVERALL TIER2 FUNCTIONS +// We use simple heuristics to determine if there are operations +// we can optimize in this. +// Specifically, we are looking for the presence of PEP 659 +// specialized forms of bytecode, because this indicates +// that it's a known form. +// ADD MORE HERE AS WE GO ALONG. +static inline int +IS_OPTIMIZABLE_OPCODE(int opcode, int oparg) +{ + switch (_PyOpcode_Deopt[opcode]) { + case BINARY_OP: + switch (oparg) { + case NB_ADD: + // We want a specialised form, not the generic BINARY_OP. + return opcode != _PyOpcode_Deopt[opcode]; + default: + return 0; + } + default: + return 0; + } +} + // 1. Initialize whatever we need. // 2. Create the entry BB. // 3. Jump into that BB. @@ -812,11 +892,17 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) if ((int)Py_SIZE(co) != Py_SIZE(co)) { return NULL; } + int optimizable = 0; for (Py_ssize_t curr = 0; curr < Py_SIZE(co); curr++) { _Py_CODEUNIT *curr_instr = _PyCode_CODE(co) + curr; if (IS_FORBIDDEN_OPCODE(_PyOpcode_Deopt[_Py_OPCODE(*curr_instr)])) { return NULL; } + optimizable |= IS_OPTIMIZABLE_OPCODE(_Py_OPCODE(*curr_instr), _Py_OPARG(*curr_instr)); + } + + if (!optimizable) { + return NULL; } _PyTier2Info *t2_info = _PyTier2Info_Initialize(co); @@ -858,8 +944,10 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) #endif - t2_info->_entry_bb = meta->tier2_start; + t2_info->_entry_bb = meta; + // SET THE FRAME INFO + frame->prev_instr = meta->tier2_start - 1; // Set the starting instruction to the entry BB. // frame->prev_instr = bb_ptr->u_code - 1; return meta->tier2_start; @@ -883,7 +971,6 @@ _PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) // If it fails, due to lack of memory or whatever, // just fall back to the tier 1 interpreter. _Py_CODEUNIT *next = _PyCode_Tier2Initialize(frame, next_instr); - return next_instr; if (next != NULL) { return next; } @@ -896,27 +983,31 @@ _PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) // The first basic block created will always be directly after the current tier 2 code. // The second basic block created will always require a jump. _Py_CODEUNIT * -_PyTier2_GenerateNextBB(_PyInterpreterFrame *frame, _Py_CODEUNIT *curr_tier1, - _Py_CODEUNIT *curr_tier2) +_PyTier2_GenerateNextBB(_PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, + _Py_CODEUNIT **tier1_fallback) { - // Be a pessimist and assume we need to write the entire code into the BB. + PyCodeObject *co = frame->f_code; + assert(co->_tier2_info != NULL); + assert(bb_id <= co->_tier2_info->bb_data_curr); + _PyTier2BBMetadata *meta = co->_tier2_info->bb_data[bb_id]; + _Py_CODEUNIT *tier1_end = meta->tier1_end + jumpby; + *tier1_fallback = tier1_end; + // Be a pessimist and assume we need to write the entire rest of code into the BB. // The size of the BB generated will definitely be equal to or smaller than this. _PyTier2BBSpace *space = _PyTier2_BBSpaceCheckAndReallocIfNeeded( - frame->f_code, _PyCode_NBYTES(frame->f_code)); + frame->f_code, + _PyCode_NBYTES(co) - (tier1_end - _PyCode_CODE(co)) * sizeof(_Py_CODEUNIT)); if (space == NULL) { // DEOPTIMIZE TO TIER 1? return NULL; } - // Write to the top of the space. That is automatically where the next instruction - // should execute. - // start writing at curr_tier2 int type_context_len = 0; PyTypeObject **type_context = initialize_type_context(frame->f_code, &type_context_len); if (type_context == NULL) { return NULL; } _PyTier2BBMetadata *metadata = _PyTier2_Code_DetectAndEmitBB( - frame->f_code, space, curr_tier1, type_context_len, + frame->f_code, space, tier1_end, type_context_len, type_context); if (metadata == NULL) { PyMem_Free(type_context); @@ -924,3 +1015,43 @@ _PyTier2_GenerateNextBB(_PyInterpreterFrame *frame, _Py_CODEUNIT *curr_tier1, } return metadata->tier2_start; } + +_Py_CODEUNIT * +_PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, + _Py_CODEUNIT **tier1_fallback) +{ + PyCodeObject *co = frame->f_code; + assert(co->_tier2_info != NULL); + assert(bb_id <= co->_tier2_info->bb_data_curr); + _PyTier2BBMetadata *meta = co->_tier2_info->bb_data[bb_id]; + // The jump target + _Py_CODEUNIT *tier1_jump_target = meta->tier1_end + jumpby; + *tier1_fallback = tier1_jump_target; + // Be a pessimist and assume we need to write the entire rest of code into the BB. + // The size of the BB generated will definitely be equal to or smaller than this. + _PyTier2BBSpace *space = _PyTier2_BBSpaceCheckAndReallocIfNeeded( + frame->f_code, + _PyCode_NBYTES(co) - (tier1_jump_target - _PyCode_CODE(co)) * sizeof(_Py_CODEUNIT)); + if (space == NULL) { + // DEOPTIMIZE TO TIER 1? + return NULL; + } + int type_context_len = 0; + PyTypeObject **type_context = initialize_type_context(frame->f_code, &type_context_len); + if (type_context == NULL) { + return NULL; + } + // Now, find the matching BB + _PyTier2Info *t2_info = co->_tier2_info; + int jump_offset = (int)(tier1_jump_target - _PyCode_CODE(co)); + int matching_bb_id = -1; + for (int i = 0; i < t2_info->backward_jump_count; i++) { + if (t2_info->backward_jump_offsets[i] == jump_offset) { + matching_bb_id = t2_info->backward_jump_target_bb_ids[i]; + } + } + assert(matching_bb_id >= 0); + assert(matching_bb_id <= t2_info->bb_data_curr); + _PyTier2BBMetadata *target_metadata = t2_info->bb_data[matching_bb_id]; + return target_metadata->tier2_start; +} From e26f746f3f552ebed5005f77f5e27de8aba8e929 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 21 Feb 2023 21:15:45 +0800 Subject: [PATCH 032/280] Part 4.1: Find backward jump targets TODO: Handle transformations to original jumps --- Include/cpython/code.h | 2 +- Include/internal/pycore_frame.h | 11 +- Python/bytecodes.c | 15 ++- Python/ceval_macros.h | 3 +- Python/generated_cases.c.h | 13 +- Python/opcode_metadata.h | 2 +- Python/tier2.c | 216 ++++++++++++++++++++++++++------ 7 files changed, 211 insertions(+), 51 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index b0683b86f8d33e..9675a6017e555a 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -97,7 +97,7 @@ typedef struct _PyTier2Info { // So backward jump offset [1, 2, 3 ,4] // will have [[BB_ID1, BB_ID2], [BB_ID3,], [], []] // etc. - int *backward_jump_target_bb_ids; + int **backward_jump_target_bb_ids; PyTypeObject **types_stack; // Max len of bb_data int bb_data_len; diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index d9d4f7c4e1322e..d9f60179a02a0d 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -66,8 +66,15 @@ typedef struct _PyInterpreterFrame { PyObject *localsplus[1]; } _PyInterpreterFrame; -#define _PyInterpreterFrame_LASTI(IF) \ - ((int)((IF)->prev_instr - _PyCode_CODE((IF)->f_code))) +static inline int +_PyInterpreterFrame_LASTI(_PyInterpreterFrame *f) { + if (f->f_code->_tier2_info != NULL) { + return ((int)((f)->prev_instr - f->f_code->_tier2_info->_bb_space->u_code)); + } + return ((int)((f)->prev_instr - _PyCode_CODE((f)->f_code))); +} +//#define _PyInterpreterFrame_LASTI(IF) \ +// ((int)((IF)->prev_instr - _PyCode_CODE((IF)->f_code))) static inline PyObject **_PyFrame_Stackbase(_PyInterpreterFrame *f) { return f->localsplus + f->f_code->co_nlocalsplus; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 44947aba44660e..974ba65866b26e 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2280,10 +2280,11 @@ dummy_func( _PyErr_Clear(tstate); } /* iterator ended normally */ - assert(_Py_OPCODE(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg]) == END_FOR); Py_DECREF(iter); STACK_SHRINK(1); bb_test = false; + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + DISPATCH(); } bb_test = true; } @@ -3298,6 +3299,7 @@ dummy_func( if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; + DISPATCH(); } } else { @@ -3309,6 +3311,7 @@ dummy_func( if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback + oparg; + DISPATCH(); } } JUMPBY(INLINE_CACHE_ENTRIES_BB_BRANCH); @@ -3327,7 +3330,7 @@ dummy_func( _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; _Py_CODEUNIT *tier1_fallback = NULL; - // @TODO: Rewrite TEST Instruction to a JUMP above. + // @TODO: Rewrite TEST intruction above to a JUMP above. t2_nextinstr = _PyTier2_GenerateNextBB( frame, cache->bb_id, oparg, &tier1_fallback); @@ -3348,7 +3351,7 @@ dummy_func( _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; _Py_CODEUNIT *tier1_fallback = NULL; - // @TODO: Rewrite TEST Instruction to a JUMP above. + // @TODO: Rewrite TEST intruction above to a JUMP above.. t2_nextinstr = _PyTier2_GenerateNextBB( frame, cache->bb_id, oparg, &tier1_fallback); @@ -3369,7 +3372,7 @@ dummy_func( _Py_CODEUNIT *tier1_fallback = NULL; t2_nextinstr = _PyTier2_LocateJumpBackwardsBB( - frame, cache->bb_id, oparg, &tier1_fallback); + frame, cache->bb_id, -oparg, &tier1_fallback); if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; @@ -3378,11 +3381,13 @@ dummy_func( _Py_CODEUNIT *curr = next_instr - 1; _Py_CODEUNIT *prev = curr - 1; assert(_Py_OPCODE(*prev) == EXTENDED_ARG); - int op_arg = (int)(t2_nextinstr - next_instr); + int op_arg = -(int)(t2_nextinstr - next_instr); + // fprintf(stderr, "JUMP_BACKWARD oparg is %d\n", op_arg); assert(op_arg <= INT16_MAX); _py_set_opcode(curr, JUMP_BACKWARD); prev->oparg = (op_arg >> 8) & 0xFF; curr->oparg = op_arg & 0xFF; + _py_set_opcode(next_instr, END_FOR); next_instr = t2_nextinstr; } diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 68069b8803332e..afbb56aa429cc8 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -141,7 +141,8 @@ GETITEM(PyObject *v, Py_ssize_t i) { /* The integer overflow is checked by an assertion below. */ // TODO change this calculation when interpreter is bb aware. -#define INSTR_OFFSET() ((int)(next_instr - _PyCode_CODE(frame->f_code))) +#define INSTR_OFFSET() ((int)(next_instr - \ + (frame->f_code->_tier2_info == NULL ? _PyCode_CODE(frame->f_code) : frame->f_code->_tier2_info->_bb_space->u_code))) #define NEXTOPARG() do { \ _Py_CODEUNIT word = *next_instr; \ opcode = _Py_OPCODE(word); \ diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 4e12ce60e89f7e..aee1db10f3ca5d 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2890,10 +2890,11 @@ _PyErr_Clear(tstate); } /* iterator ended normally */ - assert(_Py_OPCODE(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg]) == END_FOR); Py_DECREF(iter); STACK_SHRINK(1); bb_test = false; + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + DISPATCH(); } bb_test = true; STACK_GROW(1); @@ -4132,6 +4133,7 @@ if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; + DISPATCH(); } } else { @@ -4143,6 +4145,7 @@ if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback + oparg; + DISPATCH(); } } JUMPBY(INLINE_CACHE_ENTRIES_BB_BRANCH); @@ -4205,8 +4208,8 @@ _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; _Py_CODEUNIT *tier1_fallback = NULL; - t2_nextinstr = _PyTier2_GenerateNextBB( - frame, cache->bb_id, oparg, &tier1_fallback); + t2_nextinstr = _PyTier2_LocateJumpBackwardsBB( + frame, cache->bb_id, -oparg, &tier1_fallback); if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; @@ -4215,11 +4218,13 @@ _Py_CODEUNIT *curr = next_instr - 1; _Py_CODEUNIT *prev = curr - 1; assert(_Py_OPCODE(*prev) == EXTENDED_ARG); - int op_arg = (int)(t2_nextinstr - next_instr); + int op_arg = -(int)(t2_nextinstr - next_instr); + // fprintf(stderr, "JUMP_BACKWARD oparg is %d\n", op_arg); assert(op_arg <= INT16_MAX); _py_set_opcode(curr, JUMP_BACKWARD); prev->oparg = (op_arg >> 8) & 0xFF; curr->oparg = op_arg & 0xFF; + _py_set_opcode(next_instr, END_FOR); next_instr = t2_nextinstr; DISPATCH(); } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 45de8827a0398e..296d36d66163c9 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -915,7 +915,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [GET_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [GET_YIELD_FROM_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [FOR_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [BB_TEST_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, + [BB_TEST_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, [FOR_ITER_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, [FOR_ITER_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, [FOR_ITER_RANGE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, diff --git a/Python/tier2.c b/Python/tier2.c index c99ef86cec6245..e81987598455de 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -4,11 +4,13 @@ #include "pycore_frame.h" #include "pycore_opcode.h" #include "pycore_pystate.h" +#include "stdbool.h" #include "opcode.h" #define BB_DEBUG 1 - +// Max typed version basic blocks per basic block +#define MAX_BB_VERSIONS 5 // Number of potential extra instructions at end of a BB, for branch or cleanup purposes. #define BB_EPILOG 0 @@ -424,12 +426,12 @@ emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) #endif Py_UNREACHABLE(); } -#if BB_DEBUG - fprintf(stderr, "emitted logical branch %p %d\n", write_curr, - _Py_OPCODE(branch)); -#endif // Backwards jumps should be handled specially. if (opcode == BB_JUMP_BACKWARD_LAZY) { +#if BB_DEBUG + fprintf(stderr, "emitted backwards jump %p %d\n", write_curr, + _Py_OPCODE(branch)); +#endif _py_set_opcode(write_curr, EXTENDED_ARG); write_curr->oparg = (oparg >> 8) & 0xFF; write_curr++; @@ -444,7 +446,37 @@ emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) cache->bb_id = (uint16_t)(bb_id); return write_curr; } + // FOR_ITER is also a special jump + else if (opcode == BB_TEST_ITER) { +#if BB_DEBUG + fprintf(stderr, "emitted logical branch %p %d\n", write_curr, + _Py_OPCODE(branch)); +#endif + // The oparg of FOR_ITER is a little special, the actual jump has to jump over + // its own cache entries, the oparg, AND the END_FOR (+1). + oparg = INLINE_CACHE_ENTRIES_FOR_ITER + oparg; + //_Py_CODEUNIT *start = write_curr; + _py_set_opcode(write_curr, BB_TEST_ITER); + write_curr->oparg = oparg; + write_curr++; + write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_FOR_ITER); + _py_set_opcode(write_curr, EXTENDED_ARG); + write_curr->oparg = (oparg >> 8) & 0xFF; + write_curr++; + _py_set_opcode(write_curr, BB_BRANCH); + write_curr->oparg = oparg & 0xFF; + write_curr++; + _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; + write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_BB_BRANCH); + assert((uint16_t)(bb_id) == bb_id); + cache->bb_id = (uint16_t)(bb_id); + return write_curr; + } else { +#if BB_DEBUG + fprintf(stderr, "emitted logical branch %p %d\n", write_curr, + _Py_OPCODE(branch)); +#endif //_Py_CODEUNIT *start = write_curr; _py_set_opcode(write_curr, opcode); write_curr->oparg = oparg; @@ -476,7 +508,7 @@ emit_scope_exit(_Py_CODEUNIT *write_curr, _Py_CODEUNIT exit) #if BB_DEBUG fprintf(stderr, "emitted scope exit\n"); #endif - //// @TODO we can propogate and chain BBs across call boundaries + //// @TODO we can propagate and chain BBs across call boundaries //// Thanks to CPython's inlined call frames. //_py_set_opcode(write_curr, BB_EXIT_FRAME); *write_curr = exit; @@ -532,6 +564,40 @@ IS_BACKWARDS_JUMP_TARGET(PyCodeObject *co, _Py_CODEUNIT *curr) return 0; } +// 1 for error, 0 for success. +static inline int +add_metadata_to_jump_2d_array(_PyTier2Info *t2_info, _PyTier2BBMetadata *meta, + int backwards_jump_target) +{ + // Locate where to insert the BB ID + int backward_jump_offset_index = 0; + bool found = false; + for (; backward_jump_offset_index < t2_info->backward_jump_count; + backward_jump_offset_index++) { + if (t2_info->backward_jump_offsets[backward_jump_offset_index] == + backwards_jump_target) { + found = true; + break; + } + } + assert(found); + int jump_i = 0; + found = false; + for (; jump_i < MAX_BB_VERSIONS; jump_i++) { + if (t2_info->backward_jump_target_bb_ids[backward_jump_offset_index][jump_i] == -1) { + t2_info->backward_jump_target_bb_ids[backward_jump_offset_index][jump_i] = meta->id; + found = true; + break; + } + } + // Out of basic blocks versions. + if (!found) { + return 1; + } + assert(found); + return 0; +} + // Detects a BB from the current instruction start to the end of the first basic block it sees. // Then emits the instructions into the bb space. // @@ -562,24 +628,28 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, assert(co->_tier2_info != NULL); // There are only two cases that a BB ends. // 1. If there's a branch instruction / scope exit. - // 2. If the instruction is a jump target. + // 2. If there's a type guard. // Make a copy of the type context PyTypeObject **type_context_copy = PyMem_Malloc(n_typecontext * sizeof(PyTypeObject *)); if (type_context_copy == NULL) { return NULL; } + memcpy(type_context_copy, type_context, n_typecontext * sizeof(PyTypeObject *)); _PyTier2BBMetadata *meta = NULL; + _PyTier2BBMetadata *temp_meta = NULL; - - memcpy(type_context_copy, type_context, n_typecontext * sizeof(PyTypeObject *)); - + _PyTier2Info *t2_info = co->_tier2_info; _Py_CODEUNIT *t2_start = (_Py_CODEUNIT *)(((char *)bb_space->u_code) + bb_space->water_level); _Py_CODEUNIT *write_i = t2_start; PyTypeObject **stack_pointer = co->_tier2_info->types_stack; int tos = -1; + // For handling of backwards jumps + bool starts_with_backwards_jump_target = false; + int backwards_jump_target_offset = -1; + bool virtual_start = false; // A meta-interpreter for types. Py_ssize_t i = (tier1_start - _PyCode_CODE(co)); @@ -598,10 +668,14 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, dispatch_opcode: switch (opcode) { + case RESUME: + opcode = RESUME_QUICK; + DISPATCH(); case EXTENDED_ARG: write_i = emit_i(write_i, EXTENDED_ARG, _Py_OPARG(*curr)); curr++; next_instr++; + i++; oparg = oparg << 8 | _Py_OPARG(*curr); opcode = _Py_OPCODE(*curr); caches = _PyOpcode_Caches[opcode]; @@ -654,24 +728,36 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // } //} default: + fprintf(stderr, "offset: %Id\n", curr - _PyCode_CODE(co)); if (IS_BACKWARDS_JUMP_TARGET(co, curr)) { - // Indicates it's the start a new basic block. That's fine. Just continue. - if (write_i == t2_start) { - DISPATCH(); + fprintf(stderr, "Encountered a backward jump target\n"); + // This should be the end of another basic block, or the start of a new. + // Start of a new basic block, just ignore and continue. + if (virtual_start) { + fprintf(stderr, "Emitted virtual start of basic block\n"); + starts_with_backwards_jump_target = true; + backwards_jump_target_offset = curr - _PyCode_CODE(co); + virtual_start = false; + goto fall_through; } - // Not a start of a new basic block, we need to log this as a basic block - // and start a new BB for the sake of JUMP_BACKWARD. + // Else, create a virtual end to the basic block. + // But generate the block after that so it can fall through. i--; - meta = _PyTier2_AllocateBBMetaData(co, t2_start, _PyCode_CODE(co) + i, n_typecontext, type_context_copy); + meta = _PyTier2_AllocateBBMetaData(co, + t2_start, _PyCode_CODE(co) + i, n_typecontext, type_context_copy); if (meta == NULL) { PyMem_Free(type_context_copy); return NULL; } - // Set the new start + bb_space->water_level += (write_i - t2_start) * sizeof(_Py_CODEUNIT); + // Reset the start t2_start = write_i; - // Don't increment, just fall through and let the new BB start with this - // instruction. + i++; + virtual_start = true; + // Don't change opcode or oparg, let us handle it again. + DISPATCH_GOTO(); } + fall_through: // These are definitely the end of a basic block. if (IS_SCOPE_EXIT_OPCODE(opcode)) { // Emit the scope exit instruction. @@ -679,8 +765,6 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, END(); } - - // Jumps may be the end of a basic block if they are conditional (a branch). if (IS_JUMP_OPCODE(opcode)) { // Unconditional forward jump... continue with the BB without writing the jump. @@ -692,8 +776,6 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // AllocateBBMetaData will increment. write_i = emit_logical_branch(write_i, *curr, co->_tier2_info->bb_data_curr); - // Mainly for FOR_ITER - write_i = emit_cache_entries(write_i, caches); i += caches; END(); } @@ -702,20 +784,32 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, } end: -//#if BB_DEBUG -// fprintf(stderr, "i is %Id\n", i); -//#endif // Create the tier 2 BB - meta = _PyTier2_AllocateBBMetaData(co, t2_start, + temp_meta = _PyTier2_AllocateBBMetaData(co, t2_start, // + 1 because we want to start with the NEXT instruction for the scan _PyCode_CODE(co) + i + 1, n_typecontext, type_context_copy); - // Tell BB space the number of bytes we wrote. - // -1 becaues write_i points to the instruction AFTER the end - bb_space->water_level += (write_i - t2_start - 1) * sizeof(_Py_CODEUNIT); + // We need to return the first block to enter into. If there is already a block generated + // before us, then we use that instead of the most recent block. + if (meta == NULL) { + meta = temp_meta; + } + if (starts_with_backwards_jump_target) { + // Add the basic block to the jump ids + if (add_metadata_to_jump_2d_array(t2_info, temp_meta, backwards_jump_target_offset) < 0) { + PyMem_Free(meta); + PyMem_Free(temp_meta); + PyMem_Free(type_context_copy); + return NULL; + } + } + // Tell BB space the number of bytes we wrote. + // -1 becaues write_i points to the instruction AFTER the end + bb_space->water_level += (write_i - t2_start) * sizeof(_Py_CODEUNIT); #if BB_DEBUG - fprintf(stderr, "Generated BB T2 Start: %p\n", meta->tier2_start); + fprintf(stderr, "Generated BB T2 Start: %p, T1 offset: %d\n", meta->tier2_start, + meta->tier1_end - _PyCode_CODE(co)); #endif - return meta; + return meta; } @@ -728,6 +822,29 @@ compare_ints(const void *a, const void *b) return *(int *)a - *(int *)b; } +static int +allocate_jump_offset_2d_array(int backwards_jump_count, int **backward_jump_target_bb_ids) +{ + int done = 0; + for (int i = 0; i < backwards_jump_count; i++) { + int *jump_offsets = PyMem_Malloc(sizeof(int) * MAX_BB_VERSIONS); + if (jump_offsets == NULL) { + goto error; + } + for (int i = 0; i < MAX_BB_VERSIONS; i++) { + jump_offsets[i] = -1; + } + done++; + backward_jump_target_bb_ids[i] = jump_offsets; + } + return 0; +error: + for (int i = 0; i < done; i++) { + PyMem_Free(backward_jump_target_bb_ids[i]); + } + return 1; +} + // Returns 1 on error, 0 on success. Populates the backwards jump target offset // array for a code object.. static int @@ -771,14 +888,16 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) if (backward_jump_offsets == NULL) { return 1; } - int *backward_jump_target_bb_ids = PyMem_Malloc(backwards_jump_count * sizeof(int)); + int **backward_jump_target_bb_ids = PyMem_Malloc(backwards_jump_count * sizeof(int *)); if (backward_jump_target_bb_ids == NULL) { PyMem_Free(backward_jump_offsets); return 1; } - for (int i = 0; i < backwards_jump_count; i++) { - backward_jump_target_bb_ids[i] = -1; + if (allocate_jump_offset_2d_array(backwards_jump_count, backward_jump_target_bb_ids)) { + PyMem_Free(backward_jump_offsets); + return 1; } + _Py_CODEUNIT *start = _PyCode_CODE(co); int curr_i = 0; for (Py_ssize_t i = 0; i < Py_SIZE(co); i++) { @@ -787,7 +906,9 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) int opcode = _PyOpcode_Deopt[_Py_OPCODE(instr)]; int oparg = _Py_OPARG(instr); if (IS_JUMP_BACKWARDS_OPCODE(opcode)) { - _Py_CODEUNIT *target = curr + _Py_OPARG(instr); + // + 1 because it's calculated from nextinstr (see JUMPBY in ceval.c) + _Py_CODEUNIT *target = curr + 1 - oparg; + fprintf(stderr, "jump target opcode is %d\n", _Py_OPCODE(*target)); // (in terms of offset from start of co_code_adaptive) backward_jump_offsets[curr_i] = (int)(target - start); curr_i++; @@ -896,12 +1017,18 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) for (Py_ssize_t curr = 0; curr < Py_SIZE(co); curr++) { _Py_CODEUNIT *curr_instr = _PyCode_CODE(co) + curr; if (IS_FORBIDDEN_OPCODE(_PyOpcode_Deopt[_Py_OPCODE(*curr_instr)])) { +#if BB_DEBUG + fprintf(stderr, "FORBIDDEN OPCODE %d\n", _Py_OPCODE(*curr_instr)); +#endif return NULL; } optimizable |= IS_OPTIMIZABLE_OPCODE(_Py_OPCODE(*curr_instr), _Py_OPARG(*curr_instr)); } if (!optimizable) { +#if BB_DEBUG + fprintf(stderr, "NOT OPTIMIZABLE\n"); +#endif return NULL; } @@ -1045,13 +1172,28 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id, int j _PyTier2Info *t2_info = co->_tier2_info; int jump_offset = (int)(tier1_jump_target - _PyCode_CODE(co)); int matching_bb_id = -1; + + fprintf(stderr, "finding jump target: %d\n", jump_offset); for (int i = 0; i < t2_info->backward_jump_count; i++) { + fprintf(stderr, "jump offset checked: %d\n", t2_info->backward_jump_offsets[i]); if (t2_info->backward_jump_offsets[i] == jump_offset) { - matching_bb_id = t2_info->backward_jump_target_bb_ids[i]; + for (int x = 0; x < MAX_BB_VERSIONS; x++) { + fprintf(stderr, "jump target BB ID: %d\n", + t2_info->backward_jump_target_bb_ids[i][x]); + // @TODO, this is where the diff function is supposed to be + // it will calculate the closest type context BB + // For now just any valid BB (>= 0) is used. + if (t2_info->backward_jump_target_bb_ids[i][x] >= 0) { + matching_bb_id = t2_info->backward_jump_target_bb_ids[i][x]; + break; + } + } + break; } } assert(matching_bb_id >= 0); assert(matching_bb_id <= t2_info->bb_data_curr); + fprintf(stderr, "Found jump target BB ID: %d\n", matching_bb_id); _PyTier2BBMetadata *target_metadata = t2_info->bb_data[matching_bb_id]; return target_metadata->tier2_start; } From c5818876016d7e8b392d42438e06930c41f8fcc1 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 21 Feb 2023 22:19:17 +0800 Subject: [PATCH 033/280] Part 4.2: Properly handle END_FOR --- Python/bytecodes.c | 3 +-- Python/generated_cases.c.h | 6 ++---- Python/opcode_metadata.h | 2 +- Python/tier2.c | 15 ++++++++++++--- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 974ba65866b26e..9602fea53d28b4 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2267,7 +2267,7 @@ dummy_func( } // FOR_ITER - inst(BB_TEST_ITER, (unused / 1, iter -- iter, next)) { + inst(BB_TEST_ITER, (iter -- iter, next)) { next = (*Py_TYPE(iter)->tp_iternext)(iter); if (next == NULL) { if (_PyErr_Occurred(tstate)) { @@ -2283,7 +2283,6 @@ dummy_func( Py_DECREF(iter); STACK_SHRINK(1); bb_test = false; - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); DISPATCH(); } bb_test = true; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index aee1db10f3ca5d..42bfd68f9650f8 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2893,13 +2893,11 @@ Py_DECREF(iter); STACK_SHRINK(1); bb_test = false; - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); DISPATCH(); } bb_test = true; STACK_GROW(1); POKE(1, next); - JUMPBY(1); DISPATCH(); } @@ -4165,7 +4163,7 @@ _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; _Py_CODEUNIT *tier1_fallback = NULL; - // @TODO: Rewrite TEST Instruction to a JUMP above. + // @TODO: Rewrite TEST intruction above to a JUMP above. t2_nextinstr = _PyTier2_GenerateNextBB( frame, cache->bb_id, oparg, &tier1_fallback); @@ -4187,7 +4185,7 @@ _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; _Py_CODEUNIT *tier1_fallback = NULL; - // @TODO: Rewrite TEST Instruction to a JUMP above. + // @TODO: Rewrite TEST intruction above to a JUMP above.. t2_nextinstr = _PyTier2_GenerateNextBB( frame, cache->bb_id, oparg, &tier1_fallback); diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 296d36d66163c9..aacdfe3ced34d3 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -915,7 +915,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [GET_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [GET_YIELD_FROM_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [FOR_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [BB_TEST_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, + [BB_TEST_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [FOR_ITER_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, [FOR_ITER_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, [FOR_ITER_RANGE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, diff --git a/Python/tier2.c b/Python/tier2.c index e81987598455de..c8022ac6048107 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -453,13 +453,15 @@ emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) _Py_OPCODE(branch)); #endif // The oparg of FOR_ITER is a little special, the actual jump has to jump over - // its own cache entries, the oparg, AND the END_FOR (+1). - oparg = INLINE_CACHE_ENTRIES_FOR_ITER + oparg; + // its own cache entries, the oparg, -1 to tell it to start generating from the + // END_FOR. However, at runtime, we will skip this END_FOR. + oparg = INLINE_CACHE_ENTRIES_FOR_ITER + oparg - 1; //_Py_CODEUNIT *start = write_curr; _py_set_opcode(write_curr, BB_TEST_ITER); write_curr->oparg = oparg; write_curr++; - write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_FOR_ITER); + // We don't need to emit inline cache entries, because when this converts, + // we can just make use of the EXTENDED_ARG and BB_BRANCH below. _py_set_opcode(write_curr, EXTENDED_ARG); write_curr->oparg = (oparg >> 8) & 0xFF; write_curr++; @@ -684,6 +686,13 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, case COMPARE_AND_BRANCH: opcode = COMPARE_OP; DISPATCH(); + case END_FOR: + // Assert that we are the start of a BB + assert(t2_start == write_i); + // Though we want to emit this, we don't want to start execution from END_FOR. + // So we tell the BB to skip over it. + t2_start++; + DISPATCH(); // FOR_ITER must be handled separately from other opcodes as it has // CACHE entries following it. //case LOAD_FAST: From 33be113c3951f6583ac8dcb7f45c37eca103649d Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 22 Feb 2023 12:07:01 +0800 Subject: [PATCH 034/280] Part 5: Complete the lazy generation of basic blocks --- Include/cpython/code.h | 15 -- Include/internal/pycore_code.h | 4 +- Include/internal/pycore_opcode.h | 68 +++++---- .../internal/pycore_opcode_macro_to_micro.h | 2 + Include/opcode.h | 140 ++++++++++-------- Lib/opcode.py | 12 ++ Python/bytecodes.c | 61 ++++---- Python/generated_cases.c.h | 59 +++++--- Python/opcode_metadata.h | 18 ++- Python/opcode_targets.h | 46 +++--- Python/tier2.c | 128 +++++++++++++--- 11 files changed, 342 insertions(+), 211 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 9675a6017e555a..3e413c618d5eb0 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -42,21 +42,6 @@ typedef struct { PyObject *_co_freevars; } _PyCoCached; - -//// Used to store intermediate code information for the tier 2 "translator". -//// This is eventually finally converted to _PyTier2BB s. -//// Code Object -> _PyTier2IntermediateCode -> _PyTier2BB s. -//typedef struct _PyTier2IntermediateCode { -// /* Number of entries in _jump_targets */ -// int _jump_target_count; -// /* sorted ascending offsets (from start of field code) for jump targets */ -// // The offsets are in number of _Py_CODEUNITs -// int *_jump_targets; -// int n_instrs; -// _Py_CODEUNIT code[1]; -//} _PyTier2IntermediateCode; - - // Tier 2 interpreter information typedef struct _PyTier2BBMetadata { // Index into _PyTier2Info->bb_data diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index d5612e5c5be40b..914c0c03e95c9b 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -263,8 +263,8 @@ extern _Py_CODEUNIT *_PyTier2_GenerateNextBB( extern _Py_CODEUNIT *_PyTier2_LocateJumpBackwardsBB( struct _PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, _Py_CODEUNIT **tier1_fallback); - - +extern void _PyTier2_RewriteForwardJump(_Py_CODEUNIT *bb_branch, _Py_CODEUNIT *target); +extern void _PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *target); #ifdef Py_STATS diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 689564a071c483..16e0f7f2f65033 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -56,6 +56,10 @@ const uint8_t _PyOpcode_Caches[256] = { }; const uint8_t _PyOpcode_Deopt[256] = { + [BB_TEST_ITER_GEN] = BB_TEST_ITER, + [BB_TEST_ITER_LIST] = BB_TEST_ITER, + [BB_TEST_ITER_RANGE] = BB_TEST_ITER, + [BB_TEST_ITER_TUPLE] = BB_TEST_ITER, [BEFORE_ASYNC_WITH] = BEFORE_ASYNC_WITH, [BEFORE_WITH] = BEFORE_WITH, [BINARY_OP] = BINARY_OP, @@ -297,30 +301,30 @@ static const char *const _PyOpcode_OpName[263] = { [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", [FOR_ITER_RANGE] = "FOR_ITER_RANGE", [FOR_ITER_GEN] = "FOR_ITER_GEN", + [BB_TEST_ITER_LIST] = "BB_TEST_ITER_LIST", + [BB_TEST_ITER_TUPLE] = "BB_TEST_ITER_TUPLE", + [BB_TEST_ITER_RANGE] = "BB_TEST_ITER_RANGE", + [GET_ITER] = "GET_ITER", + [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", + [BB_TEST_ITER_GEN] = "BB_TEST_ITER_GEN", + [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", + [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", + [RETURN_GENERATOR] = "RETURN_GENERATOR", [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", - [GET_ITER] = "GET_ITER", - [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", - [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", - [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", - [RETURN_GENERATOR] = "RETURN_GENERATOR", [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", + [RETURN_VALUE] = "RETURN_VALUE", [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", + [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", - [RETURN_VALUE] = "RETURN_VALUE", - [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", - [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", - [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", - [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", - [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [POP_EXCEPT] = "POP_EXCEPT", [STORE_NAME] = "STORE_NAME", [DELETE_NAME] = "DELETE_NAME", @@ -345,7 +349,7 @@ static const char *const _PyOpcode_OpName[263] = { [JUMP_FORWARD] = "JUMP_FORWARD", [JUMP_IF_FALSE_OR_POP] = "JUMP_IF_FALSE_OR_POP", [JUMP_IF_TRUE_OR_POP] = "JUMP_IF_TRUE_OR_POP", - [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", + [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -375,7 +379,7 @@ static const char *const _PyOpcode_OpName[263] = { [JUMP_BACKWARD] = "JUMP_BACKWARD", [COMPARE_AND_BRANCH] = "COMPARE_AND_BRANCH", [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", - [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", + [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -385,28 +389,34 @@ static const char *const _PyOpcode_OpName[263] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", - [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", - [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", + [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", + [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", - [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", - [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", - [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", - [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", + [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", + [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", + [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", + [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", + [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", + [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", + [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", + [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", [SEND_GEN] = "SEND_GEN", - [BB_BRANCH] = "BB_BRANCH", - [BB_BRANCH_IF_FLAG_UNSET] = "BB_BRANCH_IF_FLAG_UNSET", - [BB_BRANCH_IF_FLAG_SET] = "BB_BRANCH_IF_FLAG_SET", - [BB_TEST_ITER] = "BB_TEST_ITER", [CALL] = "CALL", [KW_NAMES] = "KW_NAMES", [CALL_INTRINSIC_1] = "CALL_INTRINSIC_1", [CALL_INTRINSIC_2] = "CALL_INTRINSIC_2", + [BB_BRANCH] = "BB_BRANCH", + [BB_BRANCH_IF_FLAG_UNSET] = "BB_BRANCH_IF_FLAG_UNSET", + [BB_BRANCH_IF_FLAG_SET] = "BB_BRANCH_IF_FLAG_SET", + [BB_JUMP_IF_FLAG_UNSET] = "BB_JUMP_IF_FLAG_UNSET", + [BB_JUMP_IF_FLAG_SET] = "BB_JUMP_IF_FLAG_SET", + [BB_TEST_ITER] = "BB_TEST_ITER", [BB_TEST_IF_FALSE_OR_POP] = "BB_TEST_IF_FALSE_OR_POP", [BB_TEST_IF_TRUE_OR_POP] = "BB_TEST_IF_TRUE_OR_POP", [BB_TEST_POP_IF_FALSE] = "BB_TEST_POP_IF_FALSE", @@ -416,12 +426,6 @@ static const char *const _PyOpcode_OpName[263] = { [BB_JUMP_BACKWARD_LAZY] = "BB_JUMP_BACKWARD_LAZY", [BINARY_CHECK_INT] = "BINARY_CHECK_INT", [BINARY_OP_ADD_INT_REST] = "BINARY_OP_ADD_INT_REST", - [184] = "<184>", - [185] = "<185>", - [186] = "<186>", - [187] = "<187>", - [188] = "<188>", - [189] = "<189>", [190] = "<190>", [191] = "<191>", [192] = "<192>", @@ -500,12 +504,6 @@ static const char *const _PyOpcode_OpName[263] = { #define EXTRA_CASES \ - case 184: \ - case 185: \ - case 186: \ - case 187: \ - case 188: \ - case 189: \ case 190: \ case 191: \ case 192: \ diff --git a/Include/internal/pycore_opcode_macro_to_micro.h b/Include/internal/pycore_opcode_macro_to_micro.h index 9b9fe6117725b3..0d107771b428ea 100644 --- a/Include/internal/pycore_opcode_macro_to_micro.h +++ b/Include/internal/pycore_opcode_macro_to_micro.h @@ -190,7 +190,9 @@ extern const int _Py_MacroOpUOpCount[] = { [CACHE] = 1, [BB_BRANCH] = 1, [BB_BRANCH_IF_FLAG_UNSET] = 1, +[BB_JUMP_IF_FLAG_UNSET] = 1, [BB_BRANCH_IF_FLAG_SET] = 1, +[BB_JUMP_IF_FLAG_SET] = 1, [BB_JUMP_BACKWARD_LAZY] = 1, }; diff --git a/Include/opcode.h b/Include/opcode.h index 5cdac760821523..ec2989e8abaed5 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -163,32 +163,36 @@ extern "C" { #define FOR_ITER_TUPLE 62 #define FOR_ITER_RANGE 63 #define FOR_ITER_GEN 64 -#define LOAD_ATTR_CLASS 65 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 66 -#define LOAD_ATTR_INSTANCE_VALUE 67 -#define LOAD_ATTR_MODULE 70 -#define LOAD_ATTR_PROPERTY 72 -#define LOAD_ATTR_SLOT 73 -#define LOAD_ATTR_WITH_HINT 76 -#define LOAD_ATTR_METHOD_LAZY_DICT 77 -#define LOAD_ATTR_METHOD_NO_DICT 78 -#define LOAD_ATTR_METHOD_WITH_VALUES 79 -#define LOAD_CONST__LOAD_FAST 80 -#define LOAD_FAST__LOAD_CONST 81 -#define LOAD_FAST__LOAD_FAST 82 -#define LOAD_GLOBAL_BUILTIN 84 -#define LOAD_GLOBAL_MODULE 86 -#define STORE_ATTR_INSTANCE_VALUE 87 -#define STORE_ATTR_SLOT 88 -#define STORE_ATTR_WITH_HINT 113 -#define STORE_FAST__LOAD_FAST 143 -#define STORE_FAST__STORE_FAST 153 -#define STORE_SUBSCR_DICT 154 -#define STORE_SUBSCR_LIST_INT 158 -#define UNPACK_SEQUENCE_LIST 159 -#define UNPACK_SEQUENCE_TUPLE 160 -#define UNPACK_SEQUENCE_TWO_TUPLE 161 -#define SEND_GEN 166 +#define BB_TEST_ITER_LIST 65 +#define BB_TEST_ITER_TUPLE 66 +#define BB_TEST_ITER_RANGE 67 +#define BB_TEST_ITER_GEN 70 +#define LOAD_ATTR_CLASS 72 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 73 +#define LOAD_ATTR_INSTANCE_VALUE 76 +#define LOAD_ATTR_MODULE 77 +#define LOAD_ATTR_PROPERTY 78 +#define LOAD_ATTR_SLOT 79 +#define LOAD_ATTR_WITH_HINT 80 +#define LOAD_ATTR_METHOD_LAZY_DICT 81 +#define LOAD_ATTR_METHOD_NO_DICT 82 +#define LOAD_ATTR_METHOD_WITH_VALUES 84 +#define LOAD_CONST__LOAD_FAST 86 +#define LOAD_FAST__LOAD_CONST 87 +#define LOAD_FAST__LOAD_FAST 88 +#define LOAD_GLOBAL_BUILTIN 113 +#define LOAD_GLOBAL_MODULE 143 +#define STORE_ATTR_INSTANCE_VALUE 153 +#define STORE_ATTR_SLOT 154 +#define STORE_ATTR_WITH_HINT 158 +#define STORE_FAST__LOAD_FAST 159 +#define STORE_FAST__STORE_FAST 160 +#define STORE_SUBSCR_DICT 161 +#define STORE_SUBSCR_LIST_INT 166 +#define UNPACK_SEQUENCE_LIST 167 +#define UNPACK_SEQUENCE_TUPLE 168 +#define UNPACK_SEQUENCE_TWO_TUPLE 169 +#define SEND_GEN 170 #define DO_TRACING 255 // Tier 2 interpreter ops #define RESUME_QUICK 5 @@ -228,46 +232,52 @@ extern "C" { #define FOR_ITER_TUPLE 62 #define FOR_ITER_RANGE 63 #define FOR_ITER_GEN 64 -#define LOAD_ATTR_CLASS 65 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 66 -#define LOAD_ATTR_INSTANCE_VALUE 67 -#define LOAD_ATTR_MODULE 70 -#define LOAD_ATTR_PROPERTY 72 -#define LOAD_ATTR_SLOT 73 -#define LOAD_ATTR_WITH_HINT 76 -#define LOAD_ATTR_METHOD_LAZY_DICT 77 -#define LOAD_ATTR_METHOD_NO_DICT 78 -#define LOAD_ATTR_METHOD_WITH_VALUES 79 -#define LOAD_CONST__LOAD_FAST 80 -#define LOAD_FAST__LOAD_CONST 81 -#define LOAD_FAST__LOAD_FAST 82 -#define LOAD_GLOBAL_BUILTIN 84 -#define LOAD_GLOBAL_MODULE 86 -#define STORE_ATTR_INSTANCE_VALUE 87 -#define STORE_ATTR_SLOT 88 -#define STORE_ATTR_WITH_HINT 113 -#define STORE_FAST__LOAD_FAST 143 -#define STORE_FAST__STORE_FAST 153 -#define STORE_SUBSCR_DICT 154 -#define STORE_SUBSCR_LIST_INT 158 -#define UNPACK_SEQUENCE_LIST 159 -#define UNPACK_SEQUENCE_TUPLE 160 -#define UNPACK_SEQUENCE_TWO_TUPLE 161 -#define SEND_GEN 166 +#define BB_TEST_ITER_LIST 65 +#define BB_TEST_ITER_TUPLE 66 +#define BB_TEST_ITER_RANGE 67 +#define BB_TEST_ITER_GEN 70 +#define LOAD_ATTR_CLASS 72 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 73 +#define LOAD_ATTR_INSTANCE_VALUE 76 +#define LOAD_ATTR_MODULE 77 +#define LOAD_ATTR_PROPERTY 78 +#define LOAD_ATTR_SLOT 79 +#define LOAD_ATTR_WITH_HINT 80 +#define LOAD_ATTR_METHOD_LAZY_DICT 81 +#define LOAD_ATTR_METHOD_NO_DICT 82 +#define LOAD_ATTR_METHOD_WITH_VALUES 84 +#define LOAD_CONST__LOAD_FAST 86 +#define LOAD_FAST__LOAD_CONST 87 +#define LOAD_FAST__LOAD_FAST 88 +#define LOAD_GLOBAL_BUILTIN 113 +#define LOAD_GLOBAL_MODULE 143 +#define STORE_ATTR_INSTANCE_VALUE 153 +#define STORE_ATTR_SLOT 154 +#define STORE_ATTR_WITH_HINT 158 +#define STORE_FAST__LOAD_FAST 159 +#define STORE_FAST__STORE_FAST 160 +#define STORE_SUBSCR_DICT 161 +#define STORE_SUBSCR_LIST_INT 166 +#define UNPACK_SEQUENCE_LIST 167 +#define UNPACK_SEQUENCE_TUPLE 168 +#define UNPACK_SEQUENCE_TWO_TUPLE 169 +#define SEND_GEN 170 #define DO_TRACING 255 -#define BB_BRANCH 167 -#define BB_BRANCH_IF_FLAG_UNSET 168 -#define BB_BRANCH_IF_FLAG_SET 169 -#define BB_TEST_ITER 170 -#define BB_TEST_IF_FALSE_OR_POP 175 -#define BB_TEST_IF_TRUE_OR_POP 176 -#define BB_TEST_POP_IF_FALSE 177 -#define BB_TEST_POP_IF_TRUE 178 -#define BB_TEST_POP_IF_NOT_NONE 179 -#define BB_TEST_POP_IF_NONE 180 -#define BB_JUMP_BACKWARD_LAZY 181 -#define BINARY_CHECK_INT 182 -#define BINARY_OP_ADD_INT_REST 183 +#define BB_BRANCH 175 +#define BB_BRANCH_IF_FLAG_UNSET 176 +#define BB_BRANCH_IF_FLAG_SET 177 +#define BB_JUMP_IF_FLAG_UNSET 178 +#define BB_JUMP_IF_FLAG_SET 179 +#define BB_TEST_ITER 180 +#define BB_TEST_IF_FALSE_OR_POP 181 +#define BB_TEST_IF_TRUE_OR_POP 182 +#define BB_TEST_POP_IF_FALSE 183 +#define BB_TEST_POP_IF_TRUE 184 +#define BB_TEST_POP_IF_NOT_NONE 185 +#define BB_TEST_POP_IF_NONE 186 +#define BB_JUMP_BACKWARD_LAZY 187 +#define BINARY_CHECK_INT 188 +#define BINARY_OP_ADD_INT_REST 189 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/opcode.py b/Lib/opcode.py index 7eb00d7f9e2e04..fb4d55637fdfa1 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -330,6 +330,12 @@ def pseudo_op(name, op, real_ops): "FOR_ITER_RANGE", "FOR_ITER_GEN", ], + "BB_TEST_ITER": [ + "BB_TEST_ITER_LIST", + "BB_TEST_ITER_TUPLE", + "BB_TEST_ITER_RANGE", + "BB_TEST_ITER_GEN", + ], "LOAD_ATTR": [ # These potentially push [NULL, bound method] onto the stack. "LOAD_ATTR_CLASS", @@ -416,6 +422,9 @@ def pseudo_op(name, op, real_ops): "FOR_ITER": { "counter": 1, }, + "BB_TEST_ITER": { + "counter": 1, + }, "LOAD_ATTR": { "counter": 1, "version": 2, @@ -458,6 +467,9 @@ def pseudo_op(name, op, real_ops): # This happens when the fall through is generated, but not the other branch. 'BB_BRANCH_IF_FLAG_UNSET', # When alternate exit is not yet generated. 'BB_BRANCH_IF_FLAG_SET', # When successor exit is not yet generated. + # When both edges are generated + 'BB_JUMP_IF_FLAG_UNSET', + 'BB_JUMP_IF_FLAG_SET', # The final form is that once both branches are generated, we can just # override these instructions with a generic JUMP. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 9602fea53d28b4..caffa4ad6cba86 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2267,7 +2267,7 @@ dummy_func( } // FOR_ITER - inst(BB_TEST_ITER, (iter -- iter, next)) { + inst(BB_TEST_ITER, (unused/1, iter -- iter, next)) { next = (*Py_TYPE(iter)->tp_iternext)(iter); if (next == NULL) { if (_PyErr_Occurred(tstate)) { @@ -2283,6 +2283,7 @@ dummy_func( Py_DECREF(iter); STACK_SHRINK(1); bb_test = false; + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); DISPATCH(); } bb_test = true; @@ -3285,7 +3286,7 @@ dummy_func( } // Tier 2 instructions - inst(BB_BRANCH, (--)) { + inst(BB_BRANCH, (unused/1 --)) { _Py_CODEUNIT *t2_nextinstr = NULL; _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; _Py_CODEUNIT *tier1_fallback = NULL; @@ -3313,24 +3314,20 @@ dummy_func( DISPATCH(); } } - JUMPBY(INLINE_CACHE_ENTRIES_BB_BRANCH); // Their addresses should be the same. Because // The first BB should be generated right after the previous one. - if (next_instr != t2_nextinstr) { - fprintf(stderr, "next: %p, t2 next: %p\n", next_instr, t2_nextinstr); - } - assert(next_instr == t2_nextinstr); + assert(next_instr + INLINE_CACHE_ENTRIES_BB_BRANCH == t2_nextinstr); next_instr = t2_nextinstr; + DISPATCH(); } - inst(BB_BRANCH_IF_FLAG_UNSET, (--)) { + inst(BB_BRANCH_IF_FLAG_UNSET, (unused/1 --)) { if (!bb_test) { + _Py_CODEUNIT *curr = next_instr - 1; _Py_CODEUNIT *t2_nextinstr = NULL; _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; _Py_CODEUNIT *tier1_fallback = NULL; - // @TODO: Rewrite TEST intruction above to a JUMP above. - t2_nextinstr = _PyTier2_GenerateNextBB( frame, cache->bb_id, oparg, &tier1_fallback); if (t2_nextinstr == NULL) { @@ -3338,14 +3335,24 @@ dummy_func( next_instr = tier1_fallback; } next_instr = t2_nextinstr; + + // Rewrite self + _PyTier2_RewriteForwardJump(curr, next_instr); + DISPATCH(); } - else { - JUMPBY(INLINE_CACHE_ENTRIES_BB_BRANCH); + } + + inst(BB_JUMP_IF_FLAG_UNSET, (unused/1 --)) { + if (!bb_test) { + JUMPBY(oparg); + DISPATCH(); } + // Fall through to next instruction. } - inst(BB_BRANCH_IF_FLAG_SET, (--)) { + inst(BB_BRANCH_IF_FLAG_SET, (unused/1 --)) { if (bb_test) { + _Py_CODEUNIT *curr = next_instr - 1; _Py_CODEUNIT *t2_nextinstr = NULL; _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; _Py_CODEUNIT *tier1_fallback = NULL; @@ -3359,13 +3366,23 @@ dummy_func( next_instr = tier1_fallback; } next_instr = t2_nextinstr; + + // Rewrite self + _PyTier2_RewriteForwardJump(curr, next_instr); + DISPATCH(); } - else { - JUMPBY(INLINE_CACHE_ENTRIES_BB_BRANCH); + } + + inst(BB_JUMP_IF_FLAG_SET, (unused/1 --)) { + if (bb_test) { + JUMPBY(oparg); + DISPATCH(); } + // Fall through to next instruction. } inst(BB_JUMP_BACKWARD_LAZY, (--)) { + _Py_CODEUNIT *curr = next_instr - 1; _Py_CODEUNIT *t2_nextinstr = NULL; _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; _Py_CODEUNIT *tier1_fallback = NULL; @@ -3376,18 +3393,10 @@ dummy_func( // Fall back to tier 1. next_instr = tier1_fallback; } - // Rewrite self - _Py_CODEUNIT *curr = next_instr - 1; - _Py_CODEUNIT *prev = curr - 1; - assert(_Py_OPCODE(*prev) == EXTENDED_ARG); - int op_arg = -(int)(t2_nextinstr - next_instr); - // fprintf(stderr, "JUMP_BACKWARD oparg is %d\n", op_arg); - assert(op_arg <= INT16_MAX); - _py_set_opcode(curr, JUMP_BACKWARD); - prev->oparg = (op_arg >> 8) & 0xFF; - curr->oparg = op_arg & 0xFF; - _py_set_opcode(next_instr, END_FOR); next_instr = t2_nextinstr; + + // Rewrite self + _PyTier2_RewriteBackwardJump(curr, next_instr); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 42bfd68f9650f8..5b6e1bd9c1e1cb 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2893,11 +2893,13 @@ Py_DECREF(iter); STACK_SHRINK(1); bb_test = false; + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); DISPATCH(); } bb_test = true; STACK_GROW(1); POKE(1, next); + JUMPBY(1); DISPATCH(); } @@ -4146,25 +4148,20 @@ DISPATCH(); } } - JUMPBY(INLINE_CACHE_ENTRIES_BB_BRANCH); // Their addresses should be the same. Because // The first BB should be generated right after the previous one. - if (next_instr != t2_nextinstr) { - fprintf(stderr, "next: %p, t2 next: %p\n", next_instr, t2_nextinstr); - } - assert(next_instr == t2_nextinstr); + assert(next_instr + INLINE_CACHE_ENTRIES_BB_BRANCH == t2_nextinstr); next_instr = t2_nextinstr; DISPATCH(); } TARGET(BB_BRANCH_IF_FLAG_UNSET) { if (!bb_test) { + _Py_CODEUNIT *curr = next_instr - 1; _Py_CODEUNIT *t2_nextinstr = NULL; _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; _Py_CODEUNIT *tier1_fallback = NULL; - // @TODO: Rewrite TEST intruction above to a JUMP above. - t2_nextinstr = _PyTier2_GenerateNextBB( frame, cache->bb_id, oparg, &tier1_fallback); if (t2_nextinstr == NULL) { @@ -4172,15 +4169,28 @@ next_instr = tier1_fallback; } next_instr = t2_nextinstr; + + // Rewrite self + _PyTier2_RewriteForwardJump(curr, next_instr); + DISPATCH(); } - else { - JUMPBY(INLINE_CACHE_ENTRIES_BB_BRANCH); + JUMPBY(1); + DISPATCH(); + } + + TARGET(BB_JUMP_IF_FLAG_UNSET) { + if (!bb_test) { + JUMPBY(oparg); + DISPATCH(); } + // Fall through to next instruction. + JUMPBY(1); DISPATCH(); } TARGET(BB_BRANCH_IF_FLAG_SET) { if (bb_test) { + _Py_CODEUNIT *curr = next_instr - 1; _Py_CODEUNIT *t2_nextinstr = NULL; _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; _Py_CODEUNIT *tier1_fallback = NULL; @@ -4194,14 +4204,27 @@ next_instr = tier1_fallback; } next_instr = t2_nextinstr; + + // Rewrite self + _PyTier2_RewriteForwardJump(curr, next_instr); + DISPATCH(); } - else { - JUMPBY(INLINE_CACHE_ENTRIES_BB_BRANCH); + JUMPBY(1); + DISPATCH(); + } + + TARGET(BB_JUMP_IF_FLAG_SET) { + if (bb_test) { + JUMPBY(oparg); + DISPATCH(); } + // Fall through to next instruction. + JUMPBY(1); DISPATCH(); } TARGET(BB_JUMP_BACKWARD_LAZY) { + _Py_CODEUNIT *curr = next_instr - 1; _Py_CODEUNIT *t2_nextinstr = NULL; _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; _Py_CODEUNIT *tier1_fallback = NULL; @@ -4212,17 +4235,9 @@ // Fall back to tier 1. next_instr = tier1_fallback; } - // Rewrite self - _Py_CODEUNIT *curr = next_instr - 1; - _Py_CODEUNIT *prev = curr - 1; - assert(_Py_OPCODE(*prev) == EXTENDED_ARG); - int op_arg = -(int)(t2_nextinstr - next_instr); - // fprintf(stderr, "JUMP_BACKWARD oparg is %d\n", op_arg); - assert(op_arg <= INT16_MAX); - _py_set_opcode(curr, JUMP_BACKWARD); - prev->oparg = (op_arg >> 8) & 0xFF; - curr->oparg = op_arg & 0xFF; - _py_set_opcode(next_instr, END_FOR); next_instr = t2_nextinstr; + + // Rewrite self + _PyTier2_RewriteBackwardJump(curr, next_instr); DISPATCH(); } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index aacdfe3ced34d3..2b2148977635b8 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -372,8 +372,12 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 0; case BB_BRANCH_IF_FLAG_UNSET: return 0; + case BB_JUMP_IF_FLAG_UNSET: + return 0; case BB_BRANCH_IF_FLAG_SET: return 0; + case BB_JUMP_IF_FLAG_SET: + return 0; case BB_JUMP_BACKWARD_LAZY: return 0; default: @@ -752,8 +756,12 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case BB_BRANCH_IF_FLAG_UNSET: return 0; + case BB_JUMP_IF_FLAG_UNSET: + return 0; case BB_BRANCH_IF_FLAG_SET: return 0; + case BB_JUMP_IF_FLAG_SET: + return 0; case BB_JUMP_BACKWARD_LAZY: return 0; default: @@ -915,7 +923,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [GET_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [GET_YIELD_FROM_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [FOR_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [BB_TEST_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [BB_TEST_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, [FOR_ITER_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, [FOR_ITER_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, [FOR_ITER_RANGE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, @@ -956,9 +964,11 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [SWAP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [EXTENDED_ARG] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [CACHE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BB_BRANCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BB_BRANCH_IF_FLAG_UNSET] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BB_BRANCH_IF_FLAG_SET] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [BB_BRANCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, + [BB_BRANCH_IF_FLAG_UNSET] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, + [BB_JUMP_IF_FLAG_UNSET] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, + [BB_BRANCH_IF_FLAG_SET] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, + [BB_JUMP_IF_FLAG_SET] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, [BB_JUMP_BACKWARD_LAZY] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, }; #endif diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index e3bb0c3df2838f..c377c673f85cb2 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -64,30 +64,30 @@ static void *opcode_targets[256] = { &&TARGET_FOR_ITER_TUPLE, &&TARGET_FOR_ITER_RANGE, &&TARGET_FOR_ITER_GEN, + &&TARGET_BB_TEST_ITER_LIST, + &&TARGET_BB_TEST_ITER_TUPLE, + &&TARGET_BB_TEST_ITER_RANGE, + &&TARGET_GET_ITER, + &&TARGET_GET_YIELD_FROM_ITER, + &&TARGET_BB_TEST_ITER_GEN, + &&TARGET_LOAD_BUILD_CLASS, &&TARGET_LOAD_ATTR_CLASS, &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, + &&TARGET_LOAD_ASSERTION_ERROR, + &&TARGET_RETURN_GENERATOR, &&TARGET_LOAD_ATTR_INSTANCE_VALUE, - &&TARGET_GET_ITER, - &&TARGET_GET_YIELD_FROM_ITER, &&TARGET_LOAD_ATTR_MODULE, - &&TARGET_LOAD_BUILD_CLASS, &&TARGET_LOAD_ATTR_PROPERTY, &&TARGET_LOAD_ATTR_SLOT, - &&TARGET_LOAD_ASSERTION_ERROR, - &&TARGET_RETURN_GENERATOR, &&TARGET_LOAD_ATTR_WITH_HINT, &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, &&TARGET_LOAD_ATTR_METHOD_NO_DICT, + &&TARGET_RETURN_VALUE, &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, + &&TARGET_SETUP_ANNOTATIONS, &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_LOAD_FAST__LOAD_CONST, &&TARGET_LOAD_FAST__LOAD_FAST, - &&TARGET_RETURN_VALUE, - &&TARGET_LOAD_GLOBAL_BUILTIN, - &&TARGET_SETUP_ANNOTATIONS, - &&TARGET_LOAD_GLOBAL_MODULE, - &&TARGET_STORE_ATTR_INSTANCE_VALUE, - &&TARGET_STORE_ATTR_SLOT, &&TARGET_POP_EXCEPT, &&TARGET_STORE_NAME, &&TARGET_DELETE_NAME, @@ -112,7 +112,7 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_FORWARD, &&TARGET_JUMP_IF_FALSE_OR_POP, &&TARGET_JUMP_IF_TRUE_OR_POP, - &&TARGET_STORE_ATTR_WITH_HINT, + &&TARGET_LOAD_GLOBAL_BUILTIN, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -142,7 +142,7 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_BACKWARD, &&TARGET_COMPARE_AND_BRANCH, &&TARGET_CALL_FUNCTION_EX, - &&TARGET_STORE_FAST__LOAD_FAST, + &&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,24 +152,24 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, - &&TARGET_STORE_FAST__STORE_FAST, - &&TARGET_STORE_SUBSCR_DICT, + &&TARGET_STORE_ATTR_INSTANCE_VALUE, + &&TARGET_STORE_ATTR_SLOT, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, - &&TARGET_STORE_SUBSCR_LIST_INT, - &&TARGET_UNPACK_SEQUENCE_LIST, - &&TARGET_UNPACK_SEQUENCE_TUPLE, - &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, + &&TARGET_STORE_ATTR_WITH_HINT, + &&TARGET_STORE_FAST__LOAD_FAST, + &&TARGET_STORE_FAST__STORE_FAST, + &&TARGET_STORE_SUBSCR_DICT, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, + &&TARGET_STORE_SUBSCR_LIST_INT, + &&TARGET_UNPACK_SEQUENCE_LIST, + &&TARGET_UNPACK_SEQUENCE_TUPLE, + &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&TARGET_SEND_GEN, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_CALL, &&TARGET_KW_NAMES, &&TARGET_CALL_INTRINSIC_1, diff --git a/Python/tier2.c b/Python/tier2.c index c8022ac6048107..44f6cb858698d6 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -369,9 +369,9 @@ emit_type_guard(_Py_CODEUNIT *write_curr, _Py_CODEUNIT guard, int bb_id) { *write_curr = guard; write_curr++; - _py_set_opcode(write_curr, EXTENDED_ARG); - write_curr->oparg = 0; - write_curr++; + //_py_set_opcode(write_curr, EXTENDED_ARG); + //write_curr->oparg = 0; + //write_curr++; _py_set_opcode(write_curr, BB_BRANCH); write_curr->oparg = 0; write_curr++; @@ -426,19 +426,21 @@ emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) #endif Py_UNREACHABLE(); } + assert(oparg <= 0XFF); // Backwards jumps should be handled specially. if (opcode == BB_JUMP_BACKWARD_LAZY) { #if BB_DEBUG fprintf(stderr, "emitted backwards jump %p %d\n", write_curr, _Py_OPCODE(branch)); #endif + // Just in case _py_set_opcode(write_curr, EXTENDED_ARG); - write_curr->oparg = (oparg >> 8) & 0xFF; + write_curr->oparg = 0; write_curr++; // We don't need to recalculate the backward jump, because that only needs to be done // when it locates the next BB in JUMP_BACKWARD_LAZY. _py_set_opcode(write_curr, BB_JUMP_BACKWARD_LAZY); - write_curr->oparg = oparg & 0xFF; + write_curr->oparg = oparg; write_curr++; _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_BB_BRANCH); @@ -449,24 +451,19 @@ emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) // FOR_ITER is also a special jump else if (opcode == BB_TEST_ITER) { #if BB_DEBUG - fprintf(stderr, "emitted logical branch %p %d\n", write_curr, + fprintf(stderr, "emitted iter branch %p %d\n", write_curr, _Py_OPCODE(branch)); #endif // The oparg of FOR_ITER is a little special, the actual jump has to jump over // its own cache entries, the oparg, -1 to tell it to start generating from the // END_FOR. However, at runtime, we will skip this END_FOR. oparg = INLINE_CACHE_ENTRIES_FOR_ITER + oparg - 1; - //_Py_CODEUNIT *start = write_curr; _py_set_opcode(write_curr, BB_TEST_ITER); write_curr->oparg = oparg; write_curr++; - // We don't need to emit inline cache entries, because when this converts, - // we can just make use of the EXTENDED_ARG and BB_BRANCH below. - _py_set_opcode(write_curr, EXTENDED_ARG); - write_curr->oparg = (oparg >> 8) & 0xFF; - write_curr++; + write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_FOR_ITER); _py_set_opcode(write_curr, BB_BRANCH); - write_curr->oparg = oparg & 0xFF; + write_curr->oparg = oparg; write_curr++; _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_BB_BRANCH); @@ -483,12 +480,6 @@ emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) _py_set_opcode(write_curr, opcode); write_curr->oparg = oparg; write_curr++; - // We prefix with an empty EXTENDED_ARG, just in case the future jumps - // are not large enough to handle the bytecode format when jumping to - // the 2nd bb. - _py_set_opcode(write_curr, EXTENDED_ARG); - write_curr->oparg = (oparg >> 8) & 0xFF; - write_curr++; _py_set_opcode(write_curr, BB_BRANCH); write_curr->oparg = oparg & 0xFF; write_curr++; @@ -1206,3 +1197,102 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id, int j _PyTier2BBMetadata *target_metadata = t2_info->bb_data[matching_bb_id]; return target_metadata->tier2_start; } + +/* +At generation of the second outgoing edge (basic block), the instructions look like this: + +BB_TEST_POP_IF_TRUE +BB_BRANCH_IF_FLAG_SET +CACHE + +Since both edges are now generated, we want to rewrite it to: + +BB_TEST_POP_IF_TRUE +BB_JUMP_IF_FLAG_SET +CACHE (will be converted to EXTENDED_ARGS if we need a bigger jump) + +Some instructions will be special since they need CACHE entries. E.g. FOR_ITER + +BB_TEST_ITER +CACHE +BB_BRANCH_IF_FLAG_SET +CACHE + +Backwards jumps are handled by another function. +*/ + +void +_PyTier2_RewriteForwardJump(_Py_CODEUNIT *bb_branch, _Py_CODEUNIT *target) +{ + _Py_CODEUNIT *write_curr = bb_branch; + // -1 because the PC is auto incremented + int oparg = (int)(target - bb_branch - 1); + int branch = _Py_OPCODE(*bb_branch); + assert(branch == BB_BRANCH_IF_FLAG_SET || branch == BB_BRANCH_IF_FLAG_UNSET); + bool requires_extended = oparg > 0xFF; + assert(oparg <= 0xFFFF); + if (requires_extended) { + _py_set_opcode(write_curr, EXTENDED_ARG); + write_curr->oparg = (oparg >> 8) & 0xFF; + write_curr++; + // -1 to oparg because now the jump instruction moves one unit forward. + oparg--; + } + _py_set_opcode(write_curr, + branch == BB_BRANCH_IF_FLAG_SET ? BB_JUMP_IF_FLAG_SET : BB_JUMP_IF_FLAG_UNSET); + write_curr->oparg = oparg & 0xFF; + write_curr++; + if (!requires_extended) { + _py_set_opcode(write_curr, NOP); + write_curr++; + } + +} + + +/* +Before: + +EXTENDED_ARG/NOP +JUMP_BACKWARD_LAZY +CACHE + + +After: + +EXTENDED_ARG (if needed, else NOP) +JUMP_BACKWARD_LAZY +END_FOR +*/ + +void +_PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *target) +{ + _Py_CODEUNIT *write_curr = jump_backward_lazy - 1; + _Py_CODEUNIT *prev = jump_backward_lazy - 1; + assert(_Py_OPCODE(*jump_backward_lazy) == BB_JUMP_BACKWARD_LAZY); + assert(_Py_OPCODE(*prev) == EXTENDED_ARG); + + // +1 because we increment the PC before JUMPBY + int oparg = (int)(target - (jump_backward_lazy + 1)); + assert(oparg < 0); + oparg = -oparg; + assert(oparg > 0); + assert(oparg <= 0xFFFF); + + bool requires_extended = oparg > 0xFF; + if (requires_extended) { + _py_set_opcode(write_curr, EXTENDED_ARG); + write_curr->oparg = (oparg >> 8) & 0xFF; + write_curr++; + } + else { + _py_set_opcode(write_curr, NOP); + write_curr++; + } + _py_set_opcode(write_curr, JUMP_BACKWARD); + write_curr->oparg = oparg & 0xFF; + write_curr++; + _py_set_opcode(write_curr, END_FOR); + write_curr++; +} From 78810991b37e3a9d3ad856fb63f85e41ba4784e9 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 24 Feb 2023 15:04:18 +0800 Subject: [PATCH 035/280] Fix definition of BINARY_CHECK_INT --- Include/internal/pycore_opcode_macro_to_micro.h | 9 ++++----- Python/bytecodes.c | 9 +++++---- Python/generated_cases.c.h | 14 ++++---------- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/Include/internal/pycore_opcode_macro_to_micro.h b/Include/internal/pycore_opcode_macro_to_micro.h index 0d107771b428ea..b33b88b838099b 100644 --- a/Include/internal/pycore_opcode_macro_to_micro.h +++ b/Include/internal/pycore_opcode_macro_to_micro.h @@ -34,7 +34,7 @@ extern const int _Py_MacroOpUOpCount[] = { [BINARY_OP_ADD_UNICODE] = 1, [BINARY_OP_INPLACE_ADD_UNICODE] = 1, [BINARY_OP_ADD_FLOAT] = 1, -[BINARY_OP_ADD_INT] = 2, +[BINARY_OP_ADD_INT] = 1, [BINARY_CHECK_INT] = 1, [BINARY_OP_ADD_INT_REST] = 1, [BINARY_SUBSCR] = 1, @@ -196,11 +196,10 @@ extern const int _Py_MacroOpUOpCount[] = { [BB_JUMP_BACKWARD_LAZY] = 1, }; -extern const int _Py_MacroOpToUOp[][2] = { -[BINARY_OP_ADD_INT] = {BINARY_CHECK_INT, BINARY_OP_ADD_INT_REST}, +extern const int _Py_MacroOpToUOp[][1] = { +[BINARY_OP_ADD_INT] = {BINARY_OP_ADD_INT_REST}, }; -extern const PyTypeObject *_Py_UOpGuardTypes[][2] = { -[BINARY_CHECK_INT] = {&PyLong_Type, &PyLong_Type}, +extern const PyTypeObject *_Py_UOpGuardTypes[][0] = { }; #ifdef __cplusplus } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index caffa4ad6cba86..316171a08f45f7 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -292,14 +292,15 @@ dummy_func( } macro_inst(BINARY_OP_ADD_INT, (unused/1, left, right -- sum)) { - U_INST(BINARY_CHECK_INT); + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); + DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); U_INST(BINARY_OP_ADD_INT_REST); } - u_inst(BINARY_CHECK_INT, (left, right -- left : PyLong_Type, right: PyLong_Type)) { + inst(BINARY_CHECK_INT, (left, right -- left : PyLong_Type, right : PyLong_Type)) { assert(cframe.use_tracing == 0); - DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); - DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); + bb_test = PyLong_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); } u_inst(BINARY_OP_ADD_INT_REST, (left, right -- sum)) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 5b6e1bd9c1e1cb..9ff9a718eef8ca 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2,13 +2,6 @@ // from Python\bytecodes.c // Do not edit! - #define UOP_BINARY_CHECK_INT() \ - do { \ - assert(cframe.use_tracing == 0);\ - DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);\ - DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);\ - } while (0) - #define UOP_BINARY_OP_ADD_INT_REST() \ do { \ STAT_INC(BINARY_OP, hit);\ @@ -414,7 +407,9 @@ PyObject *right = PEEK(1); PyObject *left = PEEK(2); PyObject *sum; - UOP_BINARY_CHECK_INT(); + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); + DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); UOP_BINARY_OP_ADD_INT_REST(); STACK_SHRINK(1); POKE(1, sum); @@ -426,8 +421,7 @@ PyObject *right = PEEK(1); PyObject *left = PEEK(2); assert(cframe.use_tracing == 0); - DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); - DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); + bb_test = PyLong_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); DISPATCH(); } From 280e961838297246e92231180c8f0c59576d895b Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 24 Feb 2023 15:04:18 +0800 Subject: [PATCH 036/280] Fix definition of BINARY_CHECK_INT --- Include/internal/pycore_opcode_macro_to_micro.h | 9 ++++----- Python/bytecodes.c | 9 +++++---- Python/generated_cases.c.h | 14 ++++---------- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/Include/internal/pycore_opcode_macro_to_micro.h b/Include/internal/pycore_opcode_macro_to_micro.h index 0d107771b428ea..b33b88b838099b 100644 --- a/Include/internal/pycore_opcode_macro_to_micro.h +++ b/Include/internal/pycore_opcode_macro_to_micro.h @@ -34,7 +34,7 @@ extern const int _Py_MacroOpUOpCount[] = { [BINARY_OP_ADD_UNICODE] = 1, [BINARY_OP_INPLACE_ADD_UNICODE] = 1, [BINARY_OP_ADD_FLOAT] = 1, -[BINARY_OP_ADD_INT] = 2, +[BINARY_OP_ADD_INT] = 1, [BINARY_CHECK_INT] = 1, [BINARY_OP_ADD_INT_REST] = 1, [BINARY_SUBSCR] = 1, @@ -196,11 +196,10 @@ extern const int _Py_MacroOpUOpCount[] = { [BB_JUMP_BACKWARD_LAZY] = 1, }; -extern const int _Py_MacroOpToUOp[][2] = { -[BINARY_OP_ADD_INT] = {BINARY_CHECK_INT, BINARY_OP_ADD_INT_REST}, +extern const int _Py_MacroOpToUOp[][1] = { +[BINARY_OP_ADD_INT] = {BINARY_OP_ADD_INT_REST}, }; -extern const PyTypeObject *_Py_UOpGuardTypes[][2] = { -[BINARY_CHECK_INT] = {&PyLong_Type, &PyLong_Type}, +extern const PyTypeObject *_Py_UOpGuardTypes[][0] = { }; #ifdef __cplusplus } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index caffa4ad6cba86..316171a08f45f7 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -292,14 +292,15 @@ dummy_func( } macro_inst(BINARY_OP_ADD_INT, (unused/1, left, right -- sum)) { - U_INST(BINARY_CHECK_INT); + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); + DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); U_INST(BINARY_OP_ADD_INT_REST); } - u_inst(BINARY_CHECK_INT, (left, right -- left : PyLong_Type, right: PyLong_Type)) { + inst(BINARY_CHECK_INT, (left, right -- left : PyLong_Type, right : PyLong_Type)) { assert(cframe.use_tracing == 0); - DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); - DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); + bb_test = PyLong_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); } u_inst(BINARY_OP_ADD_INT_REST, (left, right -- sum)) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 5b6e1bd9c1e1cb..9ff9a718eef8ca 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2,13 +2,6 @@ // from Python\bytecodes.c // Do not edit! - #define UOP_BINARY_CHECK_INT() \ - do { \ - assert(cframe.use_tracing == 0);\ - DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);\ - DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);\ - } while (0) - #define UOP_BINARY_OP_ADD_INT_REST() \ do { \ STAT_INC(BINARY_OP, hit);\ @@ -414,7 +407,9 @@ PyObject *right = PEEK(1); PyObject *left = PEEK(2); PyObject *sum; - UOP_BINARY_CHECK_INT(); + assert(cframe.use_tracing == 0); + DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); + DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); UOP_BINARY_OP_ADD_INT_REST(); STACK_SHRINK(1); POKE(1, sum); @@ -426,8 +421,7 @@ PyObject *right = PEEK(1); PyObject *left = PEEK(2); assert(cframe.use_tracing == 0); - DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); - DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); + bb_test = PyLong_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); DISPATCH(); } From 89ca5de784dcaea76fb813042d005ae724f3dd8a Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 24 Feb 2023 23:35:34 +0800 Subject: [PATCH 037/280] Add JUMP_BACKWARD_QUICK --- Include/internal/pycore_opcode.h | 42 +-- .../internal/pycore_opcode_macro_to_micro.h | 207 ------------ Include/opcode.h | 296 +++++++++--------- Lib/opcode.py | 3 + PCbuild/pythoncore.vcxproj | 5 +- PCbuild/pythoncore.vcxproj.filters | 3 - Python/bytecodes.c | 5 + Python/generated_cases.c.h | 6 + Python/opcode_metadata.h | 7 +- Python/opcode_targets.h | 40 +-- Python/specialize.c | 1 - Python/tier2.c | 126 ++++---- Tools/cases_generator/generate_cases.py | 4 +- 13 files changed, 271 insertions(+), 474 deletions(-) delete mode 100644 Include/internal/pycore_opcode_macro_to_micro.h diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 16e0f7f2f65033..4c46a2cb3eb5a8 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -146,6 +146,7 @@ const uint8_t _PyOpcode_Deopt[256] = { [IS_OP] = IS_OP, [JUMP_BACKWARD] = JUMP_BACKWARD, [JUMP_BACKWARD_NO_INTERRUPT] = JUMP_BACKWARD_NO_INTERRUPT, + [JUMP_BACKWARD_QUICK] = JUMP_BACKWARD, [JUMP_FORWARD] = JUMP_FORWARD, [JUMP_IF_FALSE_OR_POP] = JUMP_IF_FALSE_OR_POP, [JUMP_IF_TRUE_OR_POP] = JUMP_IF_TRUE_OR_POP, @@ -242,16 +243,17 @@ static const char *const _PyOpcode_OpName[263] = { [INTERPRETER_EXIT] = "INTERPRETER_EXIT", [END_FOR] = "END_FOR", [RESUME_QUICK] = "RESUME_QUICK", + [JUMP_BACKWARD_QUICK] = "JUMP_BACKWARD_QUICK", [BINARY_OP_ADD_FLOAT] = "BINARY_OP_ADD_FLOAT", [BINARY_OP_ADD_INT] = "BINARY_OP_ADD_INT", - [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE", [NOP] = "NOP", - [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", + [BINARY_OP_ADD_UNICODE] = "BINARY_OP_ADD_UNICODE", [UNARY_NEGATIVE] = "UNARY_NEGATIVE", [UNARY_NOT] = "UNARY_NOT", + [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE", [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT", - [BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT", [UNARY_INVERT] = "UNARY_INVERT", + [BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT", [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT", [BINARY_OP_SUBTRACT_INT] = "BINARY_OP_SUBTRACT_INT", [BINARY_SUBSCR_DICT] = "BINARY_SUBSCR_DICT", @@ -260,20 +262,20 @@ static const char *const _PyOpcode_OpName[263] = { [BINARY_SUBSCR_TUPLE_INT] = "BINARY_SUBSCR_TUPLE_INT", [CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS", [CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS", - [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", [BINARY_SUBSCR] = "BINARY_SUBSCR", [BINARY_SLICE] = "BINARY_SLICE", [STORE_SLICE] = "STORE_SLICE", + [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS", [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS", - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", [GET_LEN] = "GET_LEN", [MATCH_MAPPING] = "MATCH_MAPPING", [MATCH_SEQUENCE] = "MATCH_SEQUENCE", [MATCH_KEYS] = "MATCH_KEYS", - [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS", [PUSH_EXC_INFO] = "PUSH_EXC_INFO", [CHECK_EXC_MATCH] = "CHECK_EXC_MATCH", [CHECK_EG_MATCH] = "CHECK_EG_MATCH", + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS", [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST", [CALL_NO_KW_BUILTIN_O] = "CALL_NO_KW_BUILTIN_O", [CALL_NO_KW_ISINSTANCE] = "CALL_NO_KW_ISINSTANCE", @@ -284,7 +286,6 @@ static const char *const _PyOpcode_OpName[263] = { [CALL_NO_KW_METHOD_DESCRIPTOR_O] = "CALL_NO_KW_METHOD_DESCRIPTOR_O", [CALL_NO_KW_STR_1] = "CALL_NO_KW_STR_1", [CALL_NO_KW_TUPLE_1] = "CALL_NO_KW_TUPLE_1", - [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", [WITH_EXCEPT_START] = "WITH_EXCEPT_START", [GET_AITER] = "GET_AITER", [GET_ANEXT] = "GET_ANEXT", @@ -292,39 +293,39 @@ static const char *const _PyOpcode_OpName[263] = { [BEFORE_WITH] = "BEFORE_WITH", [END_ASYNC_FOR] = "END_ASYNC_FOR", [CLEANUP_THROW] = "CLEANUP_THROW", + [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", [COMPARE_AND_BRANCH_FLOAT] = "COMPARE_AND_BRANCH_FLOAT", [COMPARE_AND_BRANCH_INT] = "COMPARE_AND_BRANCH_INT", [COMPARE_AND_BRANCH_STR] = "COMPARE_AND_BRANCH_STR", - [FOR_ITER_LIST] = "FOR_ITER_LIST", [STORE_SUBSCR] = "STORE_SUBSCR", [DELETE_SUBSCR] = "DELETE_SUBSCR", + [FOR_ITER_LIST] = "FOR_ITER_LIST", [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", [FOR_ITER_RANGE] = "FOR_ITER_RANGE", [FOR_ITER_GEN] = "FOR_ITER_GEN", [BB_TEST_ITER_LIST] = "BB_TEST_ITER_LIST", [BB_TEST_ITER_TUPLE] = "BB_TEST_ITER_TUPLE", - [BB_TEST_ITER_RANGE] = "BB_TEST_ITER_RANGE", [GET_ITER] = "GET_ITER", [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", - [BB_TEST_ITER_GEN] = "BB_TEST_ITER_GEN", + [BB_TEST_ITER_RANGE] = "BB_TEST_ITER_RANGE", [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", + [BB_TEST_ITER_GEN] = "BB_TEST_ITER_GEN", [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", - [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", [RETURN_GENERATOR] = "RETURN_GENERATOR", + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", - [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", [RETURN_VALUE] = "RETURN_VALUE", - [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", + [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", + [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", - [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", [POP_EXCEPT] = "POP_EXCEPT", [STORE_NAME] = "STORE_NAME", [DELETE_NAME] = "DELETE_NAME", @@ -349,7 +350,7 @@ static const char *const _PyOpcode_OpName[263] = { [JUMP_FORWARD] = "JUMP_FORWARD", [JUMP_IF_FALSE_OR_POP] = "JUMP_IF_FALSE_OR_POP", [JUMP_IF_TRUE_OR_POP] = "JUMP_IF_TRUE_OR_POP", - [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", + [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -379,7 +380,7 @@ static const char *const _PyOpcode_OpName[263] = { [JUMP_BACKWARD] = "JUMP_BACKWARD", [COMPARE_AND_BRANCH] = "COMPARE_AND_BRANCH", [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", - [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", + [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -389,28 +390,29 @@ static const char *const _PyOpcode_OpName[263] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", + [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", - [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", + [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", - [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", + [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", - [SEND_GEN] = "SEND_GEN", [CALL] = "CALL", [KW_NAMES] = "KW_NAMES", [CALL_INTRINSIC_1] = "CALL_INTRINSIC_1", [CALL_INTRINSIC_2] = "CALL_INTRINSIC_2", + [SEND_GEN] = "SEND_GEN", [BB_BRANCH] = "BB_BRANCH", [BB_BRANCH_IF_FLAG_UNSET] = "BB_BRANCH_IF_FLAG_UNSET", [BB_BRANCH_IF_FLAG_SET] = "BB_BRANCH_IF_FLAG_SET", @@ -426,7 +428,6 @@ static const char *const _PyOpcode_OpName[263] = { [BB_JUMP_BACKWARD_LAZY] = "BB_JUMP_BACKWARD_LAZY", [BINARY_CHECK_INT] = "BINARY_CHECK_INT", [BINARY_OP_ADD_INT_REST] = "BINARY_OP_ADD_INT_REST", - [190] = "<190>", [191] = "<191>", [192] = "<192>", [193] = "<193>", @@ -504,7 +505,6 @@ static const char *const _PyOpcode_OpName[263] = { #define EXTRA_CASES \ - case 190: \ case 191: \ case 192: \ case 193: \ diff --git a/Include/internal/pycore_opcode_macro_to_micro.h b/Include/internal/pycore_opcode_macro_to_micro.h deleted file mode 100644 index b33b88b838099b..00000000000000 --- a/Include/internal/pycore_opcode_macro_to_micro.h +++ /dev/null @@ -1,207 +0,0 @@ -// This file is generated by Tools\cases_generator\generate_cases.py --macromap -// from Python\bytecodes.c -// Do not edit! - -#ifndef Py_INTERNAL_OPCODE_MACRO_TO_MICRO_H -#define Py_INTERNAL_OPCODE_MACRO_TO_MICRO_H -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef Py_BUILD_CORE -# error "this header requires Py_BUILD_CORE define" -#endif -#include "opcode.h" - -extern const int _Py_MacroOpUOpCount[] = { -[NOP] = 1, -[RESUME] = 1, -[RESUME_QUICK] = 1, -[LOAD_CLOSURE] = 1, -[LOAD_FAST_CHECK] = 1, -[LOAD_FAST] = 1, -[LOAD_CONST] = 1, -[STORE_FAST] = 1, -[POP_TOP] = 1, -[PUSH_NULL] = 1, -[UNARY_NEGATIVE] = 1, -[UNARY_NOT] = 1, -[UNARY_INVERT] = 1, -[BINARY_OP_MULTIPLY_INT] = 1, -[BINARY_OP_MULTIPLY_FLOAT] = 1, -[BINARY_OP_SUBTRACT_INT] = 1, -[BINARY_OP_SUBTRACT_FLOAT] = 1, -[BINARY_OP_ADD_UNICODE] = 1, -[BINARY_OP_INPLACE_ADD_UNICODE] = 1, -[BINARY_OP_ADD_FLOAT] = 1, -[BINARY_OP_ADD_INT] = 1, -[BINARY_CHECK_INT] = 1, -[BINARY_OP_ADD_INT_REST] = 1, -[BINARY_SUBSCR] = 1, -[BINARY_SLICE] = 1, -[STORE_SLICE] = 1, -[BINARY_SUBSCR_LIST_INT] = 1, -[BINARY_SUBSCR_TUPLE_INT] = 1, -[BINARY_SUBSCR_DICT] = 1, -[BINARY_SUBSCR_GETITEM] = 1, -[LIST_APPEND] = 1, -[SET_ADD] = 1, -[STORE_SUBSCR] = 1, -[STORE_SUBSCR_LIST_INT] = 1, -[STORE_SUBSCR_DICT] = 1, -[DELETE_SUBSCR] = 1, -[CALL_INTRINSIC_1] = 1, -[CALL_INTRINSIC_2] = 1, -[RAISE_VARARGS] = 1, -[INTERPRETER_EXIT] = 1, -[RETURN_VALUE] = 1, -[RETURN_CONST] = 1, -[GET_AITER] = 1, -[GET_ANEXT] = 1, -[GET_AWAITABLE] = 1, -[SEND] = 1, -[SEND_GEN] = 1, -[YIELD_VALUE] = 1, -[POP_EXCEPT] = 1, -[RERAISE] = 1, -[END_ASYNC_FOR] = 1, -[CLEANUP_THROW] = 1, -[LOAD_ASSERTION_ERROR] = 1, -[LOAD_BUILD_CLASS] = 1, -[STORE_NAME] = 1, -[DELETE_NAME] = 1, -[UNPACK_SEQUENCE] = 1, -[UNPACK_SEQUENCE_TWO_TUPLE] = 1, -[UNPACK_SEQUENCE_TUPLE] = 1, -[UNPACK_SEQUENCE_LIST] = 1, -[UNPACK_EX] = 1, -[STORE_ATTR] = 1, -[DELETE_ATTR] = 1, -[STORE_GLOBAL] = 1, -[DELETE_GLOBAL] = 1, -[LOAD_NAME] = 1, -[LOAD_GLOBAL] = 1, -[LOAD_GLOBAL_MODULE] = 1, -[LOAD_GLOBAL_BUILTIN] = 1, -[DELETE_FAST] = 1, -[MAKE_CELL] = 1, -[DELETE_DEREF] = 1, -[LOAD_CLASSDEREF] = 1, -[LOAD_DEREF] = 1, -[STORE_DEREF] = 1, -[COPY_FREE_VARS] = 1, -[BUILD_STRING] = 1, -[BUILD_TUPLE] = 1, -[BUILD_LIST] = 1, -[LIST_EXTEND] = 1, -[SET_UPDATE] = 1, -[BUILD_SET] = 1, -[BUILD_MAP] = 1, -[SETUP_ANNOTATIONS] = 1, -[BUILD_CONST_KEY_MAP] = 1, -[DICT_UPDATE] = 1, -[DICT_MERGE] = 1, -[MAP_ADD] = 1, -[LOAD_ATTR] = 1, -[LOAD_ATTR_INSTANCE_VALUE] = 1, -[LOAD_ATTR_MODULE] = 1, -[LOAD_ATTR_WITH_HINT] = 1, -[LOAD_ATTR_SLOT] = 1, -[LOAD_ATTR_CLASS] = 1, -[LOAD_ATTR_PROPERTY] = 1, -[LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = 1, -[STORE_ATTR_INSTANCE_VALUE] = 1, -[STORE_ATTR_WITH_HINT] = 1, -[STORE_ATTR_SLOT] = 1, -[COMPARE_OP] = 1, -[COMPARE_AND_BRANCH] = 1, -[COMPARE_AND_BRANCH_FLOAT] = 1, -[COMPARE_AND_BRANCH_INT] = 1, -[COMPARE_AND_BRANCH_STR] = 1, -[IS_OP] = 1, -[CONTAINS_OP] = 1, -[CHECK_EG_MATCH] = 1, -[CHECK_EXC_MATCH] = 1, -[IMPORT_NAME] = 1, -[IMPORT_FROM] = 1, -[JUMP_FORWARD] = 1, -[JUMP_BACKWARD] = 1, -[POP_JUMP_IF_FALSE] = 1, -[BB_TEST_POP_IF_FALSE] = 1, -[POP_JUMP_IF_TRUE] = 1, -[BB_TEST_POP_IF_TRUE] = 1, -[POP_JUMP_IF_NOT_NONE] = 1, -[BB_TEST_POP_IF_NOT_NONE] = 1, -[POP_JUMP_IF_NONE] = 1, -[BB_TEST_POP_IF_NONE] = 1, -[JUMP_IF_FALSE_OR_POP] = 1, -[BB_TEST_IF_FALSE_OR_POP] = 1, -[JUMP_IF_TRUE_OR_POP] = 1, -[BB_TEST_IF_TRUE_OR_POP] = 1, -[JUMP_BACKWARD_NO_INTERRUPT] = 1, -[GET_LEN] = 1, -[MATCH_CLASS] = 1, -[MATCH_MAPPING] = 1, -[MATCH_SEQUENCE] = 1, -[MATCH_KEYS] = 1, -[GET_ITER] = 1, -[GET_YIELD_FROM_ITER] = 1, -[FOR_ITER] = 1, -[BB_TEST_ITER] = 1, -[FOR_ITER_LIST] = 1, -[FOR_ITER_TUPLE] = 1, -[FOR_ITER_RANGE] = 1, -[FOR_ITER_GEN] = 1, -[BEFORE_ASYNC_WITH] = 1, -[BEFORE_WITH] = 1, -[WITH_EXCEPT_START] = 1, -[PUSH_EXC_INFO] = 1, -[LOAD_ATTR_METHOD_WITH_VALUES] = 1, -[LOAD_ATTR_METHOD_NO_DICT] = 1, -[LOAD_ATTR_METHOD_LAZY_DICT] = 1, -[KW_NAMES] = 1, -[CALL] = 1, -[CALL_BOUND_METHOD_EXACT_ARGS] = 1, -[CALL_PY_EXACT_ARGS] = 1, -[CALL_PY_WITH_DEFAULTS] = 1, -[CALL_NO_KW_TYPE_1] = 1, -[CALL_NO_KW_STR_1] = 1, -[CALL_NO_KW_TUPLE_1] = 1, -[CALL_BUILTIN_CLASS] = 1, -[CALL_NO_KW_BUILTIN_O] = 1, -[CALL_NO_KW_BUILTIN_FAST] = 1, -[CALL_BUILTIN_FAST_WITH_KEYWORDS] = 1, -[CALL_NO_KW_LEN] = 1, -[CALL_NO_KW_ISINSTANCE] = 1, -[CALL_NO_KW_LIST_APPEND] = 1, -[CALL_NO_KW_METHOD_DESCRIPTOR_O] = 1, -[CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = 1, -[CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = 1, -[CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = 1, -[CALL_FUNCTION_EX] = 1, -[MAKE_FUNCTION] = 1, -[RETURN_GENERATOR] = 1, -[BUILD_SLICE] = 1, -[FORMAT_VALUE] = 1, -[COPY] = 1, -[BINARY_OP] = 1, -[SWAP] = 1, -[EXTENDED_ARG] = 1, -[CACHE] = 1, -[BB_BRANCH] = 1, -[BB_BRANCH_IF_FLAG_UNSET] = 1, -[BB_JUMP_IF_FLAG_UNSET] = 1, -[BB_BRANCH_IF_FLAG_SET] = 1, -[BB_JUMP_IF_FLAG_SET] = 1, -[BB_JUMP_BACKWARD_LAZY] = 1, -}; - -extern const int _Py_MacroOpToUOp[][1] = { -[BINARY_OP_ADD_INT] = {BINARY_OP_ADD_INT_REST}, -}; -extern const PyTypeObject *_Py_UOpGuardTypes[][0] = { -}; -#ifdef __cplusplus -} -#endif -#endif // Py_INTERNAL_OPCODE_MACRO_TO_MICRO diff --git a/Include/opcode.h b/Include/opcode.h index ec2989e8abaed5..7f0b02ab7687e2 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -127,157 +127,159 @@ extern "C" { #define LOAD_METHOD 262 #define MAX_PSEUDO_OPCODE 262 #define RESUME_QUICK 5 -#define BINARY_OP_ADD_FLOAT 6 -#define BINARY_OP_ADD_INT 7 -#define BINARY_OP_ADD_UNICODE 8 -#define BINARY_OP_INPLACE_ADD_UNICODE 10 -#define BINARY_OP_MULTIPLY_FLOAT 13 -#define BINARY_OP_MULTIPLY_INT 14 -#define BINARY_OP_SUBTRACT_FLOAT 16 -#define BINARY_OP_SUBTRACT_INT 17 -#define BINARY_SUBSCR_DICT 18 -#define BINARY_SUBSCR_GETITEM 19 -#define BINARY_SUBSCR_LIST_INT 20 -#define BINARY_SUBSCR_TUPLE_INT 21 -#define CALL_PY_EXACT_ARGS 22 -#define CALL_PY_WITH_DEFAULTS 23 -#define CALL_BOUND_METHOD_EXACT_ARGS 24 -#define CALL_BUILTIN_CLASS 28 -#define CALL_BUILTIN_FAST_WITH_KEYWORDS 29 -#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 34 -#define CALL_NO_KW_BUILTIN_FAST 38 -#define CALL_NO_KW_BUILTIN_O 39 -#define CALL_NO_KW_ISINSTANCE 40 -#define CALL_NO_KW_LEN 41 -#define CALL_NO_KW_LIST_APPEND 42 -#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 43 -#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 44 -#define CALL_NO_KW_METHOD_DESCRIPTOR_O 45 -#define CALL_NO_KW_STR_1 46 -#define CALL_NO_KW_TUPLE_1 47 -#define CALL_NO_KW_TYPE_1 48 -#define COMPARE_AND_BRANCH_FLOAT 56 -#define COMPARE_AND_BRANCH_INT 57 -#define COMPARE_AND_BRANCH_STR 58 -#define FOR_ITER_LIST 59 -#define FOR_ITER_TUPLE 62 -#define FOR_ITER_RANGE 63 -#define FOR_ITER_GEN 64 -#define BB_TEST_ITER_LIST 65 -#define BB_TEST_ITER_TUPLE 66 -#define BB_TEST_ITER_RANGE 67 -#define BB_TEST_ITER_GEN 70 -#define LOAD_ATTR_CLASS 72 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 73 -#define LOAD_ATTR_INSTANCE_VALUE 76 -#define LOAD_ATTR_MODULE 77 -#define LOAD_ATTR_PROPERTY 78 -#define LOAD_ATTR_SLOT 79 -#define LOAD_ATTR_WITH_HINT 80 -#define LOAD_ATTR_METHOD_LAZY_DICT 81 -#define LOAD_ATTR_METHOD_NO_DICT 82 -#define LOAD_ATTR_METHOD_WITH_VALUES 84 -#define LOAD_CONST__LOAD_FAST 86 -#define LOAD_FAST__LOAD_CONST 87 -#define LOAD_FAST__LOAD_FAST 88 -#define LOAD_GLOBAL_BUILTIN 113 -#define LOAD_GLOBAL_MODULE 143 -#define STORE_ATTR_INSTANCE_VALUE 153 -#define STORE_ATTR_SLOT 154 -#define STORE_ATTR_WITH_HINT 158 -#define STORE_FAST__LOAD_FAST 159 -#define STORE_FAST__STORE_FAST 160 -#define STORE_SUBSCR_DICT 161 -#define STORE_SUBSCR_LIST_INT 166 -#define UNPACK_SEQUENCE_LIST 167 -#define UNPACK_SEQUENCE_TUPLE 168 -#define UNPACK_SEQUENCE_TWO_TUPLE 169 -#define SEND_GEN 170 +#define JUMP_BACKWARD_QUICK 6 +#define BINARY_OP_ADD_FLOAT 7 +#define BINARY_OP_ADD_INT 8 +#define BINARY_OP_ADD_UNICODE 10 +#define BINARY_OP_INPLACE_ADD_UNICODE 13 +#define BINARY_OP_MULTIPLY_FLOAT 14 +#define BINARY_OP_MULTIPLY_INT 16 +#define BINARY_OP_SUBTRACT_FLOAT 17 +#define BINARY_OP_SUBTRACT_INT 18 +#define BINARY_SUBSCR_DICT 19 +#define BINARY_SUBSCR_GETITEM 20 +#define BINARY_SUBSCR_LIST_INT 21 +#define BINARY_SUBSCR_TUPLE_INT 22 +#define CALL_PY_EXACT_ARGS 23 +#define CALL_PY_WITH_DEFAULTS 24 +#define CALL_BOUND_METHOD_EXACT_ARGS 28 +#define CALL_BUILTIN_CLASS 29 +#define CALL_BUILTIN_FAST_WITH_KEYWORDS 34 +#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 38 +#define CALL_NO_KW_BUILTIN_FAST 39 +#define CALL_NO_KW_BUILTIN_O 40 +#define CALL_NO_KW_ISINSTANCE 41 +#define CALL_NO_KW_LEN 42 +#define CALL_NO_KW_LIST_APPEND 43 +#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 44 +#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 45 +#define CALL_NO_KW_METHOD_DESCRIPTOR_O 46 +#define CALL_NO_KW_STR_1 47 +#define CALL_NO_KW_TUPLE_1 48 +#define CALL_NO_KW_TYPE_1 56 +#define COMPARE_AND_BRANCH_FLOAT 57 +#define COMPARE_AND_BRANCH_INT 58 +#define COMPARE_AND_BRANCH_STR 59 +#define FOR_ITER_LIST 62 +#define FOR_ITER_TUPLE 63 +#define FOR_ITER_RANGE 64 +#define FOR_ITER_GEN 65 +#define BB_TEST_ITER_LIST 66 +#define BB_TEST_ITER_TUPLE 67 +#define BB_TEST_ITER_RANGE 70 +#define BB_TEST_ITER_GEN 72 +#define LOAD_ATTR_CLASS 73 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 76 +#define LOAD_ATTR_INSTANCE_VALUE 77 +#define LOAD_ATTR_MODULE 78 +#define LOAD_ATTR_PROPERTY 79 +#define LOAD_ATTR_SLOT 80 +#define LOAD_ATTR_WITH_HINT 81 +#define LOAD_ATTR_METHOD_LAZY_DICT 82 +#define LOAD_ATTR_METHOD_NO_DICT 84 +#define LOAD_ATTR_METHOD_WITH_VALUES 86 +#define LOAD_CONST__LOAD_FAST 87 +#define LOAD_FAST__LOAD_CONST 88 +#define LOAD_FAST__LOAD_FAST 113 +#define LOAD_GLOBAL_BUILTIN 143 +#define LOAD_GLOBAL_MODULE 153 +#define STORE_ATTR_INSTANCE_VALUE 154 +#define STORE_ATTR_SLOT 158 +#define STORE_ATTR_WITH_HINT 159 +#define STORE_FAST__LOAD_FAST 160 +#define STORE_FAST__STORE_FAST 161 +#define STORE_SUBSCR_DICT 166 +#define STORE_SUBSCR_LIST_INT 167 +#define UNPACK_SEQUENCE_LIST 168 +#define UNPACK_SEQUENCE_TUPLE 169 +#define UNPACK_SEQUENCE_TWO_TUPLE 170 +#define SEND_GEN 175 #define DO_TRACING 255 // Tier 2 interpreter ops #define RESUME_QUICK 5 -#define BINARY_OP_ADD_FLOAT 6 -#define BINARY_OP_ADD_INT 7 -#define BINARY_OP_ADD_UNICODE 8 -#define BINARY_OP_INPLACE_ADD_UNICODE 10 -#define BINARY_OP_MULTIPLY_FLOAT 13 -#define BINARY_OP_MULTIPLY_INT 14 -#define BINARY_OP_SUBTRACT_FLOAT 16 -#define BINARY_OP_SUBTRACT_INT 17 -#define BINARY_SUBSCR_DICT 18 -#define BINARY_SUBSCR_GETITEM 19 -#define BINARY_SUBSCR_LIST_INT 20 -#define BINARY_SUBSCR_TUPLE_INT 21 -#define CALL_PY_EXACT_ARGS 22 -#define CALL_PY_WITH_DEFAULTS 23 -#define CALL_BOUND_METHOD_EXACT_ARGS 24 -#define CALL_BUILTIN_CLASS 28 -#define CALL_BUILTIN_FAST_WITH_KEYWORDS 29 -#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 34 -#define CALL_NO_KW_BUILTIN_FAST 38 -#define CALL_NO_KW_BUILTIN_O 39 -#define CALL_NO_KW_ISINSTANCE 40 -#define CALL_NO_KW_LEN 41 -#define CALL_NO_KW_LIST_APPEND 42 -#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 43 -#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 44 -#define CALL_NO_KW_METHOD_DESCRIPTOR_O 45 -#define CALL_NO_KW_STR_1 46 -#define CALL_NO_KW_TUPLE_1 47 -#define CALL_NO_KW_TYPE_1 48 -#define COMPARE_AND_BRANCH_FLOAT 56 -#define COMPARE_AND_BRANCH_INT 57 -#define COMPARE_AND_BRANCH_STR 58 -#define FOR_ITER_LIST 59 -#define FOR_ITER_TUPLE 62 -#define FOR_ITER_RANGE 63 -#define FOR_ITER_GEN 64 -#define BB_TEST_ITER_LIST 65 -#define BB_TEST_ITER_TUPLE 66 -#define BB_TEST_ITER_RANGE 67 -#define BB_TEST_ITER_GEN 70 -#define LOAD_ATTR_CLASS 72 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 73 -#define LOAD_ATTR_INSTANCE_VALUE 76 -#define LOAD_ATTR_MODULE 77 -#define LOAD_ATTR_PROPERTY 78 -#define LOAD_ATTR_SLOT 79 -#define LOAD_ATTR_WITH_HINT 80 -#define LOAD_ATTR_METHOD_LAZY_DICT 81 -#define LOAD_ATTR_METHOD_NO_DICT 82 -#define LOAD_ATTR_METHOD_WITH_VALUES 84 -#define LOAD_CONST__LOAD_FAST 86 -#define LOAD_FAST__LOAD_CONST 87 -#define LOAD_FAST__LOAD_FAST 88 -#define LOAD_GLOBAL_BUILTIN 113 -#define LOAD_GLOBAL_MODULE 143 -#define STORE_ATTR_INSTANCE_VALUE 153 -#define STORE_ATTR_SLOT 154 -#define STORE_ATTR_WITH_HINT 158 -#define STORE_FAST__LOAD_FAST 159 -#define STORE_FAST__STORE_FAST 160 -#define STORE_SUBSCR_DICT 161 -#define STORE_SUBSCR_LIST_INT 166 -#define UNPACK_SEQUENCE_LIST 167 -#define UNPACK_SEQUENCE_TUPLE 168 -#define UNPACK_SEQUENCE_TWO_TUPLE 169 -#define SEND_GEN 170 +#define JUMP_BACKWARD_QUICK 6 +#define BINARY_OP_ADD_FLOAT 7 +#define BINARY_OP_ADD_INT 8 +#define BINARY_OP_ADD_UNICODE 10 +#define BINARY_OP_INPLACE_ADD_UNICODE 13 +#define BINARY_OP_MULTIPLY_FLOAT 14 +#define BINARY_OP_MULTIPLY_INT 16 +#define BINARY_OP_SUBTRACT_FLOAT 17 +#define BINARY_OP_SUBTRACT_INT 18 +#define BINARY_SUBSCR_DICT 19 +#define BINARY_SUBSCR_GETITEM 20 +#define BINARY_SUBSCR_LIST_INT 21 +#define BINARY_SUBSCR_TUPLE_INT 22 +#define CALL_PY_EXACT_ARGS 23 +#define CALL_PY_WITH_DEFAULTS 24 +#define CALL_BOUND_METHOD_EXACT_ARGS 28 +#define CALL_BUILTIN_CLASS 29 +#define CALL_BUILTIN_FAST_WITH_KEYWORDS 34 +#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 38 +#define CALL_NO_KW_BUILTIN_FAST 39 +#define CALL_NO_KW_BUILTIN_O 40 +#define CALL_NO_KW_ISINSTANCE 41 +#define CALL_NO_KW_LEN 42 +#define CALL_NO_KW_LIST_APPEND 43 +#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 44 +#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 45 +#define CALL_NO_KW_METHOD_DESCRIPTOR_O 46 +#define CALL_NO_KW_STR_1 47 +#define CALL_NO_KW_TUPLE_1 48 +#define CALL_NO_KW_TYPE_1 56 +#define COMPARE_AND_BRANCH_FLOAT 57 +#define COMPARE_AND_BRANCH_INT 58 +#define COMPARE_AND_BRANCH_STR 59 +#define FOR_ITER_LIST 62 +#define FOR_ITER_TUPLE 63 +#define FOR_ITER_RANGE 64 +#define FOR_ITER_GEN 65 +#define BB_TEST_ITER_LIST 66 +#define BB_TEST_ITER_TUPLE 67 +#define BB_TEST_ITER_RANGE 70 +#define BB_TEST_ITER_GEN 72 +#define LOAD_ATTR_CLASS 73 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 76 +#define LOAD_ATTR_INSTANCE_VALUE 77 +#define LOAD_ATTR_MODULE 78 +#define LOAD_ATTR_PROPERTY 79 +#define LOAD_ATTR_SLOT 80 +#define LOAD_ATTR_WITH_HINT 81 +#define LOAD_ATTR_METHOD_LAZY_DICT 82 +#define LOAD_ATTR_METHOD_NO_DICT 84 +#define LOAD_ATTR_METHOD_WITH_VALUES 86 +#define LOAD_CONST__LOAD_FAST 87 +#define LOAD_FAST__LOAD_CONST 88 +#define LOAD_FAST__LOAD_FAST 113 +#define LOAD_GLOBAL_BUILTIN 143 +#define LOAD_GLOBAL_MODULE 153 +#define STORE_ATTR_INSTANCE_VALUE 154 +#define STORE_ATTR_SLOT 158 +#define STORE_ATTR_WITH_HINT 159 +#define STORE_FAST__LOAD_FAST 160 +#define STORE_FAST__STORE_FAST 161 +#define STORE_SUBSCR_DICT 166 +#define STORE_SUBSCR_LIST_INT 167 +#define UNPACK_SEQUENCE_LIST 168 +#define UNPACK_SEQUENCE_TUPLE 169 +#define UNPACK_SEQUENCE_TWO_TUPLE 170 +#define SEND_GEN 175 #define DO_TRACING 255 -#define BB_BRANCH 175 -#define BB_BRANCH_IF_FLAG_UNSET 176 -#define BB_BRANCH_IF_FLAG_SET 177 -#define BB_JUMP_IF_FLAG_UNSET 178 -#define BB_JUMP_IF_FLAG_SET 179 -#define BB_TEST_ITER 180 -#define BB_TEST_IF_FALSE_OR_POP 181 -#define BB_TEST_IF_TRUE_OR_POP 182 -#define BB_TEST_POP_IF_FALSE 183 -#define BB_TEST_POP_IF_TRUE 184 -#define BB_TEST_POP_IF_NOT_NONE 185 -#define BB_TEST_POP_IF_NONE 186 -#define BB_JUMP_BACKWARD_LAZY 187 -#define BINARY_CHECK_INT 188 -#define BINARY_OP_ADD_INT_REST 189 +#define BB_BRANCH 176 +#define BB_BRANCH_IF_FLAG_UNSET 177 +#define BB_BRANCH_IF_FLAG_SET 178 +#define BB_JUMP_IF_FLAG_UNSET 179 +#define BB_JUMP_IF_FLAG_SET 180 +#define BB_TEST_ITER 181 +#define BB_TEST_IF_FALSE_OR_POP 182 +#define BB_TEST_IF_TRUE_OR_POP 183 +#define BB_TEST_POP_IF_FALSE 184 +#define BB_TEST_POP_IF_TRUE 185 +#define BB_TEST_POP_IF_NOT_NONE 186 +#define BB_TEST_POP_IF_NONE 187 +#define BB_JUMP_BACKWARD_LAZY 188 +#define BINARY_CHECK_INT 189 +#define BINARY_OP_ADD_INT_REST 190 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/opcode.py b/Lib/opcode.py index fb4d55637fdfa1..02e488179f2ff6 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -284,6 +284,9 @@ def pseudo_op(name, op, real_ops): "RESUME": [ "RESUME_QUICK", ], + "JUMP_BACKWARD": [ + "JUMP_BACKWARD_QUICK", + ], "BINARY_OP": [ "BINARY_OP_ADD_FLOAT", "BINARY_OP_ADD_INT", diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index b6f80cfcf910f4..41eaa5030228f9 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -123,7 +123,6 @@ - @@ -618,6 +617,7 @@ + @@ -626,7 +626,8 @@ + - \ No newline at end of file + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 953c269aca1d79..4824510f6ac7a6 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -738,9 +738,6 @@ Include\internal - - Include\internal - diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 316171a08f45f7..7816feb9cb3102 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1899,6 +1899,11 @@ dummy_func( } inst(JUMP_BACKWARD, (--)) { + frame->f_code->_tier2_warmup++; + GO_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); + } + + inst(JUMP_BACKWARD_QUICK, (--)) { assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); CHECK_EVAL_BREAKER(); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 9ff9a718eef8ca..2892b77344b5bc 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2427,6 +2427,12 @@ TARGET(JUMP_BACKWARD) { PREDICTED(JUMP_BACKWARD); + frame->f_code->_tier2_warmup++; + GO_TO_INSTRUCTION(JUMP_BACKWARD_QUICK); + } + + TARGET(JUMP_BACKWARD_QUICK) { + PREDICTED(JUMP_BACKWARD_QUICK); assert(oparg < INSTR_OFFSET()); JUMPBY(-oparg); CHECK_EVAL_BREAKER(); diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 2b2148977635b8..97ad6a9dfe547b 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -244,6 +244,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 0; case JUMP_BACKWARD: return 0; + case JUMP_BACKWARD_QUICK: + return 0; case POP_JUMP_IF_FALSE: return 1; case BB_TEST_POP_IF_FALSE: @@ -628,6 +630,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case JUMP_BACKWARD: return 0; + case JUMP_BACKWARD_QUICK: + return 0; case POP_JUMP_IF_FALSE: return 0; case BB_TEST_POP_IF_FALSE: @@ -901,7 +905,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [IMPORT_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [IMPORT_FROM] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [JUMP_FORWARD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [JUMP_BACKWARD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [JUMP_BACKWARD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [JUMP_BACKWARD_QUICK] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [POP_JUMP_IF_FALSE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [BB_TEST_POP_IF_FALSE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [POP_JUMP_IF_TRUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index c377c673f85cb2..4a815c73acb7db 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -5,16 +5,17 @@ static void *opcode_targets[256] = { &&TARGET_INTERPRETER_EXIT, &&TARGET_END_FOR, &&TARGET_RESUME_QUICK, + &&TARGET_JUMP_BACKWARD_QUICK, &&TARGET_BINARY_OP_ADD_FLOAT, &&TARGET_BINARY_OP_ADD_INT, - &&TARGET_BINARY_OP_ADD_UNICODE, &&TARGET_NOP, - &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, + &&TARGET_BINARY_OP_ADD_UNICODE, &&TARGET_UNARY_NEGATIVE, &&TARGET_UNARY_NOT, + &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, &&TARGET_BINARY_OP_MULTIPLY_FLOAT, - &&TARGET_BINARY_OP_MULTIPLY_INT, &&TARGET_UNARY_INVERT, + &&TARGET_BINARY_OP_MULTIPLY_INT, &&TARGET_BINARY_OP_SUBTRACT_FLOAT, &&TARGET_BINARY_OP_SUBTRACT_INT, &&TARGET_BINARY_SUBSCR_DICT, @@ -23,20 +24,20 @@ static void *opcode_targets[256] = { &&TARGET_BINARY_SUBSCR_TUPLE_INT, &&TARGET_CALL_PY_EXACT_ARGS, &&TARGET_CALL_PY_WITH_DEFAULTS, - &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, &&TARGET_BINARY_SUBSCR, &&TARGET_BINARY_SLICE, &&TARGET_STORE_SLICE, + &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, &&TARGET_CALL_BUILTIN_CLASS, - &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, &&TARGET_GET_LEN, &&TARGET_MATCH_MAPPING, &&TARGET_MATCH_SEQUENCE, &&TARGET_MATCH_KEYS, - &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, + &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, &&TARGET_PUSH_EXC_INFO, &&TARGET_CHECK_EXC_MATCH, &&TARGET_CHECK_EG_MATCH, + &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, &&TARGET_CALL_NO_KW_BUILTIN_FAST, &&TARGET_CALL_NO_KW_BUILTIN_O, &&TARGET_CALL_NO_KW_ISINSTANCE, @@ -47,7 +48,6 @@ static void *opcode_targets[256] = { &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, &&TARGET_CALL_NO_KW_STR_1, &&TARGET_CALL_NO_KW_TUPLE_1, - &&TARGET_CALL_NO_KW_TYPE_1, &&TARGET_WITH_EXCEPT_START, &&TARGET_GET_AITER, &&TARGET_GET_ANEXT, @@ -55,39 +55,39 @@ static void *opcode_targets[256] = { &&TARGET_BEFORE_WITH, &&TARGET_END_ASYNC_FOR, &&TARGET_CLEANUP_THROW, + &&TARGET_CALL_NO_KW_TYPE_1, &&TARGET_COMPARE_AND_BRANCH_FLOAT, &&TARGET_COMPARE_AND_BRANCH_INT, &&TARGET_COMPARE_AND_BRANCH_STR, - &&TARGET_FOR_ITER_LIST, &&TARGET_STORE_SUBSCR, &&TARGET_DELETE_SUBSCR, + &&TARGET_FOR_ITER_LIST, &&TARGET_FOR_ITER_TUPLE, &&TARGET_FOR_ITER_RANGE, &&TARGET_FOR_ITER_GEN, &&TARGET_BB_TEST_ITER_LIST, &&TARGET_BB_TEST_ITER_TUPLE, - &&TARGET_BB_TEST_ITER_RANGE, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, - &&TARGET_BB_TEST_ITER_GEN, + &&TARGET_BB_TEST_ITER_RANGE, &&TARGET_LOAD_BUILD_CLASS, + &&TARGET_BB_TEST_ITER_GEN, &&TARGET_LOAD_ATTR_CLASS, - &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, &&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_RETURN_GENERATOR, + &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_ATTR_MODULE, &&TARGET_LOAD_ATTR_PROPERTY, &&TARGET_LOAD_ATTR_SLOT, &&TARGET_LOAD_ATTR_WITH_HINT, &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, - &&TARGET_LOAD_ATTR_METHOD_NO_DICT, &&TARGET_RETURN_VALUE, - &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, + &&TARGET_LOAD_ATTR_METHOD_NO_DICT, &&TARGET_SETUP_ANNOTATIONS, + &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_LOAD_FAST__LOAD_CONST, - &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_POP_EXCEPT, &&TARGET_STORE_NAME, &&TARGET_DELETE_NAME, @@ -112,7 +112,7 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_FORWARD, &&TARGET_JUMP_IF_FALSE_OR_POP, &&TARGET_JUMP_IF_TRUE_OR_POP, - &&TARGET_LOAD_GLOBAL_BUILTIN, + &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -142,7 +142,7 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_BACKWARD, &&TARGET_COMPARE_AND_BRANCH, &&TARGET_CALL_FUNCTION_EX, - &&TARGET_LOAD_GLOBAL_MODULE, + &&TARGET_LOAD_GLOBAL_BUILTIN, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,29 +152,29 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, + &&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_STORE_ATTR_INSTANCE_VALUE, - &&TARGET_STORE_ATTR_SLOT, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, + &&TARGET_STORE_ATTR_SLOT, &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_STORE_FAST__STORE_FAST, - &&TARGET_STORE_SUBSCR_DICT, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, + &&TARGET_STORE_SUBSCR_DICT, &&TARGET_STORE_SUBSCR_LIST_INT, &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, - &&TARGET_SEND_GEN, &&TARGET_CALL, &&TARGET_KW_NAMES, &&TARGET_CALL_INTRINSIC_1, &&TARGET_CALL_INTRINSIC_2, - &&_unknown_opcode, + &&TARGET_SEND_GEN, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, diff --git a/Python/specialize.c b/Python/specialize.c index b236a06af6bc64..4ede3122d38046 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -9,7 +9,6 @@ #include "pycore_opcode.h" // _PyOpcode_Caches #include "structmember.h" // struct PyMemberDef, T_OFFSET_EX #include "pycore_descrobject.h" -#include "pycore_opcode_macro_to_micro.h" #include // rand() diff --git a/Python/tier2.c b/Python/tier2.c index 44f6cb858698d6..767d7e5bb98263 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -202,6 +202,7 @@ IS_JREL_OPCODE(int opcode) case SEND: case POP_JUMP_IF_NOT_NONE: case POP_JUMP_IF_NONE: + case JUMP_BACKWARD_QUICK: case JUMP_BACKWARD_NO_INTERRUPT: case JUMP_BACKWARD: return 1; @@ -214,7 +215,9 @@ IS_JREL_OPCODE(int opcode) static inline int IS_JUMP_BACKWARDS_OPCODE(int opcode) { - return opcode == JUMP_BACKWARD_NO_INTERRUPT || opcode == JUMP_BACKWARD; + return opcode == JUMP_BACKWARD_NO_INTERRUPT || + opcode == JUMP_BACKWARD || + opcode == JUMP_BACKWARD_QUICK; } @@ -390,6 +393,7 @@ emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) int oparg = _Py_OPARG(branch); // @TODO handle JUMP_BACKWARDS and JUMP_BACKWARDS_NO_INTERRUPT switch (_PyOpcode_Deopt[_Py_OPCODE(branch)]) { + case JUMP_BACKWARD_QUICK: case JUMP_BACKWARD: // The initial backwards jump needs to find the right basic block. // Subsequent jumps don't need to check this anymore. They can just @@ -608,7 +612,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, int n_typecontext, PyTypeObject **type_context) { #define END() goto end; -#define JUMPBY(x) i += x + 1; continue; +#define JUMPBY(x) i += x + 1; #define BASIC_PUSH(v) (*stack_pointer++ = (v)) #define BASIC_POP() (*--stack_pointer) #define DISPATCH() write_i = emit_i(write_i, opcode, oparg); \ @@ -664,15 +668,15 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, case RESUME: opcode = RESUME_QUICK; DISPATCH(); - case EXTENDED_ARG: - write_i = emit_i(write_i, EXTENDED_ARG, _Py_OPARG(*curr)); - curr++; - next_instr++; - i++; - oparg = oparg << 8 | _Py_OPARG(*curr); - opcode = _Py_OPCODE(*curr); - caches = _PyOpcode_Caches[opcode]; - DISPATCH_GOTO(); + //case EXTENDED_ARG: + // write_i = emit_i(write_i, EXTENDED_ARG, _Py_OPARG(*curr)); + // curr++; + // next_instr++; + // i++; + // oparg = oparg << 8 | _Py_OPARG(*curr); + // opcode = _Py_OPCODE(*curr); + // caches = _PyOpcode_Caches[opcode]; + // DISPATCH_GOTO(); // We need to rewrite the pseudo-branch instruction. case COMPARE_AND_BRANCH: opcode = COMPARE_OP; @@ -684,57 +688,18 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // So we tell the BB to skip over it. t2_start++; DISPATCH(); - // FOR_ITER must be handled separately from other opcodes as it has - // CACHE entries following it. - //case LOAD_FAST: - // BASIC_PUSH(type_context[oparg]); - // DISPATCH(); - //case LOAD_NAME: - // BASIC_PUSH(NULL); - // DISPATCH(); - //case LOAD_CONST: { - // PyTypeObject *cont = Py_TYPE(PyTuple_GET_ITEM(co->co_consts, oparg)); - // BASIC_PUSH(cont); - // DISPATCH(); - //} - //case STORE_FAST: { - // type_context[oparg] = BASIC_POP(); - // DISPATCH(); - //} - //case STORE_NAME: - // BASIC_POP(); - // DISPATCH(); - //case BINARY_OP: { - // PyTypeObject *res = BINARY_OP_RESULT_TYPE(co, curr, n_typecontext, type_context, - // &how_many_guards, &guard_instr, &action); - // // We need a guard. So this is the end of the basic block. - // // @TODO in the future, support multiple guards. - // if (how_many_guards > 0) { - // // Emit the guard - // emit_type_guard(&write_i, guard_instr); - // END(); - // } - // else { - // BASIC_PUSH(res); - // // Don't need a guard, either is a micro op, or is a generic instruction - // // No type information known. Use a generic instruction. - // if (res == NULL) { - // DISPATCH(); - // } - // else { - // emit_i(&write_i, _Py_OPCODE(action), 0); - // break; - // } - // } - //} default: fprintf(stderr, "offset: %Id\n", curr - _PyCode_CODE(co)); if (IS_BACKWARDS_JUMP_TARGET(co, curr)) { +#if BB_DEBUG fprintf(stderr, "Encountered a backward jump target\n"); +#endif // This should be the end of another basic block, or the start of a new. // Start of a new basic block, just ignore and continue. if (virtual_start) { +#if BB_DEBUG fprintf(stderr, "Emitted virtual start of basic block\n"); +#endif starts_with_backwards_jump_target = true; backwards_jump_target_offset = curr - _PyCode_CODE(co); virtual_start = false; @@ -771,6 +736,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, if (opcode == JUMP_FORWARD) { // JUMP offset (oparg) + current instruction + cache entries JUMPBY(oparg); + continue; } // Get the BB ID without incrementing it. // AllocateBBMetaData will increment. @@ -851,23 +817,13 @@ static int _PyCode_Tier2FillJumpTargets(PyCodeObject *co) { assert(co->_tier2_info != NULL); - // Remove all the RESUME instructions. - // Count all the jump targets. + // Count all the backwards jump targets. Py_ssize_t backwards_jump_count = 0; for (Py_ssize_t i = 0; i < Py_SIZE(co); i++) { _Py_CODEUNIT *instr_ptr = _PyCode_CODE(co) + i; _Py_CODEUNIT instr = *instr_ptr; int opcode = _PyOpcode_Deopt[_Py_OPCODE(instr)]; - int oparg = _Py_OPARG(instr); - switch (opcode) { - case RESUME: - _py_set_opcode(instr_ptr, RESUME_QUICK); - break; - default: - // We want to track all guard instructions as - // jumps too. - backwards_jump_count += IS_JUMP_BACKWARDS_OPCODE(opcode); // + INSTR_HAS_GUARD(instr); - } + backwards_jump_count += IS_JUMP_BACKWARDS_OPCODE(opcode); i += _PyOpcode_Caches[opcode]; } @@ -908,7 +864,9 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) if (IS_JUMP_BACKWARDS_OPCODE(opcode)) { // + 1 because it's calculated from nextinstr (see JUMPBY in ceval.c) _Py_CODEUNIT *target = curr + 1 - oparg; +#if BB_DEBUG fprintf(stderr, "jump target opcode is %d\n", _Py_OPCODE(*target)); +#endif // (in terms of offset from start of co_code_adaptive) backward_jump_offsets[curr_i] = (int)(target - start); curr_i++; @@ -999,6 +957,26 @@ IS_OPTIMIZABLE_OPCODE(int opcode, int oparg) } } +static inline void +replace_resume_and_jump_backwards(PyCodeObject *co) +{ + for (Py_ssize_t i = 0; i < Py_SIZE(co); i++) { + _Py_CODEUNIT *instr_ptr = _PyCode_CODE(co) + i; + _Py_CODEUNIT instr = *instr_ptr; + int opcode = _PyOpcode_Deopt[_Py_OPCODE(instr)]; + int oparg = _Py_OPARG(instr); + switch (opcode) { + case RESUME: + _py_set_opcode(instr_ptr, RESUME_QUICK); + break; + case JUMP_BACKWARD: + _py_set_opcode(instr_ptr, JUMP_BACKWARD_QUICK); + break; + } + i += _PyOpcode_Caches[opcode]; + } +} + // 1. Initialize whatever we need. // 2. Create the entry BB. // 3. Jump into that BB. @@ -1006,13 +984,14 @@ static _Py_CODEUNIT * _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) { assert(_Py_OPCODE(*(next_instr - 1)) == RESUME); - - // First check for forbidden opcodes that we currently can't handle. PyCodeObject *co = frame->f_code; + // Replace all the RESUME and JUMP_BACKWARDS so that it doesn't waste time again. + replace_resume_and_jump_backwards(co); // Impossibly big. if ((int)Py_SIZE(co) != Py_SIZE(co)) { return NULL; } + // First check for forbidden opcodes that we currently can't handle. int optimizable = 0; for (Py_ssize_t curr = 0; curr < Py_SIZE(co); curr++) { _Py_CODEUNIT *curr_instr = _PyCode_CODE(co) + curr; @@ -1094,7 +1073,8 @@ _PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) PyCodeObject *code = frame->f_code; if (code->_tier2_warmup != 0) { code->_tier2_warmup++; - if (code->_tier2_warmup == 0) { + if (code->_tier2_warmup >= 0) { + assert(code->_tier2_info == NULL); // If it fails, due to lack of memory or whatever, // just fall back to the tier 1 interpreter. _Py_CODEUNIT *next = _PyCode_Tier2Initialize(frame, next_instr); @@ -1173,12 +1153,18 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id, int j int jump_offset = (int)(tier1_jump_target - _PyCode_CODE(co)); int matching_bb_id = -1; +#if BB_DEBUG fprintf(stderr, "finding jump target: %d\n", jump_offset); +#endif for (int i = 0; i < t2_info->backward_jump_count; i++) { +#if BB_DEBUG fprintf(stderr, "jump offset checked: %d\n", t2_info->backward_jump_offsets[i]); +#endif if (t2_info->backward_jump_offsets[i] == jump_offset) { for (int x = 0; x < MAX_BB_VERSIONS; x++) { +#if BB_DEBUG fprintf(stderr, "jump target BB ID: %d\n", +#endif t2_info->backward_jump_target_bb_ids[i][x]); // @TODO, this is where the diff function is supposed to be // it will calculate the closest type context BB @@ -1290,7 +1276,7 @@ _PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *tar _py_set_opcode(write_curr, NOP); write_curr++; } - _py_set_opcode(write_curr, JUMP_BACKWARD); + _py_set_opcode(write_curr, JUMP_BACKWARD_QUICK); write_curr->oparg = oparg & 0xFF; write_curr++; _py_set_opcode(write_curr, END_FOR); diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 71bfa55e38aa6f..8703d7a0ea1ae5 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -1338,8 +1338,8 @@ def main(): sys.exit(f"Found {a.errors} errors") a.write_instructions() # Raises OSError if output can't be written a.write_metadata() - a.output_filename = TIER2_MACRO_TO_MICRO_MAP_OUTPUT - a.write_macromap_and_typedata() + # a.output_filename = TIER2_MACRO_TO_MICRO_MAP_OUTPUT + # a.write_macromap_and_typedata() if __name__ == "__main__": From 10e8eb2983dd47351723d32c8d7780f853d04ed0 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 24 Feb 2023 23:42:11 +0800 Subject: [PATCH 038/280] Fix jump calculation for FOR_ITER --- Python/tier2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Python/tier2.c b/Python/tier2.c index 767d7e5bb98263..7bc75e1f38ad79 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -461,7 +461,9 @@ emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) // The oparg of FOR_ITER is a little special, the actual jump has to jump over // its own cache entries, the oparg, -1 to tell it to start generating from the // END_FOR. However, at runtime, we will skip this END_FOR. - oparg = INLINE_CACHE_ENTRIES_FOR_ITER + oparg - 1; + // NOTE: IF YOU CHANGE ANY OF THE INSTRUCTIONS BELOW, MAKE SURE + // TO UPDATE THE CALCULATION OF OPARG. THIS IS EXTREMELY IMPORTANT. + oparg = INLINE_CACHE_ENTRIES_FOR_ITER + oparg; _py_set_opcode(write_curr, BB_TEST_ITER); write_curr->oparg = oparg; write_curr++; From e1a5b61d1563b9449786380475111418b85b9491 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 25 Feb 2023 00:04:31 +0800 Subject: [PATCH 039/280] Make compatible with main --- Python/tier2.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index 7bc75e1f38ad79..0da0a7f6be37ef 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -339,7 +339,7 @@ BINARY_OP_RESULT_TYPE(PyCodeObject *co, _Py_CODEUNIT *instr, int n_typecontext, if (lhs_type == &PyLong_Type) { if (rhs_type == &PyLong_Type) { *how_many_guards = 0; - action->opcode = BINARY_OP_ADD_INT_REST; + action->op.code = BINARY_OP_ADD_INT_REST; return &PyLong_Type; } //// Right side unknown. Emit single check. @@ -376,7 +376,7 @@ emit_type_guard(_Py_CODEUNIT *write_curr, _Py_CODEUNIT guard, int bb_id) //write_curr->oparg = 0; //write_curr++; _py_set_opcode(write_curr, BB_BRANCH); - write_curr->oparg = 0; + write_curr->op.arg = 0; write_curr++; _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_BB_BRANCH); @@ -439,12 +439,12 @@ emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) #endif // Just in case _py_set_opcode(write_curr, EXTENDED_ARG); - write_curr->oparg = 0; + write_curr->op.arg = 0; write_curr++; // We don't need to recalculate the backward jump, because that only needs to be done // when it locates the next BB in JUMP_BACKWARD_LAZY. _py_set_opcode(write_curr, BB_JUMP_BACKWARD_LAZY); - write_curr->oparg = oparg; + write_curr->op.arg = oparg; write_curr++; _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_BB_BRANCH); @@ -465,11 +465,11 @@ emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) // TO UPDATE THE CALCULATION OF OPARG. THIS IS EXTREMELY IMPORTANT. oparg = INLINE_CACHE_ENTRIES_FOR_ITER + oparg; _py_set_opcode(write_curr, BB_TEST_ITER); - write_curr->oparg = oparg; + write_curr->op.arg = oparg; write_curr++; write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_FOR_ITER); _py_set_opcode(write_curr, BB_BRANCH); - write_curr->oparg = oparg; + write_curr->op.arg = oparg; write_curr++; _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_BB_BRANCH); @@ -484,10 +484,10 @@ emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) #endif //_Py_CODEUNIT *start = write_curr; _py_set_opcode(write_curr, opcode); - write_curr->oparg = oparg; + write_curr->op.arg = oparg; write_curr++; _py_set_opcode(write_curr, BB_BRANCH); - write_curr->oparg = oparg & 0xFF; + write_curr->op.arg = oparg & 0xFF; write_curr++; _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_BB_BRANCH); @@ -526,7 +526,7 @@ static inline _Py_CODEUNIT * emit_i(_Py_CODEUNIT *write_curr, int opcode, int oparg) { _py_set_opcode(write_curr, opcode); - write_curr->oparg = oparg; + write_curr->op.arg = oparg; write_curr++; return write_curr; } @@ -1221,14 +1221,14 @@ _PyTier2_RewriteForwardJump(_Py_CODEUNIT *bb_branch, _Py_CODEUNIT *target) assert(oparg <= 0xFFFF); if (requires_extended) { _py_set_opcode(write_curr, EXTENDED_ARG); - write_curr->oparg = (oparg >> 8) & 0xFF; + write_curr->op.arg = (oparg >> 8) & 0xFF; write_curr++; // -1 to oparg because now the jump instruction moves one unit forward. oparg--; } _py_set_opcode(write_curr, branch == BB_BRANCH_IF_FLAG_SET ? BB_JUMP_IF_FLAG_SET : BB_JUMP_IF_FLAG_UNSET); - write_curr->oparg = oparg & 0xFF; + write_curr->op.arg = oparg & 0xFF; write_curr++; if (!requires_extended) { _py_set_opcode(write_curr, NOP); @@ -1271,7 +1271,7 @@ _PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *tar bool requires_extended = oparg > 0xFF; if (requires_extended) { _py_set_opcode(write_curr, EXTENDED_ARG); - write_curr->oparg = (oparg >> 8) & 0xFF; + write_curr->op.arg = (oparg >> 8) & 0xFF; write_curr++; } else { @@ -1279,7 +1279,7 @@ _PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *tar write_curr++; } _py_set_opcode(write_curr, JUMP_BACKWARD_QUICK); - write_curr->oparg = oparg & 0xFF; + write_curr->op.arg = oparg & 0xFF; write_curr++; _py_set_opcode(write_curr, END_FOR); write_curr++; From 28158ff4cc5c6900d17f4c0ad7efbaa71375fe3c Mon Sep 17 00:00:00 2001 From: Julia Date: Sat, 25 Feb 2023 13:31:52 +0800 Subject: [PATCH 040/280] refactor: generate_cases.py don't emit 0-length array --- Include/internal/pycore_opcode_macro_to_micro.h | 2 -- Tools/cases_generator/generate_cases.py | 10 +++++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Include/internal/pycore_opcode_macro_to_micro.h b/Include/internal/pycore_opcode_macro_to_micro.h index b33b88b838099b..4f120781d01037 100644 --- a/Include/internal/pycore_opcode_macro_to_micro.h +++ b/Include/internal/pycore_opcode_macro_to_micro.h @@ -199,8 +199,6 @@ extern const int _Py_MacroOpUOpCount[] = { extern const int _Py_MacroOpToUOp[][1] = { [BINARY_OP_ADD_INT] = {BINARY_OP_ADD_INT_REST}, }; -extern const PyTypeObject *_Py_UOpGuardTypes[][0] = { -}; #ifdef __cplusplus } #endif diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 71bfa55e38aa6f..ac806a2d77a5e0 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -1012,11 +1012,11 @@ def write_uopguard_typedata(self): if types: max_types = max(max_types, len(types)) uop_to_type_output[instr_def.name] = types - - self.out.emit(f"extern const PyTypeObject *_Py_UOpGuardTypes[][{max_types}] = {{") - for name, types in uop_to_type_output.items(): - self.out.emit(f"[{name}] = {{{', '.join(['&' + type_ for type_ in types])}}},") - self.out.emit("};") + if max_types > 0: + self.out.emit(f"extern const PyTypeObject *_Py_UOpGuardTypes[][{max_types}] = {{") + for name, types in uop_to_type_output.items(): + self.out.emit(f"[{name}] = {{{', '.join(['&' + type_ for type_ in types])}}},") + self.out.emit("};") def write_metadata(self) -> None: From c5bd72135165bf4ed87e5af6755e24c9df4bac1a Mon Sep 17 00:00:00 2001 From: Julia Date: Sat, 25 Feb 2023 13:32:53 +0800 Subject: [PATCH 041/280] refactor: make type_context explicit as a struct in preparation for implementing the types meta-interpreter --- Include/cpython/code.h | 22 +++++-- Objects/codeobject.c | 5 +- Python/tier2.c | 133 +++++++++++++++++++++++++++-------------- 3 files changed, 105 insertions(+), 55 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 3e413c618d5eb0..1b91a8b514124b 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -42,18 +42,22 @@ typedef struct { PyObject *_co_freevars; } _PyCoCached; +// Tier 2 types meta interpreter +typedef struct _PyTier2TypeContext { + int type_locals_len; + int type_stack_len; + PyTypeObject** type_stack; + PyTypeObject** type_locals; +} _PyTier2TypeContext; + // Tier 2 interpreter information typedef struct _PyTier2BBMetadata { // Index into _PyTier2Info->bb_data int id; - // Array of types. This corresponds to the fast locals array. - int type_context_len; - PyTypeObject **type_context; + _PyTier2TypeContext *type_context; _Py_CODEUNIT *tier2_start; // Note, this is the first tier 1 instruction to execute AFTER the BB ends. _Py_CODEUNIT *tier1_end; - // Type stack state - PyTypeObject **types_stack; } _PyTier2BBMetadata; // Bump allocator for basic blocks (overallocated) @@ -83,13 +87,19 @@ typedef struct _PyTier2Info { // will have [[BB_ID1, BB_ID2], [BB_ID3,], [], []] // etc. int **backward_jump_target_bb_ids; - PyTypeObject **types_stack; // Max len of bb_data int bb_data_len; // Current index to write into in bb_data. Incremented after each write. // This also assigns the BB ID. int bb_data_curr; _PyTier2BBMetadata **bb_data; + + // @TODO: + // Potentially optimise _PyTier2TypeContext by allocating the stacksize + // to the size needed for the snapshot, and the type propagation is performed + // on type_metainterpreter_stack_scratch which is allocated only once per + // code object. + // PyTypeObject** type_metainterpreter_stack_scratch; } _PyTier2Info; // To avoid repeating ourselves in deepfreeze.py, all PyCodeObject members are diff --git a/Objects/codeobject.c b/Objects/codeobject.c index d9259cff23a2d9..22705442b43abc 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1690,10 +1690,7 @@ code_tier2_fini(PyCodeObject *co) PyMem_Free(t2_info->backward_jump_offsets); t2_info->backward_jump_offsets = NULL; } - if (t2_info->types_stack != NULL) { - PyMem_Free(t2_info->types_stack); - t2_info->types_stack = NULL; - } + t2_info->backward_jump_count = 0; if (t2_info->bb_data != NULL && t2_info->bb_data_len > 0) { PyMem_Free(t2_info->bb_data); diff --git a/Python/tier2.c b/Python/tier2.c index 44f6cb858698d6..a6ce08ae26f52a 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -19,21 +19,78 @@ static inline int IS_SCOPE_EXIT_OPCODE(int opcode); ////////// TYPE CONTEXT FUNCTIONS -static PyTypeObject ** -initialize_type_context(PyCodeObject *co, int *type_context_len) { +static _PyTier2TypeContext * +initialize_type_context(const PyCodeObject *co) { + int nlocals = co->co_nlocals; - PyTypeObject **type_context = PyMem_Malloc(nlocals * sizeof(PyTypeObject *)); - if (type_context == NULL) { + int nstack = co->co_stacksize; + + PyTypeObject **type_locals = PyMem_Malloc(nlocals * sizeof(PyTypeObject *)); + if (type_locals == NULL) { + return NULL; + } + PyTypeObject **type_stack = PyMem_Malloc(nstack * sizeof(PyTypeObject *)); + if (type_stack == NULL) { + PyMem_Free(type_locals); return NULL; } - // Initialize to uknown type. - for (int i = 0; i < nlocals; i++) { - type_context[i] = NULL; + + // Initialize to unknown type. + for (int i = 0; i < nlocals; i++) type_locals[i] = NULL; + for (int i = 0; i < nstack; i++) type_stack[i] = NULL; + + _PyTier2TypeContext *type_context = PyMem_Malloc(sizeof(_PyTier2TypeContext)); + if (type_context == NULL) { + PyMem_Free(type_locals); + PyMem_Free(type_stack); + return NULL; } - *type_context_len = nlocals; + type_context->type_locals_len = nlocals; + type_context->type_stack_len = nstack; + type_context->type_locals = type_locals; + type_context->type_stack = type_stack; return type_context; } +static _PyTier2TypeContext * +_PyTier2TypeContext_copy(const _PyTier2TypeContext* type_context) { + + int nlocals = type_context->type_locals_len; + int nstack = type_context->type_stack_len; + + PyTypeObject** type_locals = PyMem_Malloc(nlocals * sizeof(PyTypeObject*)); + if (type_locals == NULL) { + return NULL; + } + PyTypeObject** type_stack = PyMem_Malloc(nstack * sizeof(PyTypeObject*)); + if (type_stack == NULL) { + PyMem_Free(type_locals); + return NULL; + } + + memcpy(type_locals, type_context->type_locals, nlocals * sizeof(PyTypeObject*)); + memcpy(type_stack, type_context->type_stack, nstack * sizeof(PyTypeObject*)); + + _PyTier2TypeContext* new_type_context = PyMem_Malloc(sizeof(_PyTier2TypeContext)); + if (new_type_context == NULL) { + PyMem_Free(type_locals); + PyMem_Free(type_stack); + return NULL; + } + new_type_context->type_locals_len = nlocals; + new_type_context->type_stack_len = nstack; + new_type_context->type_locals = type_locals; + new_type_context->type_stack = type_stack; + return new_type_context; +} + +static void +_PyTier2TypeContext_free(_PyTier2TypeContext* type_context) { + PyMem_Free(type_context->type_locals); + PyMem_Free(type_context->type_stack); + PyMem_Free(type_context); +} + ////////// Utility functions // Gets end of the bytecode for a code object. @@ -108,18 +165,18 @@ _PyTier2_BBSpaceCheckAndReallocIfNeeded(PyCodeObject *co, Py_ssize_t space_reque static _PyTier2BBMetadata * allocate_bb_metadata(PyCodeObject *co, _Py_CODEUNIT *tier2_start, - _Py_CODEUNIT *tier1_end, int type_context_len, - PyTypeObject **type_context) + _Py_CODEUNIT *tier1_end, + _PyTier2TypeContext *type_context) { _PyTier2BBMetadata *metadata = PyMem_Malloc(sizeof(_PyTier2BBMetadata)); if (metadata == NULL) { return NULL; + } metadata->tier2_start = tier2_start; metadata->tier1_end = tier1_end; metadata->type_context = type_context; - metadata->type_context_len = type_context_len; return metadata; } @@ -161,11 +218,11 @@ write_bb_metadata(PyCodeObject *co, _PyTier2BBMetadata *metadata) static _PyTier2BBMetadata * _PyTier2_AllocateBBMetaData(PyCodeObject *co, _Py_CODEUNIT *tier2_start, - _Py_CODEUNIT *tier1_end, int type_context_len, - PyTypeObject **type_context) + _Py_CODEUNIT *tier1_end, + _PyTier2TypeContext *type_context) { _PyTier2BBMetadata *meta = allocate_bb_metadata(co, - tier2_start, tier1_end, type_context_len, type_context); + tier2_start, tier1_end, type_context); if (meta == NULL) { return NULL; } @@ -605,7 +662,8 @@ add_metadata_to_jump_2d_array(_PyTier2Info *t2_info, _PyTier2BBMetadata *meta, _PyTier2BBMetadata * _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, _Py_CODEUNIT *tier1_start, - int n_typecontext, PyTypeObject **type_context) + // Const qualifier as this function makes a copy of the type_context + const _PyTier2TypeContext *type_context) { #define END() goto end; #define JUMPBY(x) i += x + 1; continue; @@ -624,11 +682,10 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // 2. If there's a type guard. // Make a copy of the type context - PyTypeObject **type_context_copy = PyMem_Malloc(n_typecontext * sizeof(PyTypeObject *)); + _PyTier2TypeContext *type_context_copy = _PyTier2TypeContext_copy(type_context); if (type_context_copy == NULL) { return NULL; } - memcpy(type_context_copy, type_context, n_typecontext * sizeof(PyTypeObject *)); _PyTier2BBMetadata *meta = NULL; _PyTier2BBMetadata *temp_meta = NULL; @@ -636,7 +693,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, _PyTier2Info *t2_info = co->_tier2_info; _Py_CODEUNIT *t2_start = (_Py_CODEUNIT *)(((char *)bb_space->u_code) + bb_space->water_level); _Py_CODEUNIT *write_i = t2_start; - PyTypeObject **stack_pointer = co->_tier2_info->types_stack; + PyTypeObject **stack_pointer = type_context_copy->type_stack; int tos = -1; // For handling of backwards jumps @@ -655,9 +712,9 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // Just because an instruction requires a guard doesn't mean it's the end of a BB. // We need to check whether we can eliminate the guard based on the current type context. - int how_many_guards = 0; - _Py_CODEUNIT guard_instr; - _Py_CODEUNIT action; + // int how_many_guards = 0; + // _Py_CODEUNIT guard_instr; + // _Py_CODEUNIT action; dispatch_opcode: switch (opcode) { @@ -744,7 +801,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // But generate the block after that so it can fall through. i--; meta = _PyTier2_AllocateBBMetaData(co, - t2_start, _PyCode_CODE(co) + i, n_typecontext, type_context_copy); + t2_start, _PyCode_CODE(co) + i, type_context_copy); if (meta == NULL) { PyMem_Free(type_context_copy); return NULL; @@ -787,7 +844,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // Create the tier 2 BB temp_meta = _PyTier2_AllocateBBMetaData(co, t2_start, // + 1 because we want to start with the NEXT instruction for the scan - _PyCode_CODE(co) + i + 1, n_typecontext, type_context_copy); + _PyCode_CODE(co) + i + 1, type_context_copy); // We need to return the first block to enter into. If there is already a block generated // before us, then we use that instead of the most recent block. if (meta == NULL) { @@ -943,13 +1000,6 @@ _PyTier2Info_Initialize(PyCodeObject *co) return NULL; } - // Next is to intitialize stack space for the tier 2 types meta-interpretr. - PyTypeObject **types_stack = PyMem_Malloc(co->co_stacksize * sizeof(PyObject *)); - if (types_stack == NULL) { - PyMem_Free(t2_info); - return NULL; - } - t2_info->types_stack = types_stack; t2_info->backward_jump_count = 0; t2_info->backward_jump_offsets = NULL; @@ -962,7 +1012,6 @@ _PyTier2Info_Initialize(PyCodeObject *co) _PyTier2BBMetadata **bb_data = PyMem_Malloc(bb_data_len * sizeof(_PyTier2Info *)); if (bb_data == NULL) { PyMem_Free(t2_info); - PyMem_Free(types_stack); return NULL; } t2_info->bb_data_len = (int)bb_data_len; @@ -1054,14 +1103,13 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) t2_info->_bb_space = bb_space; - int type_context_len = 0; - PyTypeObject **type_context = initialize_type_context(co, &type_context_len); + _PyTier2TypeContext *type_context = initialize_type_context(co); if (type_context == NULL) { goto cleanup; } _PyTier2BBMetadata *meta = _PyTier2_Code_DetectAndEmitBB( co, bb_space, - _PyCode_CODE(co), type_context_len, type_context); + _PyCode_CODE(co), type_context); if (meta == NULL) { PyMem_Free(type_context); goto cleanup; @@ -1128,13 +1176,10 @@ _PyTier2_GenerateNextBB(_PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, // DEOPTIMIZE TO TIER 1? return NULL; } - int type_context_len = 0; - PyTypeObject **type_context = initialize_type_context(frame->f_code, &type_context_len); - if (type_context == NULL) { - return NULL; - } + // Get type_context of previous BB + _PyTier2TypeContext *type_context = meta->type_context; _PyTier2BBMetadata *metadata = _PyTier2_Code_DetectAndEmitBB( - frame->f_code, space, tier1_end, type_context_len, + frame->f_code, space, tier1_end, type_context); if (metadata == NULL) { PyMem_Free(type_context); @@ -1163,11 +1208,9 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id, int j // DEOPTIMIZE TO TIER 1? return NULL; } - int type_context_len = 0; - PyTypeObject **type_context = initialize_type_context(frame->f_code, &type_context_len); - if (type_context == NULL) { - return NULL; - } + + // Get type_context of previous BB + _PyTier2TypeContext* type_context = meta->type_context; // Now, find the matching BB _PyTier2Info *t2_info = co->_tier2_info; int jump_offset = (int)(tier1_jump_target - _PyCode_CODE(co)); From ce57e6abd0b9d8c9da44c9b8805e509432863fa1 Mon Sep 17 00:00:00 2001 From: Julia Date: Sun, 26 Feb 2023 01:01:35 +0800 Subject: [PATCH 042/280] fix: memory handling of type_context --- Objects/codeobject.c | 5 +++++ Python/tier2.c | 10 ++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 19e6c8bdb576ba..089139073a4d7e 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1672,6 +1672,11 @@ code_tier2_fini(PyCodeObject *co) if (co->_tier2_info == NULL) { return; } + // @TODO: + // Write a proper destructor for _PyTier2Info + // and it's children structures. + // Current implementation e.g., doesn't clear + // bb_data _PyTier2Info *t2_info = co->_tier2_info; t2_info->_entry_bb = NULL; if (t2_info->_bb_space != NULL) { diff --git a/Python/tier2.c b/Python/tier2.c index 3fc76e12bb98c4..7d47db12c8bbb9 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -770,7 +770,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, meta = _PyTier2_AllocateBBMetaData(co, t2_start, _PyCode_CODE(co) + i, type_context_copy); if (meta == NULL) { - PyMem_Free(type_context_copy); + _PyTier2TypeContext_free(type_context_copy); return NULL; } bb_space->water_level += (write_i - t2_start) * sizeof(_Py_CODEUNIT); @@ -823,7 +823,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, if (add_metadata_to_jump_2d_array(t2_info, temp_meta, backwards_jump_target_offset) < 0) { PyMem_Free(meta); PyMem_Free(temp_meta); - PyMem_Free(type_context_copy); + _PyTier2TypeContext_free(type_context_copy); return NULL; } } @@ -969,7 +969,7 @@ _PyTier2Info_Initialize(PyCodeObject *co) t2_info->bb_data_curr = 0; Py_ssize_t bb_data_len = (Py_SIZE(co) / 5 + 1); assert((int)bb_data_len == bb_data_len); - _PyTier2BBMetadata **bb_data = PyMem_Malloc(bb_data_len * sizeof(_PyTier2Info *)); + _PyTier2BBMetadata **bb_data = PyMem_Calloc(bb_data_len, sizeof(_PyTier2BBMetadata*)); if (bb_data == NULL) { PyMem_Free(t2_info); return NULL; @@ -981,7 +981,6 @@ _PyTier2Info_Initialize(PyCodeObject *co) return t2_info; } - ////////// OVERALL TIER2 FUNCTIONS @@ -1092,7 +1091,7 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) co, bb_space, _PyCode_CODE(co), type_context); if (meta == NULL) { - PyMem_Free(type_context); + _PyTier2TypeContext_free(type_context); goto cleanup; } #if BB_DEBUG @@ -1164,7 +1163,6 @@ _PyTier2_GenerateNextBB(_PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, frame->f_code, space, tier1_end, type_context); if (metadata == NULL) { - PyMem_Free(type_context); return NULL; } return metadata->tier2_start; From 2f02babe7513c5f5c105ff0c50fc3a44abff0111 Mon Sep 17 00:00:00 2001 From: Julia Date: Sun, 26 Feb 2023 15:26:09 +0800 Subject: [PATCH 043/280] Refactor: deadcode cleanup for type propagation code --- Python/tier2.c | 65 -------------------------------------------------- 1 file changed, 65 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index 7d47db12c8bbb9..7aadfa8fb32939 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -349,71 +349,6 @@ IS_FORBIDDEN_OPCODE(int opcode) } } -static inline PyTypeObject * -INSTR_LOCAL_READ_TYPE(PyCodeObject *co, _Py_CODEUNIT instr, PyTypeObject **type_context) -{ - int opcode = _PyOpcode_Deopt[_Py_OPCODE(instr)]; - int oparg = _Py_OPARG(instr); - switch (opcode) { - case LOAD_CONST: - return Py_TYPE(PyTuple_GET_ITEM(co->co_consts, oparg)); - case LOAD_FAST: - return type_context[oparg]; - // Note: Don't bother with LOAD_NAME, because those exist only in the global - // scope. - default: - return NULL; - } -} - -/* -* This does multiple things: -* 1. Gets the result type of an instruction, if it can figure it out. - 2. Determines whether thet instruction has a corresponding macro/micro instruction - that acts a guard, and whether it needs it. - 3. How many guards it needs, and what are the guards. - 4. Finally, the corresponding specialised micro-op to operate on this type. - - Returns the inferred type of an operation. NULL if unknown. - - how_many_guards returns the number of guards (0, 1) - guards should be a opcode corresponding to the guard instruction to use. -*/ -static PyTypeObject * -BINARY_OP_RESULT_TYPE(PyCodeObject *co, _Py_CODEUNIT *instr, int n_typecontext, - PyTypeObject **type_context, int *how_many_guards, _Py_CODEUNIT *guard, _Py_CODEUNIT *action) -{ - int opcode = _PyOpcode_Deopt[_Py_OPCODE(*instr)]; - int oparg = _Py_OPARG(*instr); - switch (opcode) { - case BINARY_OP: - if (oparg == NB_ADD) { - // For BINARY OP, read the previous two load instructions - // to see what variables we need to type check. - PyTypeObject *lhs_type = INSTR_LOCAL_READ_TYPE(co, *(instr - 2), type_context); - PyTypeObject *rhs_type = INSTR_LOCAL_READ_TYPE(co, *(instr - 1), type_context); - // The two instruction types are known. - if (lhs_type == &PyLong_Type) { - if (rhs_type == &PyLong_Type) { - *how_many_guards = 0; - action->op.code = BINARY_OP_ADD_INT_REST; - return &PyLong_Type; - } - //// Right side unknown. Emit single check. - //else if (rhs_type == NULL) { - // *how_many_guards = 1; - // guard->opcode = - // return NULL; - //} - } - // We don't know anything, need to emit guard. - // @TODO - } - break; - } - return NULL; -} - static inline _Py_CODEUNIT * emit_cache_entries(_Py_CODEUNIT *write_curr, int cache_entries) { From f11c9af06c05cc70979c8f65628933667f9fe774 Mon Sep 17 00:00:00 2001 From: Julia Date: Sun, 26 Feb 2023 18:11:23 +0800 Subject: [PATCH 044/280] working: types meta-interpreter in progress Might require a refactor of the tier2 bytecode emitting code to progress. When emitting from a codeobject (with tier1 bytecode): 1. deop inst back to tier0 2. emit tier2 inst based on current type context 3. type propagate through emitted inst This allows the type propagator to work with tier2 bytecode (which contains more information) and can probably be generated from the DSL --- .gitattributes | 1 + Include/cpython/code.h | 2 ++ Python/tier2.c | 13 ++++++++++--- Python/tier2_metainterpreter.c.h | 0 4 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 Python/tier2_metainterpreter.c.h diff --git a/.gitattributes b/.gitattributes index 13289182400109..c26944b3387c78 100644 --- a/.gitattributes +++ b/.gitattributes @@ -83,6 +83,7 @@ Parser/token.c generated Programs/test_frozenmain.h generated Python/Python-ast.c generated Python/generated_cases.c.h generated +Python/tier2_metainterpreter.c.h generated Python/opcode_targets.h generated Python/stdlib_module_names.h generated Tools/peg_generator/pegen/grammar_parser.py generated diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 852a7965abec95..c1f8a0c27ccce3 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -58,6 +58,8 @@ typedef struct { // Tier 2 types meta interpreter typedef struct _PyTier2TypeContext { + // points into type_stack, points to one element after the stack + PyTypeObject** type_stack_ptr; int type_locals_len; int type_stack_len; PyTypeObject** type_stack; diff --git a/Python/tier2.c b/Python/tier2.c index 7aadfa8fb32939..505903e017e93e 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -49,6 +49,7 @@ initialize_type_context(const PyCodeObject *co) { type_context->type_stack_len = nstack; type_context->type_locals = type_locals; type_context->type_stack = type_stack; + type_context->type_stack_ptr = type_stack; // init ptr at start of stack return type_context; } @@ -608,8 +609,11 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, { #define END() goto end; #define JUMPBY(x) i += x + 1; -#define BASIC_PUSH(v) (*stack_pointer++ = (v)) -#define BASIC_POP() (*--stack_pointer) +#define TYPESTACK_PUSH(v) (*type_stackptr++ = v) +#define TYPESTACK_POP() (*--type_stackptr) +#define TYPESTACK_PEEK(i) (*(type_stackptr - 1 - i)) +#define TYPELOCALS_SET(idx, v) type_locals[idx] = v; +#define TYPELOCALS_UNSET(idx) type_locals[idx] = NULL; #define DISPATCH() write_i = emit_i(write_i, opcode, oparg); \ write_i = copy_cache_entries(write_i, curr+1, caches); \ i += caches; \ @@ -634,7 +638,9 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, _PyTier2Info *t2_info = co->_tier2_info; _Py_CODEUNIT *t2_start = (_Py_CODEUNIT *)(((char *)bb_space->u_code) + bb_space->water_level); _Py_CODEUNIT *write_i = t2_start; - PyTypeObject **stack_pointer = type_context_copy->type_stack; + PyTypeObject **type_stack = type_context_copy->type_stack; + PyTypeObject **type_locals = type_context_copy->type_locals; + PyTypeObject** type_stackptr = &type_context_copy->type_stack_ptr; int tos = -1; // For handling of backwards jumps @@ -672,6 +678,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // caches = _PyOpcode_Caches[opcode]; // DISPATCH_GOTO(); // We need to rewrite the pseudo-branch instruction. +#include "tier2_metainterpreter.c.h" case COMPARE_AND_BRANCH: opcode = COMPARE_OP; DISPATCH(); diff --git a/Python/tier2_metainterpreter.c.h b/Python/tier2_metainterpreter.c.h new file mode 100644 index 00000000000000..e69de29bb2d1d6 From 1e0116df6f28af7bef0d52dd37cea5321806b443 Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 27 Feb 2023 21:48:24 +0800 Subject: [PATCH 045/280] Feat: Added more type annotations and localarr effect to DSL and updated bytecodes.c --- Python/bytecodes.c | 16 +++--- Tools/cases_generator/parser.py | 90 ++++++++++++++++++++++++++++++--- 2 files changed, 92 insertions(+), 14 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 6f707d2175a3e5..ea81270e9791f8 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -102,31 +102,31 @@ dummy_func( } } - inst(LOAD_CLOSURE, (-- value)) { + inst(LOAD_CLOSURE, (-- value : locals[oparg])) { /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ value = GETLOCAL(oparg); ERROR_IF(value == NULL, unbound_local_error); Py_INCREF(value); } - inst(LOAD_FAST_CHECK, (-- value)) { + inst(LOAD_FAST_CHECK, (-- value : locals[oparg])) { value = GETLOCAL(oparg); ERROR_IF(value == NULL, unbound_local_error); Py_INCREF(value); } - inst(LOAD_FAST, (-- value)) { + inst(LOAD_FAST, (-- value : locals[oparg])) { value = GETLOCAL(oparg); assert(value != NULL); Py_INCREF(value); } - inst(LOAD_CONST, (-- value)) { + inst(LOAD_CONST, (-- value : consts[oparg])) { value = GETITEM(consts, oparg); Py_INCREF(value); } - inst(STORE_FAST, (value --)) { + inst(STORE_FAST, (value --), locals[oparg] = *value) { SETLOCAL(oparg, value); } @@ -303,7 +303,7 @@ dummy_func( bb_test = PyLong_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); } - u_inst(BINARY_OP_ADD_INT_REST, (left, right -- sum)) { + u_inst(BINARY_OP_ADD_INT_REST, (left : PyLong_Type, right : PyLong_Type -- sum : PyLong_Type)) { STAT_INC(BINARY_OP, hit); sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -1180,13 +1180,13 @@ dummy_func( null = NULL; } - inst(DELETE_FAST, (--)) { + inst(DELETE_FAST, (--), locals[oparg] = NULL) { PyObject *v = GETLOCAL(oparg); ERROR_IF(v == NULL, unbound_local_error); SETLOCAL(oparg, NULL); } - inst(MAKE_CELL, (--)) { + inst(MAKE_CELL, (--), locals[oparg] = NULL) { // "initial" is probably NULL but not if it's an arg (or set // via PyFrame_LocalsToFast() before MAKE_CELL has run). PyObject *initial = GETLOCAL(oparg); diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index 4381abe5579462..2d9687a90e1646 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -68,10 +68,25 @@ class Block(Node): pass +@dataclass +class StackVarTypeLiteral(Node): + literal: str + + +@dataclass +class StackVarTypeIndex(Node): + array: Literal["locals"] | Literal["consts"] + index: str + + +StackVarType = StackVarTypeLiteral | StackVarTypeIndex + + @dataclass class StackEffect(Node): name: str type: str = "" # Optional `:type` + type_annotation: StackVarType | None = None # Default is None cond: str = "" # Optional `if (cond)` size: str = "" # Optional `[size]` # Note: size cannot be combined with type or cond @@ -88,6 +103,25 @@ class CacheEffect(Node): size: int +@dataclass +class LocalEffectVarLiteral(Node): + name: str + + +@dataclass +class LocalEffectVarStack(Node): + name: str + + +LocalEffectVar = LocalEffectVarLiteral | LocalEffectVarStack + + +@dataclass +class LocalEffect(Node): + index: str + value: LocalEffectVar + + @dataclass class OpName(Node): name: str @@ -125,6 +159,7 @@ class InstHeader(Node): name: str inputs: list[InputEffect] outputs: list[OutputEffect] + localeffect: LocalEffect | None = None @dataclass @@ -136,6 +171,7 @@ class InstDef(Node): outputs: list[OutputEffect] block: Block u_insts: list[str] + localeffect: LocalEffect | None = None @dataclass @@ -179,7 +215,7 @@ def inst_def(self) -> InstDef | None: space, label = m.groups() u_insts.append(label) return InstDef( - hdr.register, hdr.kind, hdr.name, hdr.inputs, hdr.outputs, block, u_insts + hdr.register, hdr.kind, hdr.name, hdr.inputs, hdr.outputs, block, u_insts, hdr.localeffect ) raise self.make_syntax_error("Expected block") return None @@ -199,6 +235,11 @@ def inst_header(self) -> InstHeader | None: if self.expect(lx.RPAREN): if (tkn := self.peek()) and tkn.kind == lx.LBRACE: return InstHeader(register, kind, name, inp, outp) + elif self.expect(lx.COMMA): + leffect = self.local_effect() + if self.expect(lx.RPAREN): + if (tkn := self.peek()) and tkn.kind == lx.LBRACE: + return InstHeader(register, kind, name, inp, outp, leffect) elif self.expect(lx.RPAREN) and kind == "inst": # No legacy stack effect if kind is "op". return InstHeader(register, "legacy", name, [], []) @@ -266,9 +307,12 @@ def stack_effect(self) -> StackEffect | None: # IDENTIFIER [':' IDENTIFIER] ['if' '(' expression ')'] # | IDENTIFIER '[' expression ']' if tkn := self.expect(lx.IDENTIFIER): - type_text = "" + type = "" + has_type_annotation = False + type_annotation = None if self.expect(lx.COLON): - type_text = self.require(lx.IDENTIFIER).text.strip() + has_type_annotation = True + type_annotation = self.stackvar_type() cond_text = "" if self.expect(lx.IF): self.require(lx.LPAREN) @@ -278,14 +322,48 @@ def stack_effect(self) -> StackEffect | None: cond_text = cond.text.strip() size_text = "" if self.expect(lx.LBRACKET): - if type_text or cond_text: + if has_type_annotation or cond_text: raise self.make_syntax_error("Unexpected [") if not (size := self.expression()): raise self.make_syntax_error("Expected expression") self.require(lx.RBRACKET) - type_text = "PyObject **" + type = "PyObject **" size_text = size.text.strip() - return StackEffect(tkn.text, type_text, cond_text, size_text) + return StackEffect(tkn.text, type, type_annotation, cond_text, size_text) + + @contextual + def stackvar_type(self) -> StackVarType | None: + if id := self.expect(lx.IDENTIFIER): + idstr = id.text.strip() + if not self.expect(lx.LBRACKET): + return StackVarTypeLiteral(idstr + " *") + if idstr not in ["locals", "consts"]: return + if id := self.expect(lx.IDENTIFIER): + index = id.text.strip() + self.require(lx.RBRACKET) + return StackVarTypeIndex( + "locals" if idstr == "locals" else "consts", + index) + + @contextual + def local_effect(self) -> LocalEffect | None: + if self.expect(lx.IDENTIFIER).text.strip() == "locals": + self.require(lx.LBRACKET) + if id := self.expect(lx.IDENTIFIER): + index = id.text.strip() + self.require(lx.RBRACKET) + self.require(lx.EQUALS) + if self.expect(lx.TIMES): # stackvar + value = self.require(lx.IDENTIFIER).text.strip() + return LocalEffect( + index, + LocalEffectVarStack(value) + ) + value = self.require(lx.IDENTIFIER).text.strip() + return LocalEffect( + index, + LocalEffectVarLiteral(value) + ) @contextual def expression(self) -> Expression | None: From 4f4a3fd22663fa31280aedbe36f04ca3d713b59d Mon Sep 17 00:00:00 2001 From: Julia Date: Wed, 1 Mar 2023 01:10:38 +0800 Subject: [PATCH 046/280] feat: Implemented type propagation except for jump instructions with conditional stack effect --- Python/tier2.c | 54 +- Python/tier2_metainterpreter.c.h | 0 Python/tier2_typepropagator.c.h | 1282 +++++++++++++++++++++++ Tools/cases_generator/generate_cases.py | 159 ++- Tools/cases_generator/parser.py | 2 +- 5 files changed, 1478 insertions(+), 19 deletions(-) delete mode 100644 Python/tier2_metainterpreter.c.h create mode 100644 Python/tier2_typepropagator.c.h diff --git a/Python/tier2.c b/Python/tier2.c index 505903e017e93e..3e4c5ab0922ab2 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -590,6 +590,40 @@ add_metadata_to_jump_2d_array(_PyTier2Info *t2_info, _PyTier2BBMetadata *meta, return 0; } +static void +type_propagate( + int opcode, int oparg, + PyTypeObject** type_stackptr, PyTypeObject** type_locals, + const PyObject* consts) +{ +#define TARGET(op) case op: +#define TYPESTACK_PEEK(idx) (type_stackptr[-(idx)]) +#define TYPESTACK_POKE(idx, v) type_stackptr[-(idx)] = (v) +#define TYPELOCALS_SET(idx, v) type_locals[idx] = v; +#define TYPELOCALS_GET(idx) (type_locals[idx]) +#define TYPECONST_GET(idx) Py_TYPE(_PyTuple_CAST(consts)->ob_item[(idx)]) +#define STACK_ADJUST(idx) type_stackptr += (idx) +#define STACK_GROW(idx) STACK_ADJUST((idx)) +#define STACK_SHRINK(idx) STACK_ADJUST(-(idx)) + + switch (opcode) { +#include "tier2_typepropagator.c.h" + default: + fprintf(stderr, "Unsupported opcode in type propagator: %d\n", opcode); + assert(opcode); + } + +#undef TARGET +#undef TYPESTACK_PEEK +#undef TYPESTACK_POKE +#undef TYPELOCALS_SET +#undef TYPELOCALS_GET +#undef TYPECONST_GET +#undef STACK_ADJUST +#undef STACK_GROW +#undef STACK_SHRINK +} + // Detects a BB from the current instruction start to the end of the first basic block it sees. // Then emits the instructions into the bb space. // @@ -609,14 +643,10 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, { #define END() goto end; #define JUMPBY(x) i += x + 1; -#define TYPESTACK_PUSH(v) (*type_stackptr++ = v) -#define TYPESTACK_POP() (*--type_stackptr) -#define TYPESTACK_PEEK(i) (*(type_stackptr - 1 - i)) -#define TYPELOCALS_SET(idx, v) type_locals[idx] = v; -#define TYPELOCALS_UNSET(idx) type_locals[idx] = NULL; #define DISPATCH() write_i = emit_i(write_i, opcode, oparg); \ write_i = copy_cache_entries(write_i, curr+1, caches); \ i += caches; \ + type_propagate(opcode, oparg, type_stackptr, type_locals, consts); \ continue; #define DISPATCH_GOTO() goto dispatch_opcode; @@ -636,11 +666,12 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, _PyTier2BBMetadata *temp_meta = NULL; _PyTier2Info *t2_info = co->_tier2_info; + PyObject *consts = co->co_consts; _Py_CODEUNIT *t2_start = (_Py_CODEUNIT *)(((char *)bb_space->u_code) + bb_space->water_level); _Py_CODEUNIT *write_i = t2_start; PyTypeObject **type_stack = type_context_copy->type_stack; PyTypeObject **type_locals = type_context_copy->type_locals; - PyTypeObject** type_stackptr = &type_context_copy->type_stack_ptr; + PyTypeObject **type_stackptr = type_context_copy->type_stack_ptr; int tos = -1; // For handling of backwards jumps @@ -668,17 +699,6 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, case RESUME: opcode = RESUME_QUICK; DISPATCH(); - //case EXTENDED_ARG: - // write_i = emit_i(write_i, EXTENDED_ARG, _Py_OPARG(*curr)); - // curr++; - // next_instr++; - // i++; - // oparg = oparg << 8 | _Py_OPARG(*curr); - // opcode = _Py_OPCODE(*curr); - // caches = _PyOpcode_Caches[opcode]; - // DISPATCH_GOTO(); - // We need to rewrite the pseudo-branch instruction. -#include "tier2_metainterpreter.c.h" case COMPARE_AND_BRANCH: opcode = COMPARE_OP; DISPATCH(); diff --git a/Python/tier2_metainterpreter.c.h b/Python/tier2_metainterpreter.c.h deleted file mode 100644 index e69de29bb2d1d6..00000000000000 diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h new file mode 100644 index 00000000000000..fb7ee319f35d83 --- /dev/null +++ b/Python/tier2_typepropagator.c.h @@ -0,0 +1,1282 @@ +// This file is generated by Tools\cases_generator\generate_cases.py @TODO: make this a seperate argument +// from Python\bytecodes.c +// Do not edit! + + TARGET(NOP) { + break; + } + + TARGET(RESUME) { + break; + } + + TARGET(RESUME_QUICK) { + break; + } + + TARGET(LOAD_CLOSURE) { + STACK_GROW(1); + TYPESTACK_POKE(1, TYPELOCALS_GET(oparg)); + break; + } + + TARGET(LOAD_FAST_CHECK) { + STACK_GROW(1); + TYPESTACK_POKE(1, TYPELOCALS_GET(oparg)); + break; + } + + TARGET(LOAD_FAST) { + STACK_GROW(1); + TYPESTACK_POKE(1, TYPELOCALS_GET(oparg)); + break; + } + + TARGET(LOAD_CONST) { + STACK_GROW(1); + TYPESTACK_POKE(1, TYPECONST_GET(oparg)); + break; + } + + TARGET(STORE_FAST) { + PyTypeObject *value = TYPESTACK_PEEK(1); + TYPELOCALS_SET(oparg, value) + STACK_SHRINK(1); + break; + } + + TARGET(POP_TOP) { + PyTypeObject *value = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + break; + } + + TARGET(PUSH_NULL) { + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(END_FOR) { + { + PyTypeObject *value = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + } + { + PyTypeObject *value = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + } + break; + } + + TARGET(UNARY_NEGATIVE) { + PyTypeObject *value = TYPESTACK_PEEK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(UNARY_NOT) { + PyTypeObject *value = TYPESTACK_PEEK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(UNARY_INVERT) { + PyTypeObject *value = TYPESTACK_PEEK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(BINARY_OP_MULTIPLY_INT) { + PyTypeObject *right = TYPESTACK_PEEK(1); + PyTypeObject *left = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(BINARY_OP_MULTIPLY_FLOAT) { + PyTypeObject *right = TYPESTACK_PEEK(1); + PyTypeObject *left = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(BINARY_OP_SUBTRACT_INT) { + PyTypeObject *right = TYPESTACK_PEEK(1); + PyTypeObject *left = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(BINARY_OP_SUBTRACT_FLOAT) { + PyTypeObject *right = TYPESTACK_PEEK(1); + PyTypeObject *left = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(BINARY_OP_ADD_UNICODE) { + PyTypeObject *right = TYPESTACK_PEEK(1); + PyTypeObject *left = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { + PyTypeObject *right = TYPESTACK_PEEK(1); + PyTypeObject *left = TYPESTACK_PEEK(2); + STACK_SHRINK(2); + break; + } + + TARGET(BINARY_OP_ADD_FLOAT) { + PyTypeObject *right = TYPESTACK_PEEK(1); + PyTypeObject *left = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(BINARY_OP_ADD_INT) { + PyTypeObject *right = TYPESTACK_PEEK(1); + PyTypeObject *left = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(BINARY_CHECK_INT) { + PyTypeObject *right = TYPESTACK_PEEK(1); + PyTypeObject *left = TYPESTACK_PEEK(2); + TYPESTACK_POKE(1, &PyLong_Type); + TYPESTACK_POKE(2, &PyLong_Type); + break; + } + + TARGET(BINARY_OP_ADD_INT_REST) { + PyTypeObject *right = TYPESTACK_PEEK(1); + PyTypeObject *left = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + TYPESTACK_POKE(1, &PyLong_Type); + break; + } + + TARGET(BINARY_SUBSCR) { + PyTypeObject *sub = TYPESTACK_PEEK(1); + PyTypeObject *container = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(BINARY_SLICE) { + PyTypeObject *stop = TYPESTACK_PEEK(1); + PyTypeObject *start = TYPESTACK_PEEK(2); + PyTypeObject *container = TYPESTACK_PEEK(3); + STACK_SHRINK(2); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(STORE_SLICE) { + PyTypeObject *stop = TYPESTACK_PEEK(1); + PyTypeObject *start = TYPESTACK_PEEK(2); + PyTypeObject *container = TYPESTACK_PEEK(3); + PyTypeObject *v = TYPESTACK_PEEK(4); + STACK_SHRINK(4); + break; + } + + TARGET(BINARY_SUBSCR_LIST_INT) { + PyTypeObject *sub = TYPESTACK_PEEK(1); + PyTypeObject *list = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(BINARY_SUBSCR_TUPLE_INT) { + PyTypeObject *sub = TYPESTACK_PEEK(1); + PyTypeObject *tuple = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(BINARY_SUBSCR_DICT) { + PyTypeObject *sub = TYPESTACK_PEEK(1); + PyTypeObject *dict = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(BINARY_SUBSCR_GETITEM) { + PyTypeObject *sub = TYPESTACK_PEEK(1); + PyTypeObject *container = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + break; + } + + TARGET(LIST_APPEND) { + PyTypeObject *v = TYPESTACK_PEEK(1); + PyTypeObject *list = TYPESTACK_PEEK(2 + (oparg-1)); + STACK_SHRINK(1); + break; + } + + TARGET(SET_ADD) { + PyTypeObject *v = TYPESTACK_PEEK(1); + PyTypeObject *set = TYPESTACK_PEEK(2 + (oparg-1)); + STACK_SHRINK(1); + break; + } + + TARGET(STORE_SUBSCR) { + PyTypeObject *sub = TYPESTACK_PEEK(1); + PyTypeObject *container = TYPESTACK_PEEK(2); + PyTypeObject *v = TYPESTACK_PEEK(3); + STACK_SHRINK(3); + break; + } + + TARGET(STORE_SUBSCR_LIST_INT) { + PyTypeObject *sub = TYPESTACK_PEEK(1); + PyTypeObject *list = TYPESTACK_PEEK(2); + PyTypeObject *value = TYPESTACK_PEEK(3); + STACK_SHRINK(3); + break; + } + + TARGET(STORE_SUBSCR_DICT) { + PyTypeObject *sub = TYPESTACK_PEEK(1); + PyTypeObject *dict = TYPESTACK_PEEK(2); + PyTypeObject *value = TYPESTACK_PEEK(3); + STACK_SHRINK(3); + break; + } + + TARGET(DELETE_SUBSCR) { + PyTypeObject *sub = TYPESTACK_PEEK(1); + PyTypeObject *container = TYPESTACK_PEEK(2); + STACK_SHRINK(2); + break; + } + + TARGET(CALL_INTRINSIC_1) { + PyTypeObject *value = TYPESTACK_PEEK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(CALL_INTRINSIC_2) { + PyTypeObject *value1 = TYPESTACK_PEEK(1); + PyTypeObject *value2 = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(RAISE_VARARGS) { + PyTypeObject **args = &TYPESTACK_PEEK(oparg); + STACK_SHRINK(oparg); + break; + } + + TARGET(INTERPRETER_EXIT) { + PyTypeObject *retval = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + break; + } + + TARGET(RETURN_VALUE) { + PyTypeObject *retval = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + break; + } + + TARGET(RETURN_CONST) { + break; + } + + TARGET(GET_AITER) { + PyTypeObject *obj = TYPESTACK_PEEK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(GET_ANEXT) { + PyTypeObject *aiter = TYPESTACK_PEEK(1); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(GET_AWAITABLE) { + PyTypeObject *iterable = TYPESTACK_PEEK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(SEND) { + PyTypeObject *v = TYPESTACK_PEEK(1); + PyTypeObject *receiver = TYPESTACK_PEEK(2); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(SEND_GEN) { + PyTypeObject *v = TYPESTACK_PEEK(1); + PyTypeObject *receiver = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + break; + } + + TARGET(YIELD_VALUE) { + PyTypeObject *retval = TYPESTACK_PEEK(1); + break; + } + + TARGET(POP_EXCEPT) { + PyTypeObject *exc_value = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + break; + } + + TARGET(RERAISE) { + PyTypeObject *exc = TYPESTACK_PEEK(1); + PyTypeObject **values = &TYPESTACK_PEEK(1 + oparg); + STACK_SHRINK(1); + break; + } + + TARGET(END_ASYNC_FOR) { + PyTypeObject *exc = TYPESTACK_PEEK(1); + PyTypeObject *awaitable = TYPESTACK_PEEK(2); + STACK_SHRINK(2); + break; + } + + TARGET(CLEANUP_THROW) { + PyTypeObject *exc_value = TYPESTACK_PEEK(1); + PyTypeObject *last_sent_val = TYPESTACK_PEEK(2); + PyTypeObject *sub_iter = TYPESTACK_PEEK(3); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(2, NULL); + break; + } + + TARGET(LOAD_ASSERTION_ERROR) { + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(LOAD_BUILD_CLASS) { + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(STORE_NAME) { + PyTypeObject *v = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + break; + } + + TARGET(DELETE_NAME) { + break; + } + + TARGET(UNPACK_SEQUENCE) { + PyTypeObject *seq = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + STACK_GROW(oparg); + break; + } + + TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { + PyTypeObject *seq = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + STACK_GROW(oparg); + TYPESTACK_POKE(oparg, NULL); + break; + } + + TARGET(UNPACK_SEQUENCE_TUPLE) { + PyTypeObject *seq = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + STACK_GROW(oparg); + TYPESTACK_POKE(oparg, NULL); + break; + } + + TARGET(UNPACK_SEQUENCE_LIST) { + PyTypeObject *seq = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + STACK_GROW(oparg); + TYPESTACK_POKE(oparg, NULL); + break; + } + + TARGET(UNPACK_EX) { + PyTypeObject *seq = TYPESTACK_PEEK(1); + STACK_GROW((oparg & 0xFF) + (oparg >> 8)); + break; + } + + TARGET(STORE_ATTR) { + PyTypeObject *owner = TYPESTACK_PEEK(1); + PyTypeObject *v = TYPESTACK_PEEK(2); + STACK_SHRINK(2); + break; + } + + TARGET(DELETE_ATTR) { + PyTypeObject *owner = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + break; + } + + TARGET(STORE_GLOBAL) { + PyTypeObject *v = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + break; + } + + TARGET(DELETE_GLOBAL) { + break; + } + + TARGET(LOAD_NAME) { + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(LOAD_GLOBAL) { + STACK_GROW(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPESTACK_POKE(1, NULL); + if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + break; + } + + TARGET(LOAD_GLOBAL_MODULE) { + STACK_GROW(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPESTACK_POKE(1, NULL); + if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + break; + } + + TARGET(LOAD_GLOBAL_BUILTIN) { + STACK_GROW(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPESTACK_POKE(1, NULL); + if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + break; + } + + TARGET(DELETE_FAST) { + TYPELOCALS_SET(oparg, NULL) + break; + } + + TARGET(MAKE_CELL) { + TYPELOCALS_SET(oparg, NULL) + break; + } + + TARGET(DELETE_DEREF) { + break; + } + + TARGET(LOAD_CLASSDEREF) { + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(LOAD_DEREF) { + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(STORE_DEREF) { + PyTypeObject *v = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + break; + } + + TARGET(COPY_FREE_VARS) { + break; + } + + TARGET(BUILD_STRING) { + PyTypeObject **pieces = &TYPESTACK_PEEK(oparg); + STACK_SHRINK(oparg); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(BUILD_TUPLE) { + PyTypeObject **values = &TYPESTACK_PEEK(oparg); + STACK_SHRINK(oparg); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(BUILD_LIST) { + PyTypeObject **values = &TYPESTACK_PEEK(oparg); + STACK_SHRINK(oparg); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(LIST_EXTEND) { + PyTypeObject *iterable = TYPESTACK_PEEK(1); + PyTypeObject *list = TYPESTACK_PEEK(2 + (oparg-1)); + STACK_SHRINK(1); + break; + } + + TARGET(SET_UPDATE) { + PyTypeObject *iterable = TYPESTACK_PEEK(1); + PyTypeObject *set = TYPESTACK_PEEK(2 + (oparg-1)); + STACK_SHRINK(1); + break; + } + + TARGET(BUILD_SET) { + PyTypeObject **values = &TYPESTACK_PEEK(oparg); + STACK_SHRINK(oparg); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(BUILD_MAP) { + PyTypeObject **values = &TYPESTACK_PEEK(oparg*2); + STACK_SHRINK(oparg*2); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(SETUP_ANNOTATIONS) { + break; + } + + TARGET(BUILD_CONST_KEY_MAP) { + PyTypeObject *keys = TYPESTACK_PEEK(1); + PyTypeObject **values = &TYPESTACK_PEEK(1 + oparg); + STACK_SHRINK(oparg); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(DICT_UPDATE) { + PyTypeObject *update = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + break; + } + + TARGET(DICT_MERGE) { + PyTypeObject *update = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + break; + } + + TARGET(MAP_ADD) { + PyTypeObject *value = TYPESTACK_PEEK(1); + PyTypeObject *key = TYPESTACK_PEEK(2); + STACK_SHRINK(2); + break; + } + + TARGET(LOAD_ATTR) { + PyTypeObject *owner = TYPESTACK_PEEK(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPESTACK_POKE(1, NULL); + if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + break; + } + + TARGET(LOAD_ATTR_INSTANCE_VALUE) { + PyTypeObject *owner = TYPESTACK_PEEK(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPESTACK_POKE(1, NULL); + if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + break; + } + + TARGET(LOAD_ATTR_MODULE) { + PyTypeObject *owner = TYPESTACK_PEEK(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPESTACK_POKE(1, NULL); + if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + break; + } + + TARGET(LOAD_ATTR_WITH_HINT) { + PyTypeObject *owner = TYPESTACK_PEEK(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPESTACK_POKE(1, NULL); + if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + break; + } + + TARGET(LOAD_ATTR_SLOT) { + PyTypeObject *owner = TYPESTACK_PEEK(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPESTACK_POKE(1, NULL); + if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + break; + } + + TARGET(LOAD_ATTR_CLASS) { + PyTypeObject *cls = TYPESTACK_PEEK(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPESTACK_POKE(1, NULL); + if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + break; + } + + TARGET(LOAD_ATTR_PROPERTY) { + PyTypeObject *owner = TYPESTACK_PEEK(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + break; + } + + TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { + PyTypeObject *owner = TYPESTACK_PEEK(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + break; + } + + TARGET(STORE_ATTR_INSTANCE_VALUE) { + PyTypeObject *owner = TYPESTACK_PEEK(1); + PyTypeObject *value = TYPESTACK_PEEK(2); + STACK_SHRINK(2); + break; + } + + TARGET(STORE_ATTR_WITH_HINT) { + PyTypeObject *owner = TYPESTACK_PEEK(1); + PyTypeObject *value = TYPESTACK_PEEK(2); + STACK_SHRINK(2); + break; + } + + TARGET(STORE_ATTR_SLOT) { + PyTypeObject *owner = TYPESTACK_PEEK(1); + PyTypeObject *value = TYPESTACK_PEEK(2); + STACK_SHRINK(2); + break; + } + + TARGET(COMPARE_OP) { + PyTypeObject *right = TYPESTACK_PEEK(1); + PyTypeObject *left = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(COMPARE_AND_BRANCH) { + PyTypeObject *right = TYPESTACK_PEEK(1); + PyTypeObject *left = TYPESTACK_PEEK(2); + STACK_SHRINK(2); + break; + } + + TARGET(COMPARE_AND_BRANCH_FLOAT) { + PyTypeObject *right = TYPESTACK_PEEK(1); + PyTypeObject *left = TYPESTACK_PEEK(2); + STACK_SHRINK(2); + break; + } + + TARGET(COMPARE_AND_BRANCH_INT) { + PyTypeObject *right = TYPESTACK_PEEK(1); + PyTypeObject *left = TYPESTACK_PEEK(2); + STACK_SHRINK(2); + break; + } + + TARGET(COMPARE_AND_BRANCH_STR) { + PyTypeObject *right = TYPESTACK_PEEK(1); + PyTypeObject *left = TYPESTACK_PEEK(2); + STACK_SHRINK(2); + break; + } + + TARGET(IS_OP) { + PyTypeObject *right = TYPESTACK_PEEK(1); + PyTypeObject *left = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(CONTAINS_OP) { + PyTypeObject *right = TYPESTACK_PEEK(1); + PyTypeObject *left = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(CHECK_EG_MATCH) { + PyTypeObject *match_type = TYPESTACK_PEEK(1); + PyTypeObject *exc_value = TYPESTACK_PEEK(2); + TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(2, NULL); + break; + } + + TARGET(CHECK_EXC_MATCH) { + PyTypeObject *right = TYPESTACK_PEEK(1); + PyTypeObject *left = TYPESTACK_PEEK(2); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(IMPORT_NAME) { + PyTypeObject *fromlist = TYPESTACK_PEEK(1); + PyTypeObject *level = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(IMPORT_FROM) { + PyTypeObject *from = TYPESTACK_PEEK(1); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(JUMP_FORWARD) { + break; + } + + TARGET(JUMP_BACKWARD) { + break; + } + + TARGET(JUMP_BACKWARD_QUICK) { + break; + } + + TARGET(POP_JUMP_IF_FALSE) { + PyTypeObject *cond = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + break; + } + + TARGET(BB_TEST_POP_IF_FALSE) { + PyTypeObject *cond = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + break; + } + + TARGET(POP_JUMP_IF_TRUE) { + PyTypeObject *cond = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + break; + } + + TARGET(BB_TEST_POP_IF_TRUE) { + PyTypeObject *cond = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + break; + } + + TARGET(POP_JUMP_IF_NOT_NONE) { + PyTypeObject *value = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + break; + } + + TARGET(BB_TEST_POP_IF_NOT_NONE) { + PyTypeObject *value = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + break; + } + + TARGET(POP_JUMP_IF_NONE) { + PyTypeObject *value = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + break; + } + + TARGET(BB_TEST_POP_IF_NONE) { + PyTypeObject *value = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + break; + } + + TARGET(JUMP_IF_FALSE_OR_POP) { + PyTypeObject *cond = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + STACK_GROW((jump ? 1 : 0)); + break; + } + + TARGET(BB_TEST_IF_FALSE_OR_POP) { + PyTypeObject *cond = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + STACK_GROW((jump ? 1 : 0)); + break; + } + + TARGET(JUMP_IF_TRUE_OR_POP) { + PyTypeObject *cond = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + STACK_GROW((jump ? 1 : 0)); + break; + } + + TARGET(BB_TEST_IF_TRUE_OR_POP) { + PyTypeObject *cond = TYPESTACK_PEEK(1); + STACK_SHRINK(1); + STACK_GROW((jump ? 1 : 0)); + break; + } + + TARGET(JUMP_BACKWARD_NO_INTERRUPT) { + break; + } + + TARGET(GET_LEN) { + PyTypeObject *obj = TYPESTACK_PEEK(1); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(MATCH_CLASS) { + PyTypeObject *names = TYPESTACK_PEEK(1); + PyTypeObject *type = TYPESTACK_PEEK(2); + PyTypeObject *subject = TYPESTACK_PEEK(3); + STACK_SHRINK(2); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(MATCH_MAPPING) { + PyTypeObject *subject = TYPESTACK_PEEK(1); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(MATCH_SEQUENCE) { + PyTypeObject *subject = TYPESTACK_PEEK(1); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(MATCH_KEYS) { + PyTypeObject *keys = TYPESTACK_PEEK(1); + PyTypeObject *subject = TYPESTACK_PEEK(2); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(GET_ITER) { + PyTypeObject *iterable = TYPESTACK_PEEK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(GET_YIELD_FROM_ITER) { + PyTypeObject *iterable = TYPESTACK_PEEK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(FOR_ITER) { + PyTypeObject *iter = TYPESTACK_PEEK(1); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(BB_TEST_ITER) { + PyTypeObject *iter = TYPESTACK_PEEK(1); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(FOR_ITER_LIST) { + PyTypeObject *iter = TYPESTACK_PEEK(1); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(FOR_ITER_TUPLE) { + PyTypeObject *iter = TYPESTACK_PEEK(1); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(FOR_ITER_RANGE) { + PyTypeObject *iter = TYPESTACK_PEEK(1); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(FOR_ITER_GEN) { + PyTypeObject *iter = TYPESTACK_PEEK(1); + STACK_GROW(1); + break; + } + + TARGET(BEFORE_ASYNC_WITH) { + PyTypeObject *mgr = TYPESTACK_PEEK(1); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(2, NULL); + break; + } + + TARGET(BEFORE_WITH) { + PyTypeObject *mgr = TYPESTACK_PEEK(1); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(2, NULL); + break; + } + + TARGET(WITH_EXCEPT_START) { + PyTypeObject *val = TYPESTACK_PEEK(1); + PyTypeObject *lasti = TYPESTACK_PEEK(3); + PyTypeObject *exit_func = TYPESTACK_PEEK(4); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(PUSH_EXC_INFO) { + PyTypeObject *new_exc = TYPESTACK_PEEK(1); + STACK_GROW(1); + TYPESTACK_POKE(1, new_exc); + TYPESTACK_POKE(2, NULL); + break; + } + + TARGET(LOAD_ATTR_METHOD_WITH_VALUES) { + PyTypeObject *self = TYPESTACK_PEEK(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPESTACK_POKE(1, NULL); + if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + break; + } + + TARGET(LOAD_ATTR_METHOD_NO_DICT) { + PyTypeObject *self = TYPESTACK_PEEK(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPESTACK_POKE(1, NULL); + if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + break; + } + + TARGET(LOAD_ATTR_METHOD_LAZY_DICT) { + PyTypeObject *self = TYPESTACK_PEEK(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPESTACK_POKE(1, NULL); + if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + break; + } + + TARGET(KW_NAMES) { + break; + } + + TARGET(CALL) { + PyTypeObject **args = &TYPESTACK_PEEK(oparg); + PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); + PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { + PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); + PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); + STACK_SHRINK(oparg); + STACK_SHRINK(1); + break; + } + + TARGET(CALL_PY_EXACT_ARGS) { + PyTypeObject **args = &TYPESTACK_PEEK(oparg); + PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); + PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); + STACK_SHRINK(oparg); + STACK_SHRINK(1); + break; + } + + TARGET(CALL_PY_WITH_DEFAULTS) { + PyTypeObject **args = &TYPESTACK_PEEK(oparg); + PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); + PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); + STACK_SHRINK(oparg); + STACK_SHRINK(1); + break; + } + + TARGET(CALL_NO_KW_TYPE_1) { + PyTypeObject **args = &TYPESTACK_PEEK(oparg); + PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); + PyTypeObject *null = TYPESTACK_PEEK(2 + oparg); + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(CALL_NO_KW_STR_1) { + PyTypeObject **args = &TYPESTACK_PEEK(oparg); + PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); + PyTypeObject *null = TYPESTACK_PEEK(2 + oparg); + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(CALL_NO_KW_TUPLE_1) { + PyTypeObject **args = &TYPESTACK_PEEK(oparg); + PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); + PyTypeObject *null = TYPESTACK_PEEK(2 + oparg); + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(CALL_BUILTIN_CLASS) { + PyTypeObject **args = &TYPESTACK_PEEK(oparg); + PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); + PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(CALL_NO_KW_BUILTIN_O) { + PyTypeObject **args = &TYPESTACK_PEEK(oparg); + PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); + PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(CALL_NO_KW_BUILTIN_FAST) { + PyTypeObject **args = &TYPESTACK_PEEK(oparg); + PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); + PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(CALL_BUILTIN_FAST_WITH_KEYWORDS) { + PyTypeObject **args = &TYPESTACK_PEEK(oparg); + PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); + PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(CALL_NO_KW_LEN) { + PyTypeObject **args = &TYPESTACK_PEEK(oparg); + PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); + PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(CALL_NO_KW_ISINSTANCE) { + PyTypeObject **args = &TYPESTACK_PEEK(oparg); + PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); + PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(CALL_NO_KW_LIST_APPEND) { + PyTypeObject **args = &TYPESTACK_PEEK(oparg); + PyTypeObject *self = TYPESTACK_PEEK(1 + oparg); + PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); + STACK_SHRINK(oparg); + STACK_SHRINK(1); + break; + } + + TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { + PyTypeObject **args = &TYPESTACK_PEEK(oparg); + PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS) { + PyTypeObject **args = &TYPESTACK_PEEK(oparg); + PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) { + PyTypeObject **args = &TYPESTACK_PEEK(oparg); + PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_FAST) { + PyTypeObject **args = &TYPESTACK_PEEK(oparg); + PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(CALL_FUNCTION_EX) { + PyTypeObject *kwargs = (oparg & 1) ? TYPESTACK_PEEK(((oparg & 1) ? 1 : 0)) : NULL; + PyTypeObject *callargs = TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)); + PyTypeObject *func = TYPESTACK_PEEK(2 + ((oparg & 1) ? 1 : 0)); + STACK_SHRINK(((oparg & 1) ? 1 : 0)); + STACK_SHRINK(2); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(MAKE_FUNCTION) { + PyTypeObject *codeobj = TYPESTACK_PEEK(1); + PyTypeObject *closure = (oparg & 0x08) ? TYPESTACK_PEEK(1 + ((oparg & 0x08) ? 1 : 0)) : NULL; + PyTypeObject *annotations = (oparg & 0x04) ? TYPESTACK_PEEK(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0)) : NULL; + PyTypeObject *kwdefaults = (oparg & 0x02) ? TYPESTACK_PEEK(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0)) : NULL; + PyTypeObject *defaults = (oparg & 0x01) ? TYPESTACK_PEEK(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0)) : NULL; + STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(RETURN_GENERATOR) { + break; + } + + TARGET(BUILD_SLICE) { + PyTypeObject *step = (oparg == 3) ? TYPESTACK_PEEK(((oparg == 3) ? 1 : 0)) : NULL; + PyTypeObject *stop = TYPESTACK_PEEK(1 + ((oparg == 3) ? 1 : 0)); + PyTypeObject *start = TYPESTACK_PEEK(2 + ((oparg == 3) ? 1 : 0)); + STACK_SHRINK(((oparg == 3) ? 1 : 0)); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(FORMAT_VALUE) { + PyTypeObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? TYPESTACK_PEEK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)) : NULL; + PyTypeObject *value = TYPESTACK_PEEK(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); + STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(COPY) { + PyTypeObject *bottom = TYPESTACK_PEEK(1 + (oparg-1)); + STACK_GROW(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(BINARY_OP) { + PyTypeObject *rhs = TYPESTACK_PEEK(1); + PyTypeObject *lhs = TYPESTACK_PEEK(2); + STACK_SHRINK(1); + TYPESTACK_POKE(1, NULL); + break; + } + + TARGET(SWAP) { + PyTypeObject *top = TYPESTACK_PEEK(1); + PyTypeObject *bottom = TYPESTACK_PEEK(2 + (oparg-2)); + TYPESTACK_POKE(1, bottom); + TYPESTACK_POKE(2 + (oparg-2), top); + break; + } + + TARGET(EXTENDED_ARG) { + break; + } + + TARGET(CACHE) { + break; + } + + TARGET(BB_BRANCH) { + break; + } + + TARGET(BB_BRANCH_IF_FLAG_UNSET) { + break; + } + + TARGET(BB_JUMP_IF_FLAG_UNSET) { + break; + } + + TARGET(BB_BRANCH_IF_FLAG_SET) { + break; + } + + TARGET(BB_JUMP_IF_FLAG_SET) { + break; + } + + TARGET(BB_JUMP_BACKWARD_LAZY) { + break; + } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index ea240ee692adb7..479ee2a8977b3f 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -16,7 +16,8 @@ from enum import Enum, auto import parser -from parser import StackEffect +from parser import StackEffect, StackVarTypeLiteral, StackVarTypeIndex +from parser import LocalEffect, LocalEffectVarLiteral, LocalEffectVarStack HERE = os.path.dirname(__file__) ROOT = os.path.join(HERE, "../..") @@ -35,6 +36,11 @@ os.path.join(ROOT, "Include/internal/pycore_opcode_macro_to_micro.h") ) +# Tier 2 type propagator +TIER2_TYPE_PROPAGATOR_OUTPUT = os.path.relpath( + os.path.join(ROOT, "Python/tier2_typepropagator.c.h") +) + BEGIN_MARKER = "// BEGIN BYTECODES //" END_MARKER = "// END BYTECODES //" RE_PREDICTED = ( @@ -229,6 +235,7 @@ class Instruction: cache_effects: list[parser.CacheEffect] input_effects: list[StackEffect] output_effects: list[StackEffect] + local_effects: LocalEffect | None unmoved_names: frozenset[str] instr_fmt: str @@ -257,6 +264,7 @@ def __init__(self, inst: parser.InstDef): effect for effect in inst.inputs if isinstance(effect, StackEffect) ] self.output_effects = inst.outputs # For consistency/completeness + self.local_effects = inst.localeffect unmoved_names: set[str] = set() for ieffect, oeffect in zip(self.input_effects, self.output_effects): if ieffect.name == oeffect.name: @@ -294,6 +302,95 @@ def analyze_registers(self, a: "Analyzer") -> None: f"Instruction {self.name} has too many register effects", node=self.inst ) + def write_typeprop(self, out: Formatter) -> None: + """Write one instruction's type propagation rules""" + + # Write input stack effect variable declarations and initializations + ieffects = list(reversed(self.input_effects)) + usable_for_local_effect = {} + all_input_effect_names = {} + for i, ieffect in enumerate(ieffects): + isize = string_effect_size( + list_effect_size([ieff for ieff in ieffects[: i + 1]]) + ) + all_input_effect_names[ieffect.name] = (ieffect, i) + dst = StackEffect(ieffect.name, "PyTypeObject *") + if ieffect.size: + src = StackEffect(f"&TYPESTACK_PEEK({isize})", "PyTypeObject **") + dst = StackEffect(ieffect.name, "PyTypeObject **") + elif ieffect.cond: + src = StackEffect(f"({ieffect.cond}) ? TYPESTACK_PEEK({isize}) : NULL", "PyTypeObject *") + else: + usable_for_local_effect[ieffect.name] = ieffect + src = StackEffect(f"TYPESTACK_PEEK({isize})", "PyTypeObject *") + out.declare(dst, src) + + # Write localarr effect + if self.local_effects: + idx = self.local_effects.index + val = self.local_effects.value + match val: + case LocalEffectVarLiteral(name=valstr): + if valstr != "NULL": valstr = f"&{valstr}" + case LocalEffectVarStack(name=valstr): + assert valstr in usable_for_local_effect, \ + "`cond` and `size` stackvar not supported for localeffect" + case _: + typing.assert_never(val) + out.emit(f"TYPELOCALS_SET({idx}, {valstr})") + + # Update stack size + out.stack_adjust( + 0, + [ieff for ieff in self.input_effects], + [oeff for oeff in self.output_effects], + ) + + # Stack effect + oeffects = list(reversed(self.output_effects)) + for i, oeffect in enumerate(oeffects): + osize = string_effect_size( + list_effect_size([oeff for oeff in oeffects[: i + 1]]) + ) + + # Check if it's even used + if oeffect.name == UNUSED: continue + + # Check if there's type info + if typ := oeffect.type_annotation: + match typ: + case StackVarTypeLiteral(literal=val): + if val != "NULL": val = f"&{val}" + case StackVarTypeIndex(array=arr, index=idx): + val = f"{'TYPELOCALS_GET' if arr == 'locals' else 'TYPECONST_GET'}({idx})" + case _: + typing.assert_never(typ) + if oeffect.cond: + out.emit(f"if ({oeffect.cond}) {{ TYPESTACK_POKE({osize}, {val}); }}") + else: + out.emit(f"TYPESTACK_POKE({osize}, {val});") + continue + + # Check if it's part of input effect + # TODO: Can we assume that they have the same type? + if oeffect.name in all_input_effect_names: + ieffect, j = all_input_effect_names[oeffect.name] + assert not ieffect.cond, \ + "`cond` stackvar not supported for type prop" + # The stack var stays at the same pos + if len(oeffects) - i == len(ieffects) - j: continue + if oeffect.cond: + out.emit(f"if ({oeffect.cond}) {{ TYPESTACK_POKE({osize}, {oeffect.name}); }}") + else: + out.emit(f"TYPESTACK_POKE({osize}, {oeffect.name});") + continue + + # Just output null + if oeffect.cond: + out.emit(f"if ({oeffect.cond}) {{ TYPESTACK_POKE({osize}, NULL); }}") + else: + out.emit(f"TYPESTACK_POKE({osize}, NULL);") + def write(self, out: Formatter) -> None: """Write one instruction, sans prologue and epilogue.""" # Write a static assertion that a family's cache size is correct @@ -483,6 +580,10 @@ def write_body(self, out: Formatter, cache_adjust: int) -> None: for var, oeffect in self.output_mapping: out.assign(var, oeffect) + def write_typeprop(self, out: Formatter) -> None: + with out.block(""): + self.instr.write_typeprop(out) + @dataclasses.dataclass class SuperOrMacroInstruction: @@ -1019,6 +1120,33 @@ def write_uopguard_typedata(self): self.out.emit(f"[{name}] = {{{', '.join(['&' + type_ for type_ in types])}}},") self.out.emit("};") + + def write_typepropagator(self) -> None: + """Write the type propagator""" + + with open(self.output_filename, "w") as f: + # Write provenance header + f.write(f"// This file is generated by {THIS} @TODO: make this a seperate argument\n") + f.write(f"// from {os.path.relpath(self.filename, ROOT).replace(os.path.sep, posixpath.sep)}\n") + f.write(f"// Do not edit!\n") + + # Create formatter + self.out = Formatter(f, 8) + + for thing in self.everything: + match thing: + case parser.InstDef(kind=kind, name=name): + match kind: + case "op": pass + case _: + self.write_instr_typeprop(self.instrs[name]) + case parser.Super(name=name): + self.write_super_typeprop(self.super_instrs[name]) + case parser.Macro(name=name): + self.write_macro_typeprop(self.macro_instrs[name]) + case _: + typing.assert_never(thing) + def write_metadata(self) -> None: """Write instruction metadata to output file.""" @@ -1237,6 +1365,31 @@ def write_macro(self, mac: MacroInstruction) -> None: f'{cache_adjust}, "incorrect cache size");' ) + def write_instr_typeprop(self, instr: Instruction) -> None: + name = instr.name + self.out.emit("") + with self.out.block(f"TARGET({name})"): + instr.write_typeprop(self.out) + self.out.emit("break;") + + def write_super_typeprop(self, sup: SuperInstruction) -> None: + # TODO: Support super instructions + # Currently not support because of the need for NEXTOPARG + ... + + def write_macro_typeprop(self, mac: MacroInstruction) -> None: + # TODO: Make the code emitted more efficient by + # combining stack effect + name = mac.name + self.out.emit("") + with self.out.block(f"TARGET({name})"): + for comp in mac.parts: + if not isinstance(comp, Component): continue + comp.write_typeprop(self.out) + self.out.emit("break;") + + + @contextlib.contextmanager def wrap_super_or_macro(self, up: SuperOrMacroInstruction): """Shared boilerplate for super- and macro instructions.""" @@ -1342,6 +1495,10 @@ def main(): # a.output_filename = TIER2_MACRO_TO_MICRO_MAP_OUTPUT # a.write_macromap_and_typedata() + # Quick hack. @TODO refactor + a.output_filename = TIER2_TYPE_PROPAGATOR_OUTPUT + a.write_typepropagator() + if __name__ == "__main__": main() diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index 2d9687a90e1646..14adf59640b1dd 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -336,7 +336,7 @@ def stackvar_type(self) -> StackVarType | None: if id := self.expect(lx.IDENTIFIER): idstr = id.text.strip() if not self.expect(lx.LBRACKET): - return StackVarTypeLiteral(idstr + " *") + return StackVarTypeLiteral(idstr) if idstr not in ["locals", "consts"]: return if id := self.expect(lx.IDENTIFIER): index = id.text.strip() From 19b80a81c0b04a8ba2b9376ace35eec9055d159f Mon Sep 17 00:00:00 2001 From: Julia Date: Wed, 1 Mar 2023 12:42:43 +0800 Subject: [PATCH 047/280] Refactor: Moved type_propagate to be with the _PyTier2TypeContext code In preparation for type propagating within the tier2 branch handling code --- Python/tier2.c | 69 +++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index 3e4c5ab0922ab2..e5d0d831c4fd12 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -92,6 +92,41 @@ _PyTier2TypeContext_free(_PyTier2TypeContext* type_context) { PyMem_Free(type_context); } +// Type propagates across a single function. +static void +type_propagate( + int opcode, int oparg, + PyTypeObject** type_stackptr, PyTypeObject** type_locals, + const PyObject* consts) +{ +#define TARGET(op) case op: +#define TYPESTACK_PEEK(idx) (type_stackptr[-(idx)]) +#define TYPESTACK_POKE(idx, v) type_stackptr[-(idx)] = (v) +#define TYPELOCALS_SET(idx, v) type_locals[idx] = v; +#define TYPELOCALS_GET(idx) (type_locals[idx]) +#define TYPECONST_GET(idx) Py_TYPE(_PyTuple_CAST(consts)->ob_item[(idx)]) +#define STACK_ADJUST(idx) type_stackptr += (idx) +#define STACK_GROW(idx) STACK_ADJUST((idx)) +#define STACK_SHRINK(idx) STACK_ADJUST(-(idx)) + + switch (opcode) { +#include "tier2_typepropagator.c.h" + default: + fprintf(stderr, "Unsupported opcode in type propagator: %d\n", opcode); + assert(opcode); + } + +#undef TARGET +#undef TYPESTACK_PEEK +#undef TYPESTACK_POKE +#undef TYPELOCALS_SET +#undef TYPELOCALS_GET +#undef TYPECONST_GET +#undef STACK_ADJUST +#undef STACK_GROW +#undef STACK_SHRINK +} + ////////// Utility functions // Gets end of the bytecode for a code object. @@ -590,40 +625,6 @@ add_metadata_to_jump_2d_array(_PyTier2Info *t2_info, _PyTier2BBMetadata *meta, return 0; } -static void -type_propagate( - int opcode, int oparg, - PyTypeObject** type_stackptr, PyTypeObject** type_locals, - const PyObject* consts) -{ -#define TARGET(op) case op: -#define TYPESTACK_PEEK(idx) (type_stackptr[-(idx)]) -#define TYPESTACK_POKE(idx, v) type_stackptr[-(idx)] = (v) -#define TYPELOCALS_SET(idx, v) type_locals[idx] = v; -#define TYPELOCALS_GET(idx) (type_locals[idx]) -#define TYPECONST_GET(idx) Py_TYPE(_PyTuple_CAST(consts)->ob_item[(idx)]) -#define STACK_ADJUST(idx) type_stackptr += (idx) -#define STACK_GROW(idx) STACK_ADJUST((idx)) -#define STACK_SHRINK(idx) STACK_ADJUST(-(idx)) - - switch (opcode) { -#include "tier2_typepropagator.c.h" - default: - fprintf(stderr, "Unsupported opcode in type propagator: %d\n", opcode); - assert(opcode); - } - -#undef TARGET -#undef TYPESTACK_PEEK -#undef TYPESTACK_POKE -#undef TYPELOCALS_SET -#undef TYPELOCALS_GET -#undef TYPECONST_GET -#undef STACK_ADJUST -#undef STACK_GROW -#undef STACK_SHRINK -} - // Detects a BB from the current instruction start to the end of the first basic block it sees. // Then emits the instructions into the bb space. // From a349f1606716353bb5cf772c76ed99f5efc722d0 Mon Sep 17 00:00:00 2001 From: Julia Date: Wed, 1 Mar 2023 23:53:12 +0800 Subject: [PATCH 048/280] Refactor: Added tier2_typepropagator.c.h as generated in .gitattributes --- .gitattributes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index c26944b3387c78..35d81d575bf1e1 100644 --- a/.gitattributes +++ b/.gitattributes @@ -83,7 +83,7 @@ Parser/token.c generated Programs/test_frozenmain.h generated Python/Python-ast.c generated Python/generated_cases.c.h generated -Python/tier2_metainterpreter.c.h generated +Python/tier2_typepropagator.c.h generated Python/opcode_targets.h generated Python/stdlib_module_names.h generated Tools/peg_generator/pegen/grammar_parser.py generated From 1b2d4a428b421c4e6e93e8972321ec5582b480ac Mon Sep 17 00:00:00 2001 From: Julia Date: Thu, 2 Mar 2023 00:02:11 +0800 Subject: [PATCH 049/280] Feat: Handled type propagation across the tier2 branching logic --- Include/internal/pycore_code.h | 2 +- Python/bytecodes.c | 22 ++++- Python/ceval.c | 5 ++ Python/generated_cases.c.h | 20 ++++- Python/tier2.c | 107 +++++++++++++++++++----- Python/tier2_typepropagator.c.h | 20 ++--- Tools/cases_generator/generate_cases.py | 16 ++++ 7 files changed, 151 insertions(+), 41 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 914c0c03e95c9b..5ca88116a31b42 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -259,7 +259,7 @@ extern _Py_CODEUNIT *_PyCode_Tier2Warmup(struct _PyInterpreterFrame *, _Py_CODEUNIT *); extern _Py_CODEUNIT *_PyTier2_GenerateNextBB( struct _PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, - _Py_CODEUNIT **tier1_fallback); + _Py_CODEUNIT **tier1_fallback, char gen_bb_requires_pop); extern _Py_CODEUNIT *_PyTier2_LocateJumpBackwardsBB( struct _PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, _Py_CODEUNIT **tier1_fallback); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index ea81270e9791f8..bdd5173dc68fb2 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2084,6 +2084,10 @@ dummy_func( goto error; } } + // This gets set so BRANCH_BB knows whether to pop + // the type stack (type propagation) when generating the + // target BB + gen_bb_requires_pop = jump; } inst(JUMP_IF_TRUE_OR_POP, (cond -- cond if (jump))) { @@ -2136,6 +2140,10 @@ dummy_func( goto error; } } + // This gets set so BRANCH_BB knows whether to pop + // the type stack (type propagation) when generating the + // target BB + gen_bb_requires_pop = jump; } inst(JUMP_BACKWARD_NO_INTERRUPT, (--)) { @@ -3284,6 +3292,7 @@ dummy_func( } // Tier 2 instructions + // Type propagator assumes this doesn't affect type context inst(BB_BRANCH, (unused/1 --)) { _Py_CODEUNIT *t2_nextinstr = NULL; _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; @@ -3293,7 +3302,8 @@ dummy_func( _py_set_opcode(next_instr - 1, BB_BRANCH_IF_FLAG_UNSET); // Generate consequent. t2_nextinstr = _PyTier2_GenerateNextBB( - frame, cache->bb_id, 0, &tier1_fallback); + frame, cache->bb_id, 0, &tier1_fallback, gen_bb_requires_pop); + gen_bb_requires_pop = false; if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; @@ -3305,7 +3315,8 @@ dummy_func( _py_set_opcode(next_instr - 1, BB_BRANCH_IF_FLAG_SET); // Generate predicate. t2_nextinstr = _PyTier2_GenerateNextBB( - frame, cache->bb_id, oparg, &tier1_fallback); + frame, cache->bb_id, oparg, &tier1_fallback, gen_bb_requires_pop); + gen_bb_requires_pop = false; if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback + oparg; @@ -3327,7 +3338,8 @@ dummy_func( _Py_CODEUNIT *tier1_fallback = NULL; t2_nextinstr = _PyTier2_GenerateNextBB( - frame, cache->bb_id, oparg, &tier1_fallback); + frame, cache->bb_id, oparg, &tier1_fallback, gen_bb_requires_pop); + gen_bb_requires_pop = false; if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; @@ -3358,7 +3370,8 @@ dummy_func( // @TODO: Rewrite TEST intruction above to a JUMP above.. t2_nextinstr = _PyTier2_GenerateNextBB( - frame, cache->bb_id, oparg, &tier1_fallback); + frame, cache->bb_id, oparg, &tier1_fallback, gen_bb_requires_pop); + gen_bb_requires_pop = false; if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; @@ -3379,6 +3392,7 @@ dummy_func( // Fall through to next instruction. } + // Type propagator assumes this doesn't affect type context inst(BB_JUMP_BACKWARD_LAZY, (--)) { _Py_CODEUNIT *curr = next_instr - 1; _Py_CODEUNIT *t2_nextinstr = NULL; diff --git a/Python/ceval.c b/Python/ceval.c index 7d0f7a8813411f..9f30fbefb92cd8 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -729,6 +729,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int // true = successor // false = alternate bool bb_test = true; + // For tier2 type propagation, handling of jump instructions with + // runtime-dependent stack effect. + // This flag is used to determine if the type context of a new bb + // requires a stack element to be popped. + bool gen_bb_requires_pop = false; /* WARNING: Because the _PyCFrame lives on the C stack, * but can be accessed from a heap allocated object (tstate) diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 2f7d223618a6ac..ba0aa72c68f22d 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2643,6 +2643,10 @@ goto error; } } + // This gets set so BRANCH_BB knows whether to pop + // the type stack (type propagation) when generating the + // target BB + gen_bb_requires_pop = jump; STACK_SHRINK(1); STACK_GROW((jump ? 1 : 0)); DISPATCH(); @@ -2703,6 +2707,10 @@ goto error; } } + // This gets set so BRANCH_BB knows whether to pop + // the type stack (type propagation) when generating the + // target BB + gen_bb_requires_pop = jump; STACK_SHRINK(1); STACK_GROW((jump ? 1 : 0)); DISPATCH(); @@ -4129,7 +4137,8 @@ _py_set_opcode(next_instr - 1, BB_BRANCH_IF_FLAG_UNSET); // Generate consequent. t2_nextinstr = _PyTier2_GenerateNextBB( - frame, cache->bb_id, 0, &tier1_fallback); + frame, cache->bb_id, 0, &tier1_fallback, gen_bb_requires_pop); + gen_bb_requires_pop = false; if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; @@ -4141,7 +4150,8 @@ _py_set_opcode(next_instr - 1, BB_BRANCH_IF_FLAG_SET); // Generate predicate. t2_nextinstr = _PyTier2_GenerateNextBB( - frame, cache->bb_id, oparg, &tier1_fallback); + frame, cache->bb_id, oparg, &tier1_fallback, gen_bb_requires_pop); + gen_bb_requires_pop = false; if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback + oparg; @@ -4163,7 +4173,8 @@ _Py_CODEUNIT *tier1_fallback = NULL; t2_nextinstr = _PyTier2_GenerateNextBB( - frame, cache->bb_id, oparg, &tier1_fallback); + frame, cache->bb_id, oparg, &tier1_fallback, gen_bb_requires_pop); + gen_bb_requires_pop = false; if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; @@ -4198,7 +4209,8 @@ // @TODO: Rewrite TEST intruction above to a JUMP above.. t2_nextinstr = _PyTier2_GenerateNextBB( - frame, cache->bb_id, oparg, &tier1_fallback); + frame, cache->bb_id, oparg, &tier1_fallback, gen_bb_requires_pop); + gen_bb_requires_pop = false; if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; diff --git a/Python/tier2.c b/Python/tier2.c index e5d0d831c4fd12..569ce794859388 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -9,11 +9,13 @@ #include "opcode.h" #define BB_DEBUG 1 +#define TYPEPROP_DEBUG 1 // Max typed version basic blocks per basic block #define MAX_BB_VERSIONS 5 // Number of potential extra instructions at end of a BB, for branch or cleanup purposes. #define BB_EPILOG 0 + static inline int IS_SCOPE_EXIT_OPCODE(int opcode); @@ -22,6 +24,10 @@ static inline int IS_SCOPE_EXIT_OPCODE(int opcode); static _PyTier2TypeContext * initialize_type_context(const PyCodeObject *co) { +#if TYPEPROP_DEBUG + fprintf(stderr, " [*] Initialize type context\n"); +#endif + int nlocals = co->co_nlocals; int nstack = co->co_stacksize; @@ -56,6 +62,10 @@ initialize_type_context(const PyCodeObject *co) { static _PyTier2TypeContext * _PyTier2TypeContext_copy(const _PyTier2TypeContext* type_context) { +#if TYPEPROP_DEBUG + fprintf(stderr, " [*] Copying type context\n"); +#endif + int nlocals = type_context->type_locals_len; int nstack = type_context->type_stack_len; @@ -82,11 +92,17 @@ _PyTier2TypeContext_copy(const _PyTier2TypeContext* type_context) { new_type_context->type_stack_len = nstack; new_type_context->type_locals = type_locals; new_type_context->type_stack = type_stack; + new_type_context->type_stack_ptr = type_stack - type_context->type_stack + type_context->type_stack_ptr; return new_type_context; } static void _PyTier2TypeContext_free(_PyTier2TypeContext* type_context) { + +#if TYPEPROP_DEBUG + fprintf(stderr, " [*] Freeing type context\n"); +#endif + PyMem_Free(type_context->type_locals); PyMem_Free(type_context->type_stack); PyMem_Free(type_context); @@ -96,9 +112,13 @@ _PyTier2TypeContext_free(_PyTier2TypeContext* type_context) { static void type_propagate( int opcode, int oparg, - PyTypeObject** type_stackptr, PyTypeObject** type_locals, + _PyTier2TypeContext* type_context, const PyObject* consts) { + PyTypeObject** type_stack = type_context->type_stack; + PyTypeObject** type_locals = type_context->type_locals; + PyTypeObject** type_stackptr = type_context->type_stack_ptr; + #define TARGET(op) case op: #define TYPESTACK_PEEK(idx) (type_stackptr[-(idx)]) #define TYPESTACK_POKE(idx, v) type_stackptr[-(idx)] = (v) @@ -109,13 +129,26 @@ type_propagate( #define STACK_GROW(idx) STACK_ADJUST((idx)) #define STACK_SHRINK(idx) STACK_ADJUST(-(idx)) +#ifdef TYPEPROP_DEBUG + fprintf(stderr, " [-] Type stack bef: %llu\n", ((uint64_t)type_stackptr - (uint64_t)type_stack)/sizeof(PyTypeObject*)); +#ifdef Py_DEBUG + fprintf(stderr, " [-] Type propagating across: %s : %d\n", _PyOpcode_OpName[opcode], oparg); +#endif +#endif + switch (opcode) { #include "tier2_typepropagator.c.h" default: fprintf(stderr, "Unsupported opcode in type propagator: %d\n", opcode); - assert(opcode); + Py_UNREACHABLE(); } +#ifdef TYPEPROP_DEBUG + fprintf(stderr, " [-] Type stack aft: %llu\n", ((uint64_t)type_stackptr - (uint64_t)type_stack) / sizeof(PyTypeObject*)); +#endif + + type_context->type_stack_ptr = type_stackptr; + #undef TARGET #undef TYPESTACK_PEEK #undef TYPESTACK_POKE @@ -415,7 +448,7 @@ emit_type_guard(_Py_CODEUNIT *write_curr, _Py_CODEUNIT guard, int bb_id) // Converts the tier 1 branch bytecode to tier 2 branch bytecode. static inline _Py_CODEUNIT * -emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) +emit_logical_branch(_PyTier2TypeContext* type_context, _Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) { int opcode; int oparg = _Py_OPARG(branch); @@ -427,27 +460,38 @@ emit_logical_branch(_Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) // Subsequent jumps don't need to check this anymore. They can just // jump directly with JUMP_BACKWARD. opcode = BB_JUMP_BACKWARD_LAZY; + // v BB_JUMP_BACKWARD_LAZY has nothing to propagate + // type_propagate(opcode, oparg, type_context, NULL); break; case FOR_ITER: opcode = BB_TEST_ITER; + type_propagate(opcode, oparg, type_context, NULL); break; case JUMP_IF_FALSE_OR_POP: opcode = BB_TEST_IF_FALSE_OR_POP; + // This inst has conditional stack effect according to whether the branch is taken. + // This inst sets the `gen_bb_requires_pop` flag to handle stack effect of this opcode in BB_BRANCH break; case JUMP_IF_TRUE_OR_POP: opcode = BB_TEST_IF_TRUE_OR_POP; + // This inst has conditional stack effect according to whether the branch is taken. + // This inst sets the `gen_bb_requires_pop` flag to handle stack effect of this opcode in BB_BRANCH break; case POP_JUMP_IF_FALSE: opcode = BB_TEST_POP_IF_FALSE; + type_propagate(opcode, oparg, type_context, NULL); break; case POP_JUMP_IF_TRUE: opcode = BB_TEST_POP_IF_TRUE; + type_propagate(opcode, oparg, type_context, NULL); break; case POP_JUMP_IF_NOT_NONE: opcode = BB_TEST_POP_IF_NOT_NONE; + type_propagate(opcode, oparg, type_context, NULL); break; case POP_JUMP_IF_NONE: opcode = BB_TEST_POP_IF_NONE; + type_propagate(opcode, oparg, type_context, NULL); break; default: // Honestly shouldn't happen because branches that @@ -639,15 +683,16 @@ add_metadata_to_jump_2d_array(_PyTier2Info *t2_info, _PyTier2BBMetadata *meta, _PyTier2BBMetadata * _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, _Py_CODEUNIT *tier1_start, - // Const qualifier as this function makes a copy of the type_context - const _PyTier2TypeContext *type_context) + // starting_type_context will be modified in this function, + // do make a copy if needed before calling this function + _PyTier2TypeContext *starting_type_context) { #define END() goto end; #define JUMPBY(x) i += x + 1; #define DISPATCH() write_i = emit_i(write_i, opcode, oparg); \ write_i = copy_cache_entries(write_i, curr+1, caches); \ i += caches; \ - type_propagate(opcode, oparg, type_stackptr, type_locals, consts); \ + type_propagate(opcode, oparg, starting_type_context, consts); \ continue; #define DISPATCH_GOTO() goto dispatch_opcode; @@ -657,12 +702,6 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // 1. If there's a branch instruction / scope exit. // 2. If there's a type guard. - // Make a copy of the type context - _PyTier2TypeContext *type_context_copy = _PyTier2TypeContext_copy(type_context); - if (type_context_copy == NULL) { - return NULL; - } - _PyTier2BBMetadata *meta = NULL; _PyTier2BBMetadata *temp_meta = NULL; @@ -670,9 +709,6 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, PyObject *consts = co->co_consts; _Py_CODEUNIT *t2_start = (_Py_CODEUNIT *)(((char *)bb_space->u_code) + bb_space->water_level); _Py_CODEUNIT *write_i = t2_start; - PyTypeObject **type_stack = type_context_copy->type_stack; - PyTypeObject **type_locals = type_context_copy->type_locals; - PyTypeObject **type_stackptr = type_context_copy->type_stack_ptr; int tos = -1; // For handling of backwards jumps @@ -711,7 +747,9 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, t2_start++; DISPATCH(); default: +#if BB_DEBUG || TYPEPROP_DEBUG fprintf(stderr, "offset: %Id\n", curr - _PyCode_CODE(co)); +#endif if (IS_BACKWARDS_JUMP_TARGET(co, curr)) { #if BB_DEBUG fprintf(stderr, "Encountered a backward jump target\n"); @@ -730,6 +768,11 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // Else, create a virtual end to the basic block. // But generate the block after that so it can fall through. i--; + // Make a copy of the type context + _PyTier2TypeContext *type_context_copy = _PyTier2TypeContext_copy(starting_type_context); + if (type_context_copy == NULL) { + return NULL; + } meta = _PyTier2_AllocateBBMetaData(co, t2_start, _PyCode_CODE(co) + i, type_context_copy); if (meta == NULL) { @@ -762,7 +805,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, } // Get the BB ID without incrementing it. // AllocateBBMetaData will increment. - write_i = emit_logical_branch(write_i, *curr, + write_i = emit_logical_branch(starting_type_context, write_i, *curr, co->_tier2_info->bb_data_curr); i += caches; END(); @@ -773,9 +816,19 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, } end: // Create the tier 2 BB + + // Make a copy of the type context + _PyTier2TypeContext *type_context_copy = _PyTier2TypeContext_copy(starting_type_context); + if (type_context_copy == NULL) { + return NULL; + } temp_meta = _PyTier2_AllocateBBMetaData(co, t2_start, // + 1 because we want to start with the NEXT instruction for the scan _PyCode_CODE(co) + i + 1, type_context_copy); + if (temp_meta == NULL) { + _PyTier2TypeContext_free(type_context_copy); + return NULL; + } // We need to return the first block to enter into. If there is already a block generated // before us, then we use that instead of the most recent block. if (meta == NULL) { @@ -785,7 +838,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // Add the basic block to the jump ids if (add_metadata_to_jump_2d_array(t2_info, temp_meta, backwards_jump_target_offset) < 0) { PyMem_Free(meta); - PyMem_Free(temp_meta); + if (meta != temp_meta) PyMem_Free(temp_meta); _PyTier2TypeContext_free(type_context_copy); return NULL; } @@ -1103,7 +1156,7 @@ _PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) // The second basic block created will always require a jump. _Py_CODEUNIT * _PyTier2_GenerateNextBB(_PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, - _Py_CODEUNIT **tier1_fallback) + _Py_CODEUNIT **tier1_fallback, char gen_bb_requires_pop) { PyCodeObject *co = frame->f_code; assert(co->_tier2_info != NULL); @@ -1122,10 +1175,22 @@ _PyTier2_GenerateNextBB(_PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, } // Get type_context of previous BB _PyTier2TypeContext *type_context = meta->type_context; + // Make a copy of the type context + _PyTier2TypeContext* type_context_copy = _PyTier2TypeContext_copy(type_context); + if (type_context_copy == NULL) { + return NULL; + } + // If this flag is set, it means that either BB_TEST_IF_FALSE_OR_POP or + // BB_TEST_IF_TRUE_OR_POP was ran and the conditional stack effect was performed + // This means we have to pop an element from the type stack. + if (gen_bb_requires_pop) { + type_context_copy->type_stack_ptr--; + } _PyTier2BBMetadata *metadata = _PyTier2_Code_DetectAndEmitBB( frame->f_code, space, tier1_end, - type_context); + type_context_copy); if (metadata == NULL) { + _PyTier2TypeContext_free(type_context_copy); return NULL; } return metadata->tier2_start; @@ -1170,8 +1235,8 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id, int j for (int x = 0; x < MAX_BB_VERSIONS; x++) { #if BB_DEBUG fprintf(stderr, "jump target BB ID: %d\n", -#endif t2_info->backward_jump_target_bb_ids[i][x]); +#endif // @TODO, this is where the diff function is supposed to be // it will calculate the closest type context BB // For now just any valid BB (>= 0) is used. @@ -1185,7 +1250,9 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id, int j } assert(matching_bb_id >= 0); assert(matching_bb_id <= t2_info->bb_data_curr); +#if BB_DEBUG fprintf(stderr, "Found jump target BB ID: %d\n", matching_bb_id); +#endif _PyTier2BBMetadata *target_metadata = t2_info->bb_data[matching_bb_id]; return target_metadata->tier2_start; } diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index fb7ee319f35d83..786eff5afbcf23 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -829,30 +829,26 @@ } TARGET(JUMP_IF_FALSE_OR_POP) { - PyTypeObject *cond = TYPESTACK_PEEK(1); - STACK_SHRINK(1); - STACK_GROW((jump ? 1 : 0)); + fprintf(stderr, "Type propagation across `{self.name}` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } TARGET(BB_TEST_IF_FALSE_OR_POP) { - PyTypeObject *cond = TYPESTACK_PEEK(1); - STACK_SHRINK(1); - STACK_GROW((jump ? 1 : 0)); + fprintf(stderr, "Type propagation across `{self.name}` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } TARGET(JUMP_IF_TRUE_OR_POP) { - PyTypeObject *cond = TYPESTACK_PEEK(1); - STACK_SHRINK(1); - STACK_GROW((jump ? 1 : 0)); + fprintf(stderr, "Type propagation across `{self.name}` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } TARGET(BB_TEST_IF_TRUE_OR_POP) { - PyTypeObject *cond = TYPESTACK_PEEK(1); - STACK_SHRINK(1); - STACK_GROW((jump ? 1 : 0)); + fprintf(stderr, "Type propagation across `{self.name}` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 479ee2a8977b3f..3c37a47d21c2cf 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -49,6 +49,17 @@ UNUSED = "unused" BITS_PER_CODE_UNIT = 16 +# Type propagation across these instructions are forbidden +# due to conditional effects that can't be determined statically +# The handling of type propagation across these opcodes are handled elsewhere +# within tier2. +TYPE_PROPAGATOR_FORBIDDEN = [ + "JUMP_IF_FALSE_OR_POP", + "JUMP_IF_TRUE_OR_POP", # Type propagator shouldn't see these + "BB_TEST_IF_FALSE_OR_POP", + "BB_TEST_IF_TRUE_OR_POP" # Type propagator handles this in BB_BRANCH +] + arg_parser = argparse.ArgumentParser( description="Generate the code for the interpreter switch.", formatter_class=argparse.ArgumentDefaultsHelpFormatter, @@ -305,6 +316,11 @@ def analyze_registers(self, a: "Analyzer") -> None: def write_typeprop(self, out: Formatter) -> None: """Write one instruction's type propagation rules""" + if self.name in TYPE_PROPAGATOR_FORBIDDEN: + out.emit('fprintf(stderr, "Type propagation across `{self.name}` shouldn\'t be handled statically!\\n");') + out.emit("Py_UNREACHABLE();") + return + # Write input stack effect variable declarations and initializations ieffects = list(reversed(self.input_effects)) usable_for_local_effect = {} From 337720b095dcde838f9acdc637c9826013c0aa55 Mon Sep 17 00:00:00 2001 From: Julia Date: Thu, 2 Mar 2023 14:36:15 +0800 Subject: [PATCH 050/280] Fix: Wrong behaviour of gen_bb_requires_pop --- Python/bytecodes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index bdd5173dc68fb2..59f3db48f80283 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2087,7 +2087,7 @@ dummy_func( // This gets set so BRANCH_BB knows whether to pop // the type stack (type propagation) when generating the // target BB - gen_bb_requires_pop = jump; + gen_bb_requires_pop = !jump; } inst(JUMP_IF_TRUE_OR_POP, (cond -- cond if (jump))) { @@ -2143,7 +2143,7 @@ dummy_func( // This gets set so BRANCH_BB knows whether to pop // the type stack (type propagation) when generating the // target BB - gen_bb_requires_pop = jump; + gen_bb_requires_pop = !jump; } inst(JUMP_BACKWARD_NO_INTERRUPT, (--)) { From 17b09caf86aec0b1c00f82595339833f57a5dc7e Mon Sep 17 00:00:00 2001 From: Julia Date: Thu, 2 Mar 2023 15:35:11 +0800 Subject: [PATCH 051/280] Style: Reformatted to follow CPython's style guide --- Python/tier2.c | 89 +++++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index 569ce794859388..62384f90e5c419 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -22,7 +22,8 @@ static inline int IS_SCOPE_EXIT_OPCODE(int opcode); ////////// TYPE CONTEXT FUNCTIONS static _PyTier2TypeContext * -initialize_type_context(const PyCodeObject *co) { +initialize_type_context(const PyCodeObject *co) +{ #if TYPEPROP_DEBUG fprintf(stderr, " [*] Initialize type context\n"); @@ -42,8 +43,12 @@ initialize_type_context(const PyCodeObject *co) { } // Initialize to unknown type. - for (int i = 0; i < nlocals; i++) type_locals[i] = NULL; - for (int i = 0; i < nstack; i++) type_stack[i] = NULL; + for (int i = 0; i < nlocals; i++) { + type_locals[i] = NULL; + } + for (int i = 0; i < nstack; i++) { + type_stack[i] = NULL; + } _PyTier2TypeContext *type_context = PyMem_Malloc(sizeof(_PyTier2TypeContext)); if (type_context == NULL) { @@ -60,7 +65,8 @@ initialize_type_context(const PyCodeObject *co) { } static _PyTier2TypeContext * -_PyTier2TypeContext_copy(const _PyTier2TypeContext* type_context) { +_PyTier2TypeContext_copy(const _PyTier2TypeContext *type_context) +{ #if TYPEPROP_DEBUG fprintf(stderr, " [*] Copying type context\n"); @@ -69,20 +75,20 @@ _PyTier2TypeContext_copy(const _PyTier2TypeContext* type_context) { int nlocals = type_context->type_locals_len; int nstack = type_context->type_stack_len; - PyTypeObject** type_locals = PyMem_Malloc(nlocals * sizeof(PyTypeObject*)); + PyTypeObject **type_locals = PyMem_Malloc(nlocals * sizeof(PyTypeObject *)); if (type_locals == NULL) { return NULL; } - PyTypeObject** type_stack = PyMem_Malloc(nstack * sizeof(PyTypeObject*)); + PyTypeObject **type_stack = PyMem_Malloc(nstack * sizeof(PyTypeObject *)); if (type_stack == NULL) { PyMem_Free(type_locals); return NULL; } - memcpy(type_locals, type_context->type_locals, nlocals * sizeof(PyTypeObject*)); - memcpy(type_stack, type_context->type_stack, nstack * sizeof(PyTypeObject*)); + memcpy(type_locals, type_context->type_locals, nlocals * sizeof(PyTypeObject *)); + memcpy(type_stack, type_context->type_stack, nstack * sizeof(PyTypeObject *)); - _PyTier2TypeContext* new_type_context = PyMem_Malloc(sizeof(_PyTier2TypeContext)); + _PyTier2TypeContext *new_type_context = PyMem_Malloc(sizeof(_PyTier2TypeContext)); if (new_type_context == NULL) { PyMem_Free(type_locals); PyMem_Free(type_stack); @@ -97,7 +103,8 @@ _PyTier2TypeContext_copy(const _PyTier2TypeContext* type_context) { } static void -_PyTier2TypeContext_free(_PyTier2TypeContext* type_context) { +_PyTier2TypeContext_free(_PyTier2TypeContext *type_context) +{ #if TYPEPROP_DEBUG fprintf(stderr, " [*] Freeing type context\n"); @@ -112,12 +119,12 @@ _PyTier2TypeContext_free(_PyTier2TypeContext* type_context) { static void type_propagate( int opcode, int oparg, - _PyTier2TypeContext* type_context, - const PyObject* consts) + _PyTier2TypeContext *type_context, + const PyObject *consts) { - PyTypeObject** type_stack = type_context->type_stack; - PyTypeObject** type_locals = type_context->type_locals; - PyTypeObject** type_stackptr = type_context->type_stack_ptr; + PyTypeObject **type_stack = type_context->type_stack; + PyTypeObject **type_locals = type_context->type_locals; + PyTypeObject **type_stackptr = type_context->type_stack_ptr; #define TARGET(op) case op: #define TYPESTACK_PEEK(idx) (type_stackptr[-(idx)]) @@ -130,7 +137,7 @@ type_propagate( #define STACK_SHRINK(idx) STACK_ADJUST(-(idx)) #ifdef TYPEPROP_DEBUG - fprintf(stderr, " [-] Type stack bef: %llu\n", ((uint64_t)type_stackptr - (uint64_t)type_stack)/sizeof(PyTypeObject*)); + fprintf(stderr, " [-] Type stack bef: %llu\n", ((uint64_t)type_stackptr - (uint64_t)type_stack) / sizeof(PyTypeObject *)); #ifdef Py_DEBUG fprintf(stderr, " [-] Type propagating across: %s : %d\n", _PyOpcode_OpName[opcode], oparg); #endif @@ -144,7 +151,7 @@ type_propagate( } #ifdef TYPEPROP_DEBUG - fprintf(stderr, " [-] Type stack aft: %llu\n", ((uint64_t)type_stackptr - (uint64_t)type_stack) / sizeof(PyTypeObject*)); + fprintf(stderr, " [-] Type stack aft: %llu\n", ((uint64_t)type_stackptr - (uint64_t)type_stack) / sizeof(PyTypeObject *)); #endif type_context->type_stack_ptr = type_stackptr; @@ -322,7 +329,7 @@ IS_JREL_OPCODE(int opcode) case JUMP_FORWARD: case JUMP_IF_FALSE_OR_POP: case JUMP_IF_TRUE_OR_POP: - // These two tend to be after a COMPARE_AND_BRANCH. + // These two tend to be after a COMPARE_AND_BRANCH. case POP_JUMP_IF_FALSE: case POP_JUMP_IF_TRUE: case SEND: @@ -389,27 +396,27 @@ static inline int IS_FORBIDDEN_OPCODE(int opcode) { switch (opcode) { - // Generators and coroutines + // Generators and coroutines case SEND: case YIELD_VALUE: - // Raise keyword + // Raise keyword case RAISE_VARARGS: - // Exceptions, we could support these theoretically. - // Just too much work for now + // Exceptions, we could support these theoretically. + // Just too much work for now case PUSH_EXC_INFO: case RERAISE: case POP_EXCEPT: - // Closures + // Closures case LOAD_DEREF: case MAKE_CELL: - // DELETE_FAST + // DELETE_FAST case DELETE_FAST: - // Pattern matching + // Pattern matching case MATCH_MAPPING: case MATCH_SEQUENCE: case MATCH_KEYS: - // Too large arguments, we can handle this, just - // increases complexity + // Too large arguments, we can handle this, just + // increases complexity case EXTENDED_ARG: return 1; @@ -448,7 +455,7 @@ emit_type_guard(_Py_CODEUNIT *write_curr, _Py_CODEUNIT guard, int bb_id) // Converts the tier 1 branch bytecode to tier 2 branch bytecode. static inline _Py_CODEUNIT * -emit_logical_branch(_PyTier2TypeContext* type_context, _Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) +emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) { int opcode; int oparg = _Py_OPARG(branch); @@ -696,7 +703,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, continue; #define DISPATCH_GOTO() goto dispatch_opcode; - + assert(co->_tier2_info != NULL); // There are only two cases that a BB ends. // 1. If there's a branch instruction / scope exit. @@ -730,7 +737,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // int how_many_guards = 0; // _Py_CODEUNIT guard_instr; // _Py_CODEUNIT action; - + dispatch_opcode: switch (opcode) { case RESUME: @@ -823,8 +830,8 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, return NULL; } temp_meta = _PyTier2_AllocateBBMetaData(co, t2_start, - // + 1 because we want to start with the NEXT instruction for the scan - _PyCode_CODE(co) + i + 1, type_context_copy); + // + 1 because we want to start with the NEXT instruction for the scan + _PyCode_CODE(co) + i + 1, type_context_copy); if (temp_meta == NULL) { _PyTier2TypeContext_free(type_context_copy); return NULL; @@ -838,7 +845,9 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // Add the basic block to the jump ids if (add_metadata_to_jump_2d_array(t2_info, temp_meta, backwards_jump_target_offset) < 0) { PyMem_Free(meta); - if (meta != temp_meta) PyMem_Free(temp_meta); + if (meta != temp_meta) { + PyMem_Free(temp_meta); + } _PyTier2TypeContext_free(type_context_copy); return NULL; } @@ -875,7 +884,7 @@ allocate_jump_offset_2d_array(int backwards_jump_count, int **backward_jump_targ for (int i = 0; i < MAX_BB_VERSIONS; i++) { jump_offsets[i] = -1; } - done++; + done++; backward_jump_target_bb_ids[i] = jump_offsets; } return 0; @@ -949,8 +958,8 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) i += _PyOpcode_Caches[opcode]; } assert(curr_i == backwards_jump_count); - qsort(backward_jump_offsets,backwards_jump_count, - sizeof(int), compare_ints); + qsort(backward_jump_offsets, backwards_jump_count, + sizeof(int), compare_ints); #if BB_DEBUG fprintf(stderr, "BACKWARD JUMP COUNT : %Id\n", backwards_jump_count); fprintf(stderr, "BACKWARD JUMP TARGET OFFSETS (FROM START OF CODE): "); @@ -985,7 +994,7 @@ _PyTier2Info_Initialize(PyCodeObject *co) t2_info->bb_data_curr = 0; Py_ssize_t bb_data_len = (Py_SIZE(co) / 5 + 1); assert((int)bb_data_len == bb_data_len); - _PyTier2BBMetadata **bb_data = PyMem_Calloc(bb_data_len, sizeof(_PyTier2BBMetadata*)); + _PyTier2BBMetadata **bb_data = PyMem_Calloc(bb_data_len, sizeof(_PyTier2BBMetadata *)); if (bb_data == NULL) { PyMem_Free(t2_info); return NULL; @@ -1114,7 +1123,7 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) fprintf(stderr, "ENTRY BB END IS: %d\n", (int)(meta->tier1_end - _PyCode_CODE(co))); #endif - + t2_info->_entry_bb = meta; // SET THE FRAME INFO @@ -1176,7 +1185,7 @@ _PyTier2_GenerateNextBB(_PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, // Get type_context of previous BB _PyTier2TypeContext *type_context = meta->type_context; // Make a copy of the type context - _PyTier2TypeContext* type_context_copy = _PyTier2TypeContext_copy(type_context); + _PyTier2TypeContext *type_context_copy = _PyTier2TypeContext_copy(type_context); if (type_context_copy == NULL) { return NULL; } @@ -1218,7 +1227,7 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id, int j } // Get type_context of previous BB - _PyTier2TypeContext* type_context = meta->type_context; + _PyTier2TypeContext *type_context = meta->type_context; // Now, find the matching BB _PyTier2Info *t2_info = co->_tier2_info; int jump_offset = (int)(tier1_jump_target - _PyCode_CODE(co)); From 579c2d68c4c51a8a642101a039d9d4b8b53dce2a Mon Sep 17 00:00:00 2001 From: Jules <57632293+JuliaPoo@users.noreply.github.com> Date: Thu, 2 Mar 2023 15:38:17 +0800 Subject: [PATCH 052/280] Update Tools/cases_generator/parser.py Co-authored-by: Ken Jin --- Tools/cases_generator/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index 14adf59640b1dd..49f563b0628416 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -75,7 +75,7 @@ class StackVarTypeLiteral(Node): @dataclass class StackVarTypeIndex(Node): - array: Literal["locals"] | Literal["consts"] + array: Literal["locals", "consts"] index: str From 80b9cbe4b584fe349a366a9314af597c9bf1f773 Mon Sep 17 00:00:00 2001 From: Jules <57632293+JuliaPoo@users.noreply.github.com> Date: Thu, 2 Mar 2023 15:38:42 +0800 Subject: [PATCH 053/280] Update Tools/cases_generator/parser.py Co-authored-by: Ken Jin --- Tools/cases_generator/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index 49f563b0628416..1e66bf71bb7a36 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -79,7 +79,7 @@ class StackVarTypeIndex(Node): index: str -StackVarType = StackVarTypeLiteral | StackVarTypeIndex +StackVarType: TypeAlias = StackVarTypeLiteral | StackVarTypeIndex @dataclass From 5c5db523b0723f34bde90b69b7f22674644537f2 Mon Sep 17 00:00:00 2001 From: Jules <57632293+JuliaPoo@users.noreply.github.com> Date: Thu, 2 Mar 2023 15:39:33 +0800 Subject: [PATCH 054/280] Update Tools/cases_generator/parser.py Co-authored-by: Ken Jin --- Tools/cases_generator/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index 1e66bf71bb7a36..d81a9eefd529c3 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -113,7 +113,7 @@ class LocalEffectVarStack(Node): name: str -LocalEffectVar = LocalEffectVarLiteral | LocalEffectVarStack +LocalEffectVar: TypeAlias = LocalEffectVarLiteral | LocalEffectVarStack @dataclass From f17dd5f82f394d54f7596d6ae0001de880a0ebc9 Mon Sep 17 00:00:00 2001 From: Julia Date: Thu, 2 Mar 2023 15:43:47 +0800 Subject: [PATCH 055/280] Refactor: Change shadowed builtins `type` in parser.py --- Tools/cases_generator/parser.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index 14adf59640b1dd..5655dc0be76e9d 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -307,7 +307,7 @@ def stack_effect(self) -> StackEffect | None: # IDENTIFIER [':' IDENTIFIER] ['if' '(' expression ')'] # | IDENTIFIER '[' expression ']' if tkn := self.expect(lx.IDENTIFIER): - type = "" + _type = "" has_type_annotation = False type_annotation = None if self.expect(lx.COLON): @@ -327,9 +327,9 @@ def stack_effect(self) -> StackEffect | None: if not (size := self.expression()): raise self.make_syntax_error("Expected expression") self.require(lx.RBRACKET) - type = "PyObject **" + _type = "PyObject **" size_text = size.text.strip() - return StackEffect(tkn.text, type, type_annotation, cond_text, size_text) + return StackEffect(tkn.text, _type, type_annotation, cond_text, size_text) @contextual def stackvar_type(self) -> StackVarType | None: From 699a6a3fea2553e53b510a7d3a90e39a8a0db546 Mon Sep 17 00:00:00 2001 From: Julia Date: Thu, 2 Mar 2023 15:45:43 +0800 Subject: [PATCH 056/280] Refactor: Renamed functions --- Python/tier2.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index 62384f90e5c419..c49ee8eea1dda8 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -65,7 +65,7 @@ initialize_type_context(const PyCodeObject *co) } static _PyTier2TypeContext * -_PyTier2TypeContext_copy(const _PyTier2TypeContext *type_context) +_PyTier2TypeContext_Copy(const _PyTier2TypeContext *type_context) { #if TYPEPROP_DEBUG @@ -103,7 +103,7 @@ _PyTier2TypeContext_copy(const _PyTier2TypeContext *type_context) } static void -_PyTier2TypeContext_free(_PyTier2TypeContext *type_context) +_PyTier2TypeContext_Free(_PyTier2TypeContext *type_context) { #if TYPEPROP_DEBUG @@ -776,14 +776,14 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // But generate the block after that so it can fall through. i--; // Make a copy of the type context - _PyTier2TypeContext *type_context_copy = _PyTier2TypeContext_copy(starting_type_context); + _PyTier2TypeContext *type_context_copy = _PyTier2TypeContext_Copy(starting_type_context); if (type_context_copy == NULL) { return NULL; } meta = _PyTier2_AllocateBBMetaData(co, t2_start, _PyCode_CODE(co) + i, type_context_copy); if (meta == NULL) { - _PyTier2TypeContext_free(type_context_copy); + _PyTier2TypeContext_Free(type_context_copy); return NULL; } bb_space->water_level += (write_i - t2_start) * sizeof(_Py_CODEUNIT); @@ -825,7 +825,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // Create the tier 2 BB // Make a copy of the type context - _PyTier2TypeContext *type_context_copy = _PyTier2TypeContext_copy(starting_type_context); + _PyTier2TypeContext *type_context_copy = _PyTier2TypeContext_Copy(starting_type_context); if (type_context_copy == NULL) { return NULL; } @@ -833,7 +833,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // + 1 because we want to start with the NEXT instruction for the scan _PyCode_CODE(co) + i + 1, type_context_copy); if (temp_meta == NULL) { - _PyTier2TypeContext_free(type_context_copy); + _PyTier2TypeContext_Free(type_context_copy); return NULL; } // We need to return the first block to enter into. If there is already a block generated @@ -848,7 +848,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, if (meta != temp_meta) { PyMem_Free(temp_meta); } - _PyTier2TypeContext_free(type_context_copy); + _PyTier2TypeContext_Free(type_context_copy); return NULL; } } @@ -1116,7 +1116,7 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) co, bb_space, _PyCode_CODE(co), type_context); if (meta == NULL) { - _PyTier2TypeContext_free(type_context); + _PyTier2TypeContext_Free(type_context); goto cleanup; } #if BB_DEBUG @@ -1185,7 +1185,7 @@ _PyTier2_GenerateNextBB(_PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, // Get type_context of previous BB _PyTier2TypeContext *type_context = meta->type_context; // Make a copy of the type context - _PyTier2TypeContext *type_context_copy = _PyTier2TypeContext_copy(type_context); + _PyTier2TypeContext *type_context_copy = _PyTier2TypeContext_Copy(type_context); if (type_context_copy == NULL) { return NULL; } @@ -1199,7 +1199,7 @@ _PyTier2_GenerateNextBB(_PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, frame->f_code, space, tier1_end, type_context_copy); if (metadata == NULL) { - _PyTier2TypeContext_free(type_context_copy); + _PyTier2TypeContext_Free(type_context_copy); return NULL; } return metadata->tier2_start; From 99a4ade88a3d9fefd29ac1190241e81b5c04d9c8 Mon Sep 17 00:00:00 2001 From: Julia Date: Fri, 3 Mar 2023 01:53:08 +0800 Subject: [PATCH 057/280] Feat: More type prop rules in the DSL and bytecodes.c DSL now allows declaring the type of an output stack effect with the type of an input stack effect. --- Python/bytecodes.c | 74 +++++++-------- Python/generated_cases.c.h | 8 +- Python/tier2_typepropagator.c.h | 115 +++++++++++------------- Tools/cases_generator/generate_cases.py | 48 +++++----- Tools/cases_generator/parser.py | 25 +++++- 5 files changed, 144 insertions(+), 126 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 59f3db48f80283..35cc2176615d58 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -140,7 +140,7 @@ dummy_func( DECREF_INPUTS(); } - inst(PUSH_NULL, (-- res)) { + inst(PUSH_NULL, (-- res: NULL)) { res = NULL; } @@ -184,7 +184,7 @@ dummy_func( }; - inst(BINARY_OP_MULTIPLY_INT, (unused/1, left, right -- prod)) { + inst(BINARY_OP_MULTIPLY_INT, (unused/1, left, right -- prod: PyLong_Type)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); @@ -195,7 +195,7 @@ dummy_func( ERROR_IF(prod == NULL, error); } - inst(BINARY_OP_MULTIPLY_FLOAT, (unused/1, left, right -- prod)) { + inst(BINARY_OP_MULTIPLY_FLOAT, (unused/1, left, right -- prod: PyFloat_Type)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); @@ -208,7 +208,7 @@ dummy_func( ERROR_IF(prod == NULL, error); } - inst(BINARY_OP_SUBTRACT_INT, (unused/1, left, right -- sub)) { + inst(BINARY_OP_SUBTRACT_INT, (unused/1, left, right -- sub: PyLong_Type)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); @@ -219,7 +219,7 @@ dummy_func( ERROR_IF(sub == NULL, error); } - inst(BINARY_OP_SUBTRACT_FLOAT, (unused/1, left, right -- sub)) { + inst(BINARY_OP_SUBTRACT_FLOAT, (unused/1, left, right -- sub: PyFloat_Type)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); @@ -231,7 +231,7 @@ dummy_func( ERROR_IF(sub == NULL, error); } - inst(BINARY_OP_ADD_UNICODE, (unused/1, left, right -- res)) { + inst(BINARY_OP_ADD_UNICODE, (unused/1, left, right -- res: PyUnicode_Type)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); @@ -278,7 +278,7 @@ dummy_func( JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); } - inst(BINARY_OP_ADD_FLOAT, (unused/1, left, right -- sum)) { + inst(BINARY_OP_ADD_FLOAT, (unused/1, left, right -- sum: PyFloat_Type)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); @@ -291,7 +291,7 @@ dummy_func( ERROR_IF(sum == NULL, error); } - macro_inst(BINARY_OP_ADD_INT, (unused/1, left, right -- sum)) { + macro_inst(BINARY_OP_ADD_INT, (unused/1, left, right -- sum: PyLong_Type)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); @@ -303,7 +303,7 @@ dummy_func( bb_test = PyLong_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); } - u_inst(BINARY_OP_ADD_INT_REST, (left : PyLong_Type, right : PyLong_Type -- sum : PyLong_Type)) { + u_inst(BINARY_OP_ADD_INT_REST, (left, right -- sum : PyLong_Type)) { STAT_INC(BINARY_OP, hit); sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -440,12 +440,12 @@ dummy_func( DISPATCH_INLINED(new_frame); } - inst(LIST_APPEND, (list, unused[oparg-1], v -- list, unused[oparg-1])) { + inst(LIST_APPEND, (list, unused[oparg-1], v -- list: *list, unused[oparg-1])) { ERROR_IF(_PyList_AppendTakeRef((PyListObject *)list, v) < 0, error); PREDICT(JUMP_BACKWARD); } - inst(SET_ADD, (set, unused[oparg-1], v -- set, unused[oparg-1])) { + inst(SET_ADD, (set, unused[oparg-1], v -- set: *set, unused[oparg-1])) { int err = PySet_Add(set, v); Py_DECREF(v); ERROR_IF(err, error); @@ -628,7 +628,7 @@ dummy_func( } } - inst(GET_ANEXT, (aiter -- aiter, awaitable)) { + inst(GET_ANEXT, (aiter -- aiter: *aiter, awaitable)) { unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -1274,7 +1274,7 @@ dummy_func( } } - inst(BUILD_STRING, (pieces[oparg] -- str)) { + inst(BUILD_STRING, (pieces[oparg] -- str: PyUnicode_Type)) { str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); for (int i = 0; i < oparg; i++) { Py_DECREF(pieces[i]); @@ -1282,17 +1282,17 @@ dummy_func( ERROR_IF(str == NULL, error); } - inst(BUILD_TUPLE, (values[oparg] -- tup)) { + inst(BUILD_TUPLE, (values[oparg] -- tup: PyTuple_Type)) { tup = _PyTuple_FromArraySteal(values, oparg); ERROR_IF(tup == NULL, error); } - inst(BUILD_LIST, (values[oparg] -- list)) { + inst(BUILD_LIST, (values[oparg] -- list: PyList_Type)) { list = _PyList_FromArraySteal(values, oparg); ERROR_IF(list == NULL, error); } - inst(LIST_EXTEND, (list, unused[oparg-1], iterable -- list, unused[oparg-1])) { + inst(LIST_EXTEND, (list, unused[oparg-1], iterable -- list: *list, unused[oparg-1])) { PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -1310,13 +1310,13 @@ dummy_func( DECREF_INPUTS(); } - inst(SET_UPDATE, (set, unused[oparg-1], iterable -- set, unused[oparg-1])) { + inst(SET_UPDATE, (set, unused[oparg-1], iterable -- set: *set, unused[oparg-1])) { int err = _PySet_Update(set, iterable); DECREF_INPUTS(); ERROR_IF(err < 0, error); } - inst(BUILD_SET, (values[oparg] -- set)) { + inst(BUILD_SET, (values[oparg] -- set: PySet_Type)) { set = PySet_New(NULL); if (set == NULL) goto error; @@ -1333,7 +1333,7 @@ dummy_func( } } - inst(BUILD_MAP, (values[oparg*2] -- map)) { + inst(BUILD_MAP, (values[oparg*2] -- map: PyDict_Type)) { map = _PyDict_FromItems( values, 2, values+1, 2, @@ -1390,7 +1390,7 @@ dummy_func( } } - inst(BUILD_CONST_KEY_MAP, (values[oparg], keys -- map)) { + inst(BUILD_CONST_KEY_MAP, (values[oparg], keys -- map: PyDict_Type)) { if (!PyTuple_CheckExact(keys) || PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) { _PyErr_SetString(tstate, PyExc_SystemError, @@ -1835,13 +1835,13 @@ dummy_func( } } - inst(IS_OP, (left, right -- b)) { + inst(IS_OP, (left, right -- b: PyBool_Type)) { int res = Py_Is(left, right) ^ oparg; DECREF_INPUTS(); b = Py_NewRef(res ? Py_True : Py_False); } - inst(CONTAINS_OP, (left, right -- b)) { + inst(CONTAINS_OP, (left, right -- b: PyBool_Type)) { int res = PySequence_Contains(right, left); DECREF_INPUTS(); ERROR_IF(res < 0, error); @@ -1869,7 +1869,7 @@ dummy_func( } } - inst(CHECK_EXC_MATCH, (left, right -- left, b)) { + inst(CHECK_EXC_MATCH, (left, right -- left: *left, b: PyBool_Type)) { assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { DECREF_INPUTS(); @@ -1888,7 +1888,7 @@ dummy_func( ERROR_IF(res == NULL, error); } - inst(IMPORT_FROM, (from -- from, res)) { + inst(IMPORT_FROM, (from -- from: *from, res)) { PyObject *name = GETITEM(names, oparg); res = import_from(tstate, from, name); ERROR_IF(res == NULL, error); @@ -2155,7 +2155,7 @@ dummy_func( JUMPBY(-oparg); } - inst(GET_LEN, (obj -- obj, len_o)) { + inst(GET_LEN, (obj -- obj: *obj, len_o: PyLong_Type)) { // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); ERROR_IF(len_i < 0, error); @@ -2178,19 +2178,19 @@ dummy_func( } } - inst(MATCH_MAPPING, (subject -- subject, res)) { + inst(MATCH_MAPPING, (subject -- subject: *subject, res: PyBool_Type)) { int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); PREDICT(POP_JUMP_IF_FALSE); } - inst(MATCH_SEQUENCE, (subject -- subject, res)) { + inst(MATCH_SEQUENCE, (subject -- subject: *subject, res: PyBool_Type)) { int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); PREDICT(POP_JUMP_IF_FALSE); } - inst(MATCH_KEYS, (subject, keys -- subject, keys, values_or_none)) { + inst(MATCH_KEYS, (subject, keys -- subject: *subject, keys: *keys, values_or_none)) { // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); ERROR_IF(values_or_none == NULL, error); @@ -2245,7 +2245,7 @@ dummy_func( FOR_ITER_GEN, }; - inst(FOR_ITER, (unused/1, iter -- iter, next)) { + inst(FOR_ITER, (unused/1, iter -- iter: *iter, next)) { #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2281,7 +2281,7 @@ dummy_func( } // FOR_ITER - inst(BB_TEST_ITER, (unused/1, iter -- iter, next)) { + inst(BB_TEST_ITER, (unused/1, iter -- iter: *iter, next)) { next = (*Py_TYPE(iter)->tp_iternext)(iter); if (next == NULL) { if (_PyErr_Occurred(tstate)) { @@ -2303,7 +2303,7 @@ dummy_func( bb_test = true; } - inst(FOR_ITER_LIST, (unused/1, iter -- iter, next)) { + inst(FOR_ITER_LIST, (unused/1, iter -- iter: *iter, next)) { assert(cframe.use_tracing == 0); DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; @@ -2326,7 +2326,7 @@ dummy_func( // Common case: no jump, leave it to the code generator } - inst(FOR_ITER_TUPLE, (unused/1, iter -- iter, next)) { + inst(FOR_ITER_TUPLE, (unused/1, iter -- iter: *iter, next)) { assert(cframe.use_tracing == 0); _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); @@ -2349,7 +2349,7 @@ dummy_func( // Common case: no jump, leave it to the code generator } - inst(FOR_ITER_RANGE, (unused/1, iter -- iter, next)) { + inst(FOR_ITER_RANGE, (unused/1, iter -- iter: *iter, next)) { assert(cframe.use_tracing == 0); _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); @@ -2370,7 +2370,7 @@ dummy_func( } } - inst(FOR_ITER_GEN, (unused/1, iter -- iter, unused)) { + inst(FOR_ITER_GEN, (unused/1, iter -- iter: *iter, unused)) { assert(cframe.use_tracing == 0); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -2455,7 +2455,7 @@ dummy_func( } } - inst(WITH_EXCEPT_START, (exit_func, lasti, unused, val -- exit_func, lasti, unused, val, res)) { + inst(WITH_EXCEPT_START, (exit_func, lasti, unused, val -- exit_func, lasti: PyLong_Type, unused, val, res)) { /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3247,7 +3247,7 @@ dummy_func( } } - inst(COPY, (bottom, unused[oparg-1] -- bottom, unused[oparg-1], top)) { + inst(COPY, (bottom, unused[oparg-1] -- bottom: *bottom, unused[oparg-1], top: *bottom)) { assert(oparg > 0); top = Py_NewRef(bottom); } @@ -3274,7 +3274,7 @@ dummy_func( } inst(SWAP, (bottom, unused[oparg-2], top -- - top, unused[oparg-2], bottom)) { + top : *top, unused[oparg-2], bottom : *bottom)) { assert(oparg >= 2); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index ba0aa72c68f22d..8aac7f5e2fa8f9 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1,5 +1,5 @@ -// This file is generated by Tools\cases_generator\generate_cases.py -// from Python\bytecodes.c +// This file is generated by Tools/cases_generator/generate_cases.py +// from Python/bytecodes.c // Do not edit! #define UOP_BINARY_OP_ADD_INT_REST() \ @@ -2646,7 +2646,7 @@ // This gets set so BRANCH_BB knows whether to pop // the type stack (type propagation) when generating the // target BB - gen_bb_requires_pop = jump; + gen_bb_requires_pop = !jump; STACK_SHRINK(1); STACK_GROW((jump ? 1 : 0)); DISPATCH(); @@ -2710,7 +2710,7 @@ // This gets set so BRANCH_BB knows whether to pop // the type stack (type propagation) when generating the // target BB - gen_bb_requires_pop = jump; + gen_bb_requires_pop = !jump; STACK_SHRINK(1); STACK_GROW((jump ? 1 : 0)); DISPATCH(); diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index 786eff5afbcf23..17ffa81e673dd8 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -1,5 +1,5 @@ -// This file is generated by Tools\cases_generator\generate_cases.py @TODO: make this a seperate argument -// from Python\bytecodes.c +// This file is generated by Tools/cases_generator/generate_cases.py @TODO: make this a seperate argument +// from Python/bytecodes.c // Do not edit! TARGET(NOP) { @@ -91,7 +91,7 @@ PyTypeObject *right = TYPESTACK_PEEK(1); PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(1, &PyLong_Type); break; } @@ -99,7 +99,7 @@ PyTypeObject *right = TYPESTACK_PEEK(1); PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(1, &PyFloat_Type); break; } @@ -107,7 +107,7 @@ PyTypeObject *right = TYPESTACK_PEEK(1); PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(1, &PyLong_Type); break; } @@ -115,7 +115,7 @@ PyTypeObject *right = TYPESTACK_PEEK(1); PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(1, &PyFloat_Type); break; } @@ -123,7 +123,7 @@ PyTypeObject *right = TYPESTACK_PEEK(1); PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(1, &PyUnicode_Type); break; } @@ -138,7 +138,7 @@ PyTypeObject *right = TYPESTACK_PEEK(1); PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(1, &PyFloat_Type); break; } @@ -146,7 +146,7 @@ PyTypeObject *right = TYPESTACK_PEEK(1); PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(1, &PyLong_Type); break; } @@ -283,8 +283,8 @@ } TARGET(RAISE_VARARGS) { - PyTypeObject **args = &TYPESTACK_PEEK(oparg); - STACK_SHRINK(oparg); + fprintf(stderr, "Type propagation across `RAISE_VARARGS` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } @@ -324,34 +324,32 @@ } TARGET(SEND) { - PyTypeObject *v = TYPESTACK_PEEK(1); - PyTypeObject *receiver = TYPESTACK_PEEK(2); - TYPESTACK_POKE(1, NULL); + fprintf(stderr, "Type propagation across `SEND` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } TARGET(SEND_GEN) { - PyTypeObject *v = TYPESTACK_PEEK(1); - PyTypeObject *receiver = TYPESTACK_PEEK(2); - STACK_SHRINK(1); + fprintf(stderr, "Type propagation across `SEND_GEN` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } TARGET(YIELD_VALUE) { - PyTypeObject *retval = TYPESTACK_PEEK(1); + fprintf(stderr, "Type propagation across `YIELD_VALUE` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } TARGET(POP_EXCEPT) { - PyTypeObject *exc_value = TYPESTACK_PEEK(1); - STACK_SHRINK(1); + fprintf(stderr, "Type propagation across `POP_EXCEPT` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } TARGET(RERAISE) { - PyTypeObject *exc = TYPESTACK_PEEK(1); - PyTypeObject **values = &TYPESTACK_PEEK(1 + oparg); - STACK_SHRINK(1); + fprintf(stderr, "Type propagation across `RERAISE` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } @@ -485,12 +483,14 @@ } TARGET(DELETE_FAST) { - TYPELOCALS_SET(oparg, NULL) + fprintf(stderr, "Type propagation across `DELETE_FAST` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } TARGET(MAKE_CELL) { - TYPELOCALS_SET(oparg, NULL) + fprintf(stderr, "Type propagation across `MAKE_CELL` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } @@ -505,8 +505,8 @@ } TARGET(LOAD_DEREF) { - STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + fprintf(stderr, "Type propagation across `LOAD_DEREF` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } @@ -524,7 +524,7 @@ PyTypeObject **pieces = &TYPESTACK_PEEK(oparg); STACK_SHRINK(oparg); STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(1, &PyUnicode_Type); break; } @@ -532,7 +532,7 @@ PyTypeObject **values = &TYPESTACK_PEEK(oparg); STACK_SHRINK(oparg); STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(1, &PyTuple_Type); break; } @@ -540,7 +540,7 @@ PyTypeObject **values = &TYPESTACK_PEEK(oparg); STACK_SHRINK(oparg); STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(1, &PyList_Type); break; } @@ -562,7 +562,7 @@ PyTypeObject **values = &TYPESTACK_PEEK(oparg); STACK_SHRINK(oparg); STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(1, &PySet_Type); break; } @@ -570,7 +570,7 @@ PyTypeObject **values = &TYPESTACK_PEEK(oparg*2); STACK_SHRINK(oparg*2); STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(1, &PyDict_Type); break; } @@ -582,7 +582,7 @@ PyTypeObject *keys = TYPESTACK_PEEK(1); PyTypeObject **values = &TYPESTACK_PEEK(1 + oparg); STACK_SHRINK(oparg); - TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(1, &PyDict_Type); break; } @@ -726,7 +726,7 @@ PyTypeObject *right = TYPESTACK_PEEK(1); PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(1, &PyBool_Type); break; } @@ -734,7 +734,7 @@ PyTypeObject *right = TYPESTACK_PEEK(1); PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(1, &PyBool_Type); break; } @@ -749,7 +749,7 @@ TARGET(CHECK_EXC_MATCH) { PyTypeObject *right = TYPESTACK_PEEK(1); PyTypeObject *left = TYPESTACK_PEEK(2); - TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(1, &PyBool_Type); break; } @@ -829,25 +829,25 @@ } TARGET(JUMP_IF_FALSE_OR_POP) { - fprintf(stderr, "Type propagation across `{self.name}` shouldn't be handled statically!\n"); + fprintf(stderr, "Type propagation across `JUMP_IF_FALSE_OR_POP` shouldn't be handled statically!\n"); Py_UNREACHABLE(); break; } TARGET(BB_TEST_IF_FALSE_OR_POP) { - fprintf(stderr, "Type propagation across `{self.name}` shouldn't be handled statically!\n"); + fprintf(stderr, "Type propagation across `BB_TEST_IF_FALSE_OR_POP` shouldn't be handled statically!\n"); Py_UNREACHABLE(); break; } TARGET(JUMP_IF_TRUE_OR_POP) { - fprintf(stderr, "Type propagation across `{self.name}` shouldn't be handled statically!\n"); + fprintf(stderr, "Type propagation across `JUMP_IF_TRUE_OR_POP` shouldn't be handled statically!\n"); Py_UNREACHABLE(); break; } TARGET(BB_TEST_IF_TRUE_OR_POP) { - fprintf(stderr, "Type propagation across `{self.name}` shouldn't be handled statically!\n"); + fprintf(stderr, "Type propagation across `BB_TEST_IF_TRUE_OR_POP` shouldn't be handled statically!\n"); Py_UNREACHABLE(); break; } @@ -859,7 +859,7 @@ TARGET(GET_LEN) { PyTypeObject *obj = TYPESTACK_PEEK(1); STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(1, &PyLong_Type); break; } @@ -873,24 +873,20 @@ } TARGET(MATCH_MAPPING) { - PyTypeObject *subject = TYPESTACK_PEEK(1); - STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + fprintf(stderr, "Type propagation across `MATCH_MAPPING` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } TARGET(MATCH_SEQUENCE) { - PyTypeObject *subject = TYPESTACK_PEEK(1); - STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + fprintf(stderr, "Type propagation across `MATCH_SEQUENCE` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } TARGET(MATCH_KEYS) { - PyTypeObject *keys = TYPESTACK_PEEK(1); - PyTypeObject *subject = TYPESTACK_PEEK(2); - STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + fprintf(stderr, "Type propagation across `MATCH_KEYS` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } @@ -964,19 +960,14 @@ } TARGET(WITH_EXCEPT_START) { - PyTypeObject *val = TYPESTACK_PEEK(1); - PyTypeObject *lasti = TYPESTACK_PEEK(3); - PyTypeObject *exit_func = TYPESTACK_PEEK(4); - STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + fprintf(stderr, "Type propagation across `WITH_EXCEPT_START` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } TARGET(PUSH_EXC_INFO) { - PyTypeObject *new_exc = TYPESTACK_PEEK(1); - STACK_GROW(1); - TYPESTACK_POKE(1, new_exc); - TYPESTACK_POKE(2, NULL); + fprintf(stderr, "Type propagation across `PUSH_EXC_INFO` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } @@ -1225,7 +1216,7 @@ TARGET(COPY) { PyTypeObject *bottom = TYPESTACK_PEEK(1 + (oparg-1)); STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + TYPESTACK_POKE(1, bottom); break; } @@ -1246,6 +1237,8 @@ } TARGET(EXTENDED_ARG) { + fprintf(stderr, "Type propagation across `EXTENDED_ARG` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 3c37a47d21c2cf..58ed38b65221e5 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -16,7 +16,7 @@ from enum import Enum, auto import parser -from parser import StackEffect, StackVarTypeLiteral, StackVarTypeIndex +from parser import StackEffect, StackVarTypeLiteral, StackVarTypeIndex, StackVarInputVar from parser import LocalEffect, LocalEffectVarLiteral, LocalEffectVarStack HERE = os.path.dirname(__file__) @@ -49,13 +49,29 @@ UNUSED = "unused" BITS_PER_CODE_UNIT = 16 -# Type propagation across these instructions are forbidden -# due to conditional effects that can't be determined statically -# The handling of type propagation across these opcodes are handled elsewhere -# within tier2. TYPE_PROPAGATOR_FORBIDDEN = [ + # Type propagator shouldn't see these "JUMP_IF_FALSE_OR_POP", - "JUMP_IF_TRUE_OR_POP", # Type propagator shouldn't see these + "JUMP_IF_TRUE_OR_POP", + "SEND", + "SEND_GEN", + "YIELD_VALUE", + "RAISE_VARARGS", + "PUSH_EXC_INFO", + "RERAISE", + "POP_EXCEPT", + "LOAD_DEREF", + "MAKE_CELL", + "DELETE_FAST", + "MATCH_MAPPING", + "MATCH_SEQUENCE", + "MATCH_KEYS", + "EXTENDED_ARG", + "WITH_EXCEPT_START", + # Type propagation across these instructions are forbidden + # due to conditional effects that can't be determined statically + # The handling of type propagation across these opcodes are handled elsewhere + # within tier2. "BB_TEST_IF_FALSE_OR_POP", "BB_TEST_IF_TRUE_OR_POP" # Type propagator handles this in BB_BRANCH ] @@ -317,7 +333,7 @@ def write_typeprop(self, out: Formatter) -> None: """Write one instruction's type propagation rules""" if self.name in TYPE_PROPAGATOR_FORBIDDEN: - out.emit('fprintf(stderr, "Type propagation across `{self.name}` shouldn\'t be handled statically!\\n");') + out.emit(f'fprintf(stderr, "Type propagation across `{self.name}` shouldn\'t be handled statically!\\n");') out.emit("Py_UNREACHABLE();") return @@ -379,6 +395,10 @@ def write_typeprop(self, out: Formatter) -> None: if val != "NULL": val = f"&{val}" case StackVarTypeIndex(array=arr, index=idx): val = f"{'TYPELOCALS_GET' if arr == 'locals' else 'TYPECONST_GET'}({idx})" + case StackVarInputVar(name=val): + ieffect, j = all_input_effect_names[val] + if len(oeffects) - i == len(ieffects) - j: + continue case _: typing.assert_never(typ) if oeffect.cond: @@ -386,20 +406,6 @@ def write_typeprop(self, out: Formatter) -> None: else: out.emit(f"TYPESTACK_POKE({osize}, {val});") continue - - # Check if it's part of input effect - # TODO: Can we assume that they have the same type? - if oeffect.name in all_input_effect_names: - ieffect, j = all_input_effect_names[oeffect.name] - assert not ieffect.cond, \ - "`cond` stackvar not supported for type prop" - # The stack var stays at the same pos - if len(oeffects) - i == len(ieffects) - j: continue - if oeffect.cond: - out.emit(f"if ({oeffect.cond}) {{ TYPESTACK_POKE({osize}, {oeffect.name}); }}") - else: - out.emit(f"TYPESTACK_POKE({osize}, {oeffect.name});") - continue # Just output null if oeffect.cond: diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index 1e84119854edf2..d4feee6599fe7c 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -78,8 +78,12 @@ class StackVarTypeIndex(Node): array: Literal["locals", "consts"] index: str +@dataclass +class StackVarInputVar(Node): + name: str + -StackVarType: TypeAlias = StackVarTypeLiteral | StackVarTypeIndex +StackVarType: TypeAlias = StackVarTypeLiteral | StackVarTypeIndex | StackVarInputVar @dataclass @@ -91,6 +95,9 @@ class StackEffect(Node): size: str = "" # Optional `[size]` # Note: size cannot be combined with type or cond + def __eq__(self, other: 'StackEffect') -> bool: + return self.name == other.name + @dataclass class Expression(Node): @@ -270,7 +277,13 @@ def inputs(self) -> list[InputEffect] | None: @contextual def input(self) -> InputEffect | None: - return self.cache_effect() or self.stack_effect() + if r := self.cache_effect(): + return r + r = self.stack_effect() + if r is None: return r + assert r.type_annotation is None, \ + "Type annotations aren't allowed in input stack effect." + return r def outputs(self) -> list[OutputEffect] | None: # output (, output)* @@ -344,10 +357,16 @@ def stackvar_type(self) -> StackVarType | None: return StackVarTypeIndex( "locals" if idstr == "locals" else "consts", index) + elif self.expect(lx.TIMES): + id = self.require(lx.IDENTIFIER) + return StackVarInputVar(id.text.strip()) + @contextual def local_effect(self) -> LocalEffect | None: - if self.expect(lx.IDENTIFIER).text.strip() == "locals": + if tok := self.expect(lx.IDENTIFIER): + if tok.text.strip() != "locals": + return self.require(lx.LBRACKET) if id := self.expect(lx.IDENTIFIER): index = id.text.strip() From d8c6edce966b2c136a8ea31f653185730f823b54 Mon Sep 17 00:00:00 2001 From: Julia Date: Fri, 3 Mar 2023 12:14:17 +0800 Subject: [PATCH 058/280] Perf: Removed unneccessary declarations in type propagator Updated DSL to not require type annotations for unmoved stack variables --- Python/bytecodes.c | 30 ++-- Python/tier2_typepropagator.c.h | 221 ------------------------ Tools/cases_generator/generate_cases.py | 30 +++- 3 files changed, 43 insertions(+), 238 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 35cc2176615d58..05436c842ddb68 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -440,12 +440,12 @@ dummy_func( DISPATCH_INLINED(new_frame); } - inst(LIST_APPEND, (list, unused[oparg-1], v -- list: *list, unused[oparg-1])) { + inst(LIST_APPEND, (list, unused[oparg-1], v -- list, unused[oparg-1])) { ERROR_IF(_PyList_AppendTakeRef((PyListObject *)list, v) < 0, error); PREDICT(JUMP_BACKWARD); } - inst(SET_ADD, (set, unused[oparg-1], v -- set: *set, unused[oparg-1])) { + inst(SET_ADD, (set, unused[oparg-1], v -- set, unused[oparg-1])) { int err = PySet_Add(set, v); Py_DECREF(v); ERROR_IF(err, error); @@ -628,7 +628,7 @@ dummy_func( } } - inst(GET_ANEXT, (aiter -- aiter: *aiter, awaitable)) { + inst(GET_ANEXT, (aiter -- aiter, awaitable)) { unaryfunc getter = NULL; PyObject *next_iter = NULL; PyTypeObject *type = Py_TYPE(aiter); @@ -1292,7 +1292,7 @@ dummy_func( ERROR_IF(list == NULL, error); } - inst(LIST_EXTEND, (list, unused[oparg-1], iterable -- list: *list, unused[oparg-1])) { + inst(LIST_EXTEND, (list, unused[oparg-1], iterable -- list, unused[oparg-1])) { PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable); if (none_val == NULL) { if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) && @@ -1310,7 +1310,7 @@ dummy_func( DECREF_INPUTS(); } - inst(SET_UPDATE, (set, unused[oparg-1], iterable -- set: *set, unused[oparg-1])) { + inst(SET_UPDATE, (set, unused[oparg-1], iterable -- set, unused[oparg-1])) { int err = _PySet_Update(set, iterable); DECREF_INPUTS(); ERROR_IF(err < 0, error); @@ -1869,7 +1869,7 @@ dummy_func( } } - inst(CHECK_EXC_MATCH, (left, right -- left: *left, b: PyBool_Type)) { + inst(CHECK_EXC_MATCH, (left, right -- left, b: PyBool_Type)) { assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { DECREF_INPUTS(); @@ -1888,7 +1888,7 @@ dummy_func( ERROR_IF(res == NULL, error); } - inst(IMPORT_FROM, (from -- from: *from, res)) { + inst(IMPORT_FROM, (from -- from, res)) { PyObject *name = GETITEM(names, oparg); res = import_from(tstate, from, name); ERROR_IF(res == NULL, error); @@ -2155,7 +2155,7 @@ dummy_func( JUMPBY(-oparg); } - inst(GET_LEN, (obj -- obj: *obj, len_o: PyLong_Type)) { + inst(GET_LEN, (obj -- obj, len_o: PyLong_Type)) { // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); ERROR_IF(len_i < 0, error); @@ -2245,7 +2245,7 @@ dummy_func( FOR_ITER_GEN, }; - inst(FOR_ITER, (unused/1, iter -- iter: *iter, next)) { + inst(FOR_ITER, (unused/1, iter -- iter, next)) { #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2281,7 +2281,7 @@ dummy_func( } // FOR_ITER - inst(BB_TEST_ITER, (unused/1, iter -- iter: *iter, next)) { + inst(BB_TEST_ITER, (unused/1, iter -- iter, next)) { next = (*Py_TYPE(iter)->tp_iternext)(iter); if (next == NULL) { if (_PyErr_Occurred(tstate)) { @@ -2303,7 +2303,7 @@ dummy_func( bb_test = true; } - inst(FOR_ITER_LIST, (unused/1, iter -- iter: *iter, next)) { + inst(FOR_ITER_LIST, (unused/1, iter -- iter, next)) { assert(cframe.use_tracing == 0); DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; @@ -2326,7 +2326,7 @@ dummy_func( // Common case: no jump, leave it to the code generator } - inst(FOR_ITER_TUPLE, (unused/1, iter -- iter: *iter, next)) { + inst(FOR_ITER_TUPLE, (unused/1, iter -- iter, next)) { assert(cframe.use_tracing == 0); _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); @@ -2349,7 +2349,7 @@ dummy_func( // Common case: no jump, leave it to the code generator } - inst(FOR_ITER_RANGE, (unused/1, iter -- iter: *iter, next)) { + inst(FOR_ITER_RANGE, (unused/1, iter -- iter, next)) { assert(cframe.use_tracing == 0); _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); @@ -2370,7 +2370,7 @@ dummy_func( } } - inst(FOR_ITER_GEN, (unused/1, iter -- iter: *iter, unused)) { + inst(FOR_ITER_GEN, (unused/1, iter -- iter, unused)) { assert(cframe.use_tracing == 0); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3247,7 +3247,7 @@ dummy_func( } } - inst(COPY, (bottom, unused[oparg-1] -- bottom: *bottom, unused[oparg-1], top: *bottom)) { + inst(COPY, (bottom, unused[oparg-1] -- bottom, unused[oparg-1], top: *bottom)) { assert(oparg > 0); top = Py_NewRef(bottom); } diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index 17ffa81e673dd8..787d956eab0e72 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -46,7 +46,6 @@ } TARGET(POP_TOP) { - PyTypeObject *value = TYPESTACK_PEEK(1); STACK_SHRINK(1); break; } @@ -59,224 +58,164 @@ TARGET(END_FOR) { { - PyTypeObject *value = TYPESTACK_PEEK(1); STACK_SHRINK(1); } { - PyTypeObject *value = TYPESTACK_PEEK(1); STACK_SHRINK(1); } break; } TARGET(UNARY_NEGATIVE) { - PyTypeObject *value = TYPESTACK_PEEK(1); TYPESTACK_POKE(1, NULL); break; } TARGET(UNARY_NOT) { - PyTypeObject *value = TYPESTACK_PEEK(1); TYPESTACK_POKE(1, NULL); break; } TARGET(UNARY_INVERT) { - PyTypeObject *value = TYPESTACK_PEEK(1); TYPESTACK_POKE(1, NULL); break; } TARGET(BINARY_OP_MULTIPLY_INT) { - PyTypeObject *right = TYPESTACK_PEEK(1); - PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); TYPESTACK_POKE(1, &PyLong_Type); break; } TARGET(BINARY_OP_MULTIPLY_FLOAT) { - PyTypeObject *right = TYPESTACK_PEEK(1); - PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); TYPESTACK_POKE(1, &PyFloat_Type); break; } TARGET(BINARY_OP_SUBTRACT_INT) { - PyTypeObject *right = TYPESTACK_PEEK(1); - PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); TYPESTACK_POKE(1, &PyLong_Type); break; } TARGET(BINARY_OP_SUBTRACT_FLOAT) { - PyTypeObject *right = TYPESTACK_PEEK(1); - PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); TYPESTACK_POKE(1, &PyFloat_Type); break; } TARGET(BINARY_OP_ADD_UNICODE) { - PyTypeObject *right = TYPESTACK_PEEK(1); - PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); TYPESTACK_POKE(1, &PyUnicode_Type); break; } TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { - PyTypeObject *right = TYPESTACK_PEEK(1); - PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(2); break; } TARGET(BINARY_OP_ADD_FLOAT) { - PyTypeObject *right = TYPESTACK_PEEK(1); - PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); TYPESTACK_POKE(1, &PyFloat_Type); break; } TARGET(BINARY_OP_ADD_INT) { - PyTypeObject *right = TYPESTACK_PEEK(1); - PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); TYPESTACK_POKE(1, &PyLong_Type); break; } TARGET(BINARY_CHECK_INT) { - PyTypeObject *right = TYPESTACK_PEEK(1); - PyTypeObject *left = TYPESTACK_PEEK(2); TYPESTACK_POKE(1, &PyLong_Type); TYPESTACK_POKE(2, &PyLong_Type); break; } TARGET(BINARY_OP_ADD_INT_REST) { - PyTypeObject *right = TYPESTACK_PEEK(1); - PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); TYPESTACK_POKE(1, &PyLong_Type); break; } TARGET(BINARY_SUBSCR) { - PyTypeObject *sub = TYPESTACK_PEEK(1); - PyTypeObject *container = TYPESTACK_PEEK(2); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); break; } TARGET(BINARY_SLICE) { - PyTypeObject *stop = TYPESTACK_PEEK(1); - PyTypeObject *start = TYPESTACK_PEEK(2); - PyTypeObject *container = TYPESTACK_PEEK(3); STACK_SHRINK(2); TYPESTACK_POKE(1, NULL); break; } TARGET(STORE_SLICE) { - PyTypeObject *stop = TYPESTACK_PEEK(1); - PyTypeObject *start = TYPESTACK_PEEK(2); - PyTypeObject *container = TYPESTACK_PEEK(3); - PyTypeObject *v = TYPESTACK_PEEK(4); STACK_SHRINK(4); break; } TARGET(BINARY_SUBSCR_LIST_INT) { - PyTypeObject *sub = TYPESTACK_PEEK(1); - PyTypeObject *list = TYPESTACK_PEEK(2); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); break; } TARGET(BINARY_SUBSCR_TUPLE_INT) { - PyTypeObject *sub = TYPESTACK_PEEK(1); - PyTypeObject *tuple = TYPESTACK_PEEK(2); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); break; } TARGET(BINARY_SUBSCR_DICT) { - PyTypeObject *sub = TYPESTACK_PEEK(1); - PyTypeObject *dict = TYPESTACK_PEEK(2); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); break; } TARGET(BINARY_SUBSCR_GETITEM) { - PyTypeObject *sub = TYPESTACK_PEEK(1); - PyTypeObject *container = TYPESTACK_PEEK(2); STACK_SHRINK(1); break; } TARGET(LIST_APPEND) { - PyTypeObject *v = TYPESTACK_PEEK(1); - PyTypeObject *list = TYPESTACK_PEEK(2 + (oparg-1)); STACK_SHRINK(1); break; } TARGET(SET_ADD) { - PyTypeObject *v = TYPESTACK_PEEK(1); - PyTypeObject *set = TYPESTACK_PEEK(2 + (oparg-1)); STACK_SHRINK(1); break; } TARGET(STORE_SUBSCR) { - PyTypeObject *sub = TYPESTACK_PEEK(1); - PyTypeObject *container = TYPESTACK_PEEK(2); - PyTypeObject *v = TYPESTACK_PEEK(3); STACK_SHRINK(3); break; } TARGET(STORE_SUBSCR_LIST_INT) { - PyTypeObject *sub = TYPESTACK_PEEK(1); - PyTypeObject *list = TYPESTACK_PEEK(2); - PyTypeObject *value = TYPESTACK_PEEK(3); STACK_SHRINK(3); break; } TARGET(STORE_SUBSCR_DICT) { - PyTypeObject *sub = TYPESTACK_PEEK(1); - PyTypeObject *dict = TYPESTACK_PEEK(2); - PyTypeObject *value = TYPESTACK_PEEK(3); STACK_SHRINK(3); break; } TARGET(DELETE_SUBSCR) { - PyTypeObject *sub = TYPESTACK_PEEK(1); - PyTypeObject *container = TYPESTACK_PEEK(2); STACK_SHRINK(2); break; } TARGET(CALL_INTRINSIC_1) { - PyTypeObject *value = TYPESTACK_PEEK(1); TYPESTACK_POKE(1, NULL); break; } TARGET(CALL_INTRINSIC_2) { - PyTypeObject *value1 = TYPESTACK_PEEK(1); - PyTypeObject *value2 = TYPESTACK_PEEK(2); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); break; @@ -289,13 +228,11 @@ } TARGET(INTERPRETER_EXIT) { - PyTypeObject *retval = TYPESTACK_PEEK(1); STACK_SHRINK(1); break; } TARGET(RETURN_VALUE) { - PyTypeObject *retval = TYPESTACK_PEEK(1); STACK_SHRINK(1); break; } @@ -305,20 +242,17 @@ } TARGET(GET_AITER) { - PyTypeObject *obj = TYPESTACK_PEEK(1); TYPESTACK_POKE(1, NULL); break; } TARGET(GET_ANEXT) { - PyTypeObject *aiter = TYPESTACK_PEEK(1); STACK_GROW(1); TYPESTACK_POKE(1, NULL); break; } TARGET(GET_AWAITABLE) { - PyTypeObject *iterable = TYPESTACK_PEEK(1); TYPESTACK_POKE(1, NULL); break; } @@ -354,16 +288,11 @@ } TARGET(END_ASYNC_FOR) { - PyTypeObject *exc = TYPESTACK_PEEK(1); - PyTypeObject *awaitable = TYPESTACK_PEEK(2); STACK_SHRINK(2); break; } TARGET(CLEANUP_THROW) { - PyTypeObject *exc_value = TYPESTACK_PEEK(1); - PyTypeObject *last_sent_val = TYPESTACK_PEEK(2); - PyTypeObject *sub_iter = TYPESTACK_PEEK(3); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); TYPESTACK_POKE(2, NULL); @@ -383,7 +312,6 @@ } TARGET(STORE_NAME) { - PyTypeObject *v = TYPESTACK_PEEK(1); STACK_SHRINK(1); break; } @@ -393,14 +321,12 @@ } TARGET(UNPACK_SEQUENCE) { - PyTypeObject *seq = TYPESTACK_PEEK(1); STACK_SHRINK(1); STACK_GROW(oparg); break; } TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { - PyTypeObject *seq = TYPESTACK_PEEK(1); STACK_SHRINK(1); STACK_GROW(oparg); TYPESTACK_POKE(oparg, NULL); @@ -408,7 +334,6 @@ } TARGET(UNPACK_SEQUENCE_TUPLE) { - PyTypeObject *seq = TYPESTACK_PEEK(1); STACK_SHRINK(1); STACK_GROW(oparg); TYPESTACK_POKE(oparg, NULL); @@ -416,7 +341,6 @@ } TARGET(UNPACK_SEQUENCE_LIST) { - PyTypeObject *seq = TYPESTACK_PEEK(1); STACK_SHRINK(1); STACK_GROW(oparg); TYPESTACK_POKE(oparg, NULL); @@ -424,26 +348,21 @@ } TARGET(UNPACK_EX) { - PyTypeObject *seq = TYPESTACK_PEEK(1); STACK_GROW((oparg & 0xFF) + (oparg >> 8)); break; } TARGET(STORE_ATTR) { - PyTypeObject *owner = TYPESTACK_PEEK(1); - PyTypeObject *v = TYPESTACK_PEEK(2); STACK_SHRINK(2); break; } TARGET(DELETE_ATTR) { - PyTypeObject *owner = TYPESTACK_PEEK(1); STACK_SHRINK(1); break; } TARGET(STORE_GLOBAL) { - PyTypeObject *v = TYPESTACK_PEEK(1); STACK_SHRINK(1); break; } @@ -511,7 +430,6 @@ } TARGET(STORE_DEREF) { - PyTypeObject *v = TYPESTACK_PEEK(1); STACK_SHRINK(1); break; } @@ -521,7 +439,6 @@ } TARGET(BUILD_STRING) { - PyTypeObject **pieces = &TYPESTACK_PEEK(oparg); STACK_SHRINK(oparg); STACK_GROW(1); TYPESTACK_POKE(1, &PyUnicode_Type); @@ -529,7 +446,6 @@ } TARGET(BUILD_TUPLE) { - PyTypeObject **values = &TYPESTACK_PEEK(oparg); STACK_SHRINK(oparg); STACK_GROW(1); TYPESTACK_POKE(1, &PyTuple_Type); @@ -537,7 +453,6 @@ } TARGET(BUILD_LIST) { - PyTypeObject **values = &TYPESTACK_PEEK(oparg); STACK_SHRINK(oparg); STACK_GROW(1); TYPESTACK_POKE(1, &PyList_Type); @@ -545,21 +460,16 @@ } TARGET(LIST_EXTEND) { - PyTypeObject *iterable = TYPESTACK_PEEK(1); - PyTypeObject *list = TYPESTACK_PEEK(2 + (oparg-1)); STACK_SHRINK(1); break; } TARGET(SET_UPDATE) { - PyTypeObject *iterable = TYPESTACK_PEEK(1); - PyTypeObject *set = TYPESTACK_PEEK(2 + (oparg-1)); STACK_SHRINK(1); break; } TARGET(BUILD_SET) { - PyTypeObject **values = &TYPESTACK_PEEK(oparg); STACK_SHRINK(oparg); STACK_GROW(1); TYPESTACK_POKE(1, &PySet_Type); @@ -567,7 +477,6 @@ } TARGET(BUILD_MAP) { - PyTypeObject **values = &TYPESTACK_PEEK(oparg*2); STACK_SHRINK(oparg*2); STACK_GROW(1); TYPESTACK_POKE(1, &PyDict_Type); @@ -579,34 +488,27 @@ } TARGET(BUILD_CONST_KEY_MAP) { - PyTypeObject *keys = TYPESTACK_PEEK(1); - PyTypeObject **values = &TYPESTACK_PEEK(1 + oparg); STACK_SHRINK(oparg); TYPESTACK_POKE(1, &PyDict_Type); break; } TARGET(DICT_UPDATE) { - PyTypeObject *update = TYPESTACK_PEEK(1); STACK_SHRINK(1); break; } TARGET(DICT_MERGE) { - PyTypeObject *update = TYPESTACK_PEEK(1); STACK_SHRINK(1); break; } TARGET(MAP_ADD) { - PyTypeObject *value = TYPESTACK_PEEK(1); - PyTypeObject *key = TYPESTACK_PEEK(2); STACK_SHRINK(2); break; } TARGET(LOAD_ATTR) { - PyTypeObject *owner = TYPESTACK_PEEK(1); STACK_GROW(((oparg & 1) ? 1 : 0)); TYPESTACK_POKE(1, NULL); if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } @@ -614,7 +516,6 @@ } TARGET(LOAD_ATTR_INSTANCE_VALUE) { - PyTypeObject *owner = TYPESTACK_PEEK(1); STACK_GROW(((oparg & 1) ? 1 : 0)); TYPESTACK_POKE(1, NULL); if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } @@ -622,7 +523,6 @@ } TARGET(LOAD_ATTR_MODULE) { - PyTypeObject *owner = TYPESTACK_PEEK(1); STACK_GROW(((oparg & 1) ? 1 : 0)); TYPESTACK_POKE(1, NULL); if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } @@ -630,7 +530,6 @@ } TARGET(LOAD_ATTR_WITH_HINT) { - PyTypeObject *owner = TYPESTACK_PEEK(1); STACK_GROW(((oparg & 1) ? 1 : 0)); TYPESTACK_POKE(1, NULL); if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } @@ -638,7 +537,6 @@ } TARGET(LOAD_ATTR_SLOT) { - PyTypeObject *owner = TYPESTACK_PEEK(1); STACK_GROW(((oparg & 1) ? 1 : 0)); TYPESTACK_POKE(1, NULL); if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } @@ -646,7 +544,6 @@ } TARGET(LOAD_ATTR_CLASS) { - PyTypeObject *cls = TYPESTACK_PEEK(1); STACK_GROW(((oparg & 1) ? 1 : 0)); TYPESTACK_POKE(1, NULL); if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } @@ -654,115 +551,86 @@ } TARGET(LOAD_ATTR_PROPERTY) { - PyTypeObject *owner = TYPESTACK_PEEK(1); STACK_GROW(((oparg & 1) ? 1 : 0)); break; } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { - PyTypeObject *owner = TYPESTACK_PEEK(1); STACK_GROW(((oparg & 1) ? 1 : 0)); break; } TARGET(STORE_ATTR_INSTANCE_VALUE) { - PyTypeObject *owner = TYPESTACK_PEEK(1); - PyTypeObject *value = TYPESTACK_PEEK(2); STACK_SHRINK(2); break; } TARGET(STORE_ATTR_WITH_HINT) { - PyTypeObject *owner = TYPESTACK_PEEK(1); - PyTypeObject *value = TYPESTACK_PEEK(2); STACK_SHRINK(2); break; } TARGET(STORE_ATTR_SLOT) { - PyTypeObject *owner = TYPESTACK_PEEK(1); - PyTypeObject *value = TYPESTACK_PEEK(2); STACK_SHRINK(2); break; } TARGET(COMPARE_OP) { - PyTypeObject *right = TYPESTACK_PEEK(1); - PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); break; } TARGET(COMPARE_AND_BRANCH) { - PyTypeObject *right = TYPESTACK_PEEK(1); - PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(2); break; } TARGET(COMPARE_AND_BRANCH_FLOAT) { - PyTypeObject *right = TYPESTACK_PEEK(1); - PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(2); break; } TARGET(COMPARE_AND_BRANCH_INT) { - PyTypeObject *right = TYPESTACK_PEEK(1); - PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(2); break; } TARGET(COMPARE_AND_BRANCH_STR) { - PyTypeObject *right = TYPESTACK_PEEK(1); - PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(2); break; } TARGET(IS_OP) { - PyTypeObject *right = TYPESTACK_PEEK(1); - PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); TYPESTACK_POKE(1, &PyBool_Type); break; } TARGET(CONTAINS_OP) { - PyTypeObject *right = TYPESTACK_PEEK(1); - PyTypeObject *left = TYPESTACK_PEEK(2); STACK_SHRINK(1); TYPESTACK_POKE(1, &PyBool_Type); break; } TARGET(CHECK_EG_MATCH) { - PyTypeObject *match_type = TYPESTACK_PEEK(1); - PyTypeObject *exc_value = TYPESTACK_PEEK(2); TYPESTACK_POKE(1, NULL); TYPESTACK_POKE(2, NULL); break; } TARGET(CHECK_EXC_MATCH) { - PyTypeObject *right = TYPESTACK_PEEK(1); - PyTypeObject *left = TYPESTACK_PEEK(2); TYPESTACK_POKE(1, &PyBool_Type); break; } TARGET(IMPORT_NAME) { - PyTypeObject *fromlist = TYPESTACK_PEEK(1); - PyTypeObject *level = TYPESTACK_PEEK(2); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); break; } TARGET(IMPORT_FROM) { - PyTypeObject *from = TYPESTACK_PEEK(1); STACK_GROW(1); TYPESTACK_POKE(1, NULL); break; @@ -781,49 +649,41 @@ } TARGET(POP_JUMP_IF_FALSE) { - PyTypeObject *cond = TYPESTACK_PEEK(1); STACK_SHRINK(1); break; } TARGET(BB_TEST_POP_IF_FALSE) { - PyTypeObject *cond = TYPESTACK_PEEK(1); STACK_SHRINK(1); break; } TARGET(POP_JUMP_IF_TRUE) { - PyTypeObject *cond = TYPESTACK_PEEK(1); STACK_SHRINK(1); break; } TARGET(BB_TEST_POP_IF_TRUE) { - PyTypeObject *cond = TYPESTACK_PEEK(1); STACK_SHRINK(1); break; } TARGET(POP_JUMP_IF_NOT_NONE) { - PyTypeObject *value = TYPESTACK_PEEK(1); STACK_SHRINK(1); break; } TARGET(BB_TEST_POP_IF_NOT_NONE) { - PyTypeObject *value = TYPESTACK_PEEK(1); STACK_SHRINK(1); break; } TARGET(POP_JUMP_IF_NONE) { - PyTypeObject *value = TYPESTACK_PEEK(1); STACK_SHRINK(1); break; } TARGET(BB_TEST_POP_IF_NONE) { - PyTypeObject *value = TYPESTACK_PEEK(1); STACK_SHRINK(1); break; } @@ -857,16 +717,12 @@ } TARGET(GET_LEN) { - PyTypeObject *obj = TYPESTACK_PEEK(1); STACK_GROW(1); TYPESTACK_POKE(1, &PyLong_Type); break; } TARGET(MATCH_CLASS) { - PyTypeObject *names = TYPESTACK_PEEK(1); - PyTypeObject *type = TYPESTACK_PEEK(2); - PyTypeObject *subject = TYPESTACK_PEEK(3); STACK_SHRINK(2); TYPESTACK_POKE(1, NULL); break; @@ -891,60 +747,51 @@ } TARGET(GET_ITER) { - PyTypeObject *iterable = TYPESTACK_PEEK(1); TYPESTACK_POKE(1, NULL); break; } TARGET(GET_YIELD_FROM_ITER) { - PyTypeObject *iterable = TYPESTACK_PEEK(1); TYPESTACK_POKE(1, NULL); break; } TARGET(FOR_ITER) { - PyTypeObject *iter = TYPESTACK_PEEK(1); STACK_GROW(1); TYPESTACK_POKE(1, NULL); break; } TARGET(BB_TEST_ITER) { - PyTypeObject *iter = TYPESTACK_PEEK(1); STACK_GROW(1); TYPESTACK_POKE(1, NULL); break; } TARGET(FOR_ITER_LIST) { - PyTypeObject *iter = TYPESTACK_PEEK(1); STACK_GROW(1); TYPESTACK_POKE(1, NULL); break; } TARGET(FOR_ITER_TUPLE) { - PyTypeObject *iter = TYPESTACK_PEEK(1); STACK_GROW(1); TYPESTACK_POKE(1, NULL); break; } TARGET(FOR_ITER_RANGE) { - PyTypeObject *iter = TYPESTACK_PEEK(1); STACK_GROW(1); TYPESTACK_POKE(1, NULL); break; } TARGET(FOR_ITER_GEN) { - PyTypeObject *iter = TYPESTACK_PEEK(1); STACK_GROW(1); break; } TARGET(BEFORE_ASYNC_WITH) { - PyTypeObject *mgr = TYPESTACK_PEEK(1); STACK_GROW(1); TYPESTACK_POKE(1, NULL); TYPESTACK_POKE(2, NULL); @@ -952,7 +799,6 @@ } TARGET(BEFORE_WITH) { - PyTypeObject *mgr = TYPESTACK_PEEK(1); STACK_GROW(1); TYPESTACK_POKE(1, NULL); TYPESTACK_POKE(2, NULL); @@ -972,7 +818,6 @@ } TARGET(LOAD_ATTR_METHOD_WITH_VALUES) { - PyTypeObject *self = TYPESTACK_PEEK(1); STACK_GROW(((oparg & 1) ? 1 : 0)); TYPESTACK_POKE(1, NULL); if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } @@ -980,7 +825,6 @@ } TARGET(LOAD_ATTR_METHOD_NO_DICT) { - PyTypeObject *self = TYPESTACK_PEEK(1); STACK_GROW(((oparg & 1) ? 1 : 0)); TYPESTACK_POKE(1, NULL); if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } @@ -988,7 +832,6 @@ } TARGET(LOAD_ATTR_METHOD_LAZY_DICT) { - PyTypeObject *self = TYPESTACK_PEEK(1); STACK_GROW(((oparg & 1) ? 1 : 0)); TYPESTACK_POKE(1, NULL); if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } @@ -1000,9 +843,6 @@ } TARGET(CALL) { - PyTypeObject **args = &TYPESTACK_PEEK(oparg); - PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); - PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); STACK_SHRINK(oparg); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); @@ -1010,35 +850,24 @@ } TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { - PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); - PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); STACK_SHRINK(oparg); STACK_SHRINK(1); break; } TARGET(CALL_PY_EXACT_ARGS) { - PyTypeObject **args = &TYPESTACK_PEEK(oparg); - PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); - PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); STACK_SHRINK(oparg); STACK_SHRINK(1); break; } TARGET(CALL_PY_WITH_DEFAULTS) { - PyTypeObject **args = &TYPESTACK_PEEK(oparg); - PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); - PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); STACK_SHRINK(oparg); STACK_SHRINK(1); break; } TARGET(CALL_NO_KW_TYPE_1) { - PyTypeObject **args = &TYPESTACK_PEEK(oparg); - PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); - PyTypeObject *null = TYPESTACK_PEEK(2 + oparg); STACK_SHRINK(oparg); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); @@ -1046,9 +875,6 @@ } TARGET(CALL_NO_KW_STR_1) { - PyTypeObject **args = &TYPESTACK_PEEK(oparg); - PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); - PyTypeObject *null = TYPESTACK_PEEK(2 + oparg); STACK_SHRINK(oparg); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); @@ -1056,9 +882,6 @@ } TARGET(CALL_NO_KW_TUPLE_1) { - PyTypeObject **args = &TYPESTACK_PEEK(oparg); - PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); - PyTypeObject *null = TYPESTACK_PEEK(2 + oparg); STACK_SHRINK(oparg); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); @@ -1066,9 +889,6 @@ } TARGET(CALL_BUILTIN_CLASS) { - PyTypeObject **args = &TYPESTACK_PEEK(oparg); - PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); - PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); STACK_SHRINK(oparg); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); @@ -1076,9 +896,6 @@ } TARGET(CALL_NO_KW_BUILTIN_O) { - PyTypeObject **args = &TYPESTACK_PEEK(oparg); - PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); - PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); STACK_SHRINK(oparg); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); @@ -1086,9 +903,6 @@ } TARGET(CALL_NO_KW_BUILTIN_FAST) { - PyTypeObject **args = &TYPESTACK_PEEK(oparg); - PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); - PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); STACK_SHRINK(oparg); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); @@ -1096,9 +910,6 @@ } TARGET(CALL_BUILTIN_FAST_WITH_KEYWORDS) { - PyTypeObject **args = &TYPESTACK_PEEK(oparg); - PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); - PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); STACK_SHRINK(oparg); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); @@ -1106,9 +917,6 @@ } TARGET(CALL_NO_KW_LEN) { - PyTypeObject **args = &TYPESTACK_PEEK(oparg); - PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); - PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); STACK_SHRINK(oparg); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); @@ -1116,9 +924,6 @@ } TARGET(CALL_NO_KW_ISINSTANCE) { - PyTypeObject **args = &TYPESTACK_PEEK(oparg); - PyTypeObject *callable = TYPESTACK_PEEK(1 + oparg); - PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); STACK_SHRINK(oparg); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); @@ -1126,17 +931,12 @@ } TARGET(CALL_NO_KW_LIST_APPEND) { - PyTypeObject **args = &TYPESTACK_PEEK(oparg); - PyTypeObject *self = TYPESTACK_PEEK(1 + oparg); - PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); STACK_SHRINK(oparg); STACK_SHRINK(1); break; } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { - PyTypeObject **args = &TYPESTACK_PEEK(oparg); - PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); STACK_SHRINK(oparg); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); @@ -1144,8 +944,6 @@ } TARGET(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS) { - PyTypeObject **args = &TYPESTACK_PEEK(oparg); - PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); STACK_SHRINK(oparg); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); @@ -1153,8 +951,6 @@ } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) { - PyTypeObject **args = &TYPESTACK_PEEK(oparg); - PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); STACK_SHRINK(oparg); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); @@ -1162,8 +958,6 @@ } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_FAST) { - PyTypeObject **args = &TYPESTACK_PEEK(oparg); - PyTypeObject *method = TYPESTACK_PEEK(2 + oparg); STACK_SHRINK(oparg); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); @@ -1171,9 +965,6 @@ } TARGET(CALL_FUNCTION_EX) { - PyTypeObject *kwargs = (oparg & 1) ? TYPESTACK_PEEK(((oparg & 1) ? 1 : 0)) : NULL; - PyTypeObject *callargs = TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)); - PyTypeObject *func = TYPESTACK_PEEK(2 + ((oparg & 1) ? 1 : 0)); STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); TYPESTACK_POKE(1, NULL); @@ -1181,11 +972,6 @@ } TARGET(MAKE_FUNCTION) { - PyTypeObject *codeobj = TYPESTACK_PEEK(1); - PyTypeObject *closure = (oparg & 0x08) ? TYPESTACK_PEEK(1 + ((oparg & 0x08) ? 1 : 0)) : NULL; - PyTypeObject *annotations = (oparg & 0x04) ? TYPESTACK_PEEK(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0)) : NULL; - PyTypeObject *kwdefaults = (oparg & 0x02) ? TYPESTACK_PEEK(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0)) : NULL; - PyTypeObject *defaults = (oparg & 0x01) ? TYPESTACK_PEEK(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0)) : NULL; STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); TYPESTACK_POKE(1, NULL); break; @@ -1196,9 +982,6 @@ } TARGET(BUILD_SLICE) { - PyTypeObject *step = (oparg == 3) ? TYPESTACK_PEEK(((oparg == 3) ? 1 : 0)) : NULL; - PyTypeObject *stop = TYPESTACK_PEEK(1 + ((oparg == 3) ? 1 : 0)); - PyTypeObject *start = TYPESTACK_PEEK(2 + ((oparg == 3) ? 1 : 0)); STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); @@ -1206,8 +989,6 @@ } TARGET(FORMAT_VALUE) { - PyTypeObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? TYPESTACK_PEEK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)) : NULL; - PyTypeObject *value = TYPESTACK_PEEK(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); TYPESTACK_POKE(1, NULL); break; @@ -1221,8 +1002,6 @@ } TARGET(BINARY_OP) { - PyTypeObject *rhs = TYPESTACK_PEEK(1); - PyTypeObject *lhs = TYPESTACK_PEEK(2); STACK_SHRINK(1); TYPESTACK_POKE(1, NULL); break; diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 58ed38b65221e5..ab83895f1fabd2 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -337,11 +337,30 @@ def write_typeprop(self, out: Formatter) -> None: out.emit("Py_UNREACHABLE();") return + need_to_declare = [] + # Stack input is used in local effect + if self.local_effects and \ + isinstance(val := self.local_effects.value, LocalEffectVarStack): + need_to_declare.append(val.name) + # Stack input is used in output effect + for oeffect in self.output_effects: + if not (typ := oeffect.type_annotation): continue + if not isinstance(typ, StackVarInputVar): continue + if oeffect.name in self.unmoved_names: + print( + f"Warn: {self.name} type annotation for {oeffect.name} will be ignored " + "as it is unmoved") + continue + need_to_declare.append(typ.name) + # Write input stack effect variable declarations and initializations ieffects = list(reversed(self.input_effects)) usable_for_local_effect = {} all_input_effect_names = {} for i, ieffect in enumerate(ieffects): + + if ieffect.name not in need_to_declare: continue + isize = string_effect_size( list_effect_size([ieff for ieff in ieffects[: i + 1]]) ) @@ -396,8 +415,11 @@ def write_typeprop(self, out: Formatter) -> None: case StackVarTypeIndex(array=arr, index=idx): val = f"{'TYPELOCALS_GET' if arr == 'locals' else 'TYPECONST_GET'}({idx})" case StackVarInputVar(name=val): - ieffect, j = all_input_effect_names[val] - if len(oeffects) - i == len(ieffects) - j: + # We determined above that we don't need to write this stack effect + if val not in need_to_declare: + continue + # Unmoved var, don't need to write + if oeffect.name in self.unmoved_names: continue case _: typing.assert_never(typ) @@ -406,6 +428,10 @@ def write_typeprop(self, out: Formatter) -> None: else: out.emit(f"TYPESTACK_POKE({osize}, {val});") continue + + # Don't touch unmoved stack vars + if oeffect.name in self.unmoved_names: + continue # Just output null if oeffect.cond: From 24ded88163a2c0e003a8ea1ecc7c423bd3def077 Mon Sep 17 00:00:00 2001 From: Julia Date: Fri, 3 Mar 2023 12:23:36 +0800 Subject: [PATCH 059/280] Perf: Removed unneccessary type annotations in MATCH bytecode --- Python/bytecodes.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 05436c842ddb68..ef42a10c4d572e 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2178,19 +2178,19 @@ dummy_func( } } - inst(MATCH_MAPPING, (subject -- subject: *subject, res: PyBool_Type)) { + inst(MATCH_MAPPING, (subject -- subject, res: PyBool_Type)) { int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = Py_NewRef(match ? Py_True : Py_False); PREDICT(POP_JUMP_IF_FALSE); } - inst(MATCH_SEQUENCE, (subject -- subject: *subject, res: PyBool_Type)) { + inst(MATCH_SEQUENCE, (subject -- subject, res: PyBool_Type)) { int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = Py_NewRef(match ? Py_True : Py_False); PREDICT(POP_JUMP_IF_FALSE); } - inst(MATCH_KEYS, (subject, keys -- subject: *subject, keys: *keys, values_or_none)) { + inst(MATCH_KEYS, (subject, keys -- subject, keys, values_or_none)) { // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); ERROR_IF(values_or_none == NULL, error); From 223894439bcd10720e6c841a35cd599ceca62eec Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 4 Mar 2023 16:32:55 +0800 Subject: [PATCH 060/280] Support multi-file inputs --- Python/opcode_metadata.h | 5 +- Python/tier2_typepropagator.c.h | 3 +- Tools/cases_generator/generate_cases.py | 77 ++----------------------- 3 files changed, 9 insertions(+), 76 deletions(-) diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 97ad6a9dfe547b..dc15965d034a9b 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -1,5 +1,6 @@ -// This file is generated by Tools\cases_generator\generate_cases.py --metadata -// from Python\bytecodes.c +// This file is generated by Tools/cases_generator/generate_cases.py +// from: +// Python/bytecodes.c // Do not edit! #ifndef NEED_OPCODE_TABLES diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index 787d956eab0e72..ffbc68a62ae403 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -1,5 +1,6 @@ // This file is generated by Tools/cases_generator/generate_cases.py @TODO: make this a seperate argument -// from Python/bytecodes.c +// from: +// Python/bytecodes.c // Do not edit! TARGET(NOP) { diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 18d7f11dab6afe..5495b3c9f08f94 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -92,7 +92,6 @@ arg_parser.add_argument( "-u", - "--macromap", action="store_true", help=f"Generate macro to micro instruction map instead," f" along with the type for uop type guards" @@ -717,6 +716,9 @@ def parse(self) -> None: self.instrs = {} self.supers = {} self.macros = {} + self.macro_instrs = {} + self.macro_instdefs = [] + self.u_insts = [] self.families = {} instrs_idx: dict[str, int] = dict() @@ -1128,77 +1130,6 @@ def write_function( write_function("popped", popped_data) write_function("pushed", pushed_data) self.out.emit("") - - def write_macromap_and_typedata(self): - with open(self.output_filename, "w") as f: - # Write provenance header - f.write(f"// This file is generated by {THIS} --macromap\n") - f.write(f"// from {os.path.relpath(self.filename, ROOT)}\n") - f.write(f"// Do not edit!\n") - - # Create formatter; the rest of the code uses this - self.out = Formatter(f, 0) - # Header guard - self.out.emit("") - self.out.emit("#ifndef Py_INTERNAL_OPCODE_MACRO_TO_MICRO_H") - self.out.emit("#define Py_INTERNAL_OPCODE_MACRO_TO_MICRO_H") - self.out.emit("#ifdef __cplusplus") - self.out.emit('extern "C" {') - self.out.emit("#endif") - self.out.emit("") - self.out.emit("#ifndef Py_BUILD_CORE") - self.out.emit('# error "this header requires Py_BUILD_CORE define"') - self.out.emit("#endif") - self.out.emit('#include "opcode.h"') - self.out.emit("") - self.write_macromap() - self.write_uopguard_typedata() - # Header guard end - self.out.emit("#ifdef __cplusplus") - self.out.emit("}") - self.out.emit("#endif") - self.out.emit("#endif // Py_INTERNAL_OPCODE_MACRO_TO_MICRO") - - def write_macromap(self): - """Write the macro instruction to uop mapping to output file.""" - self.out.emit("extern const int _Py_MacroOpUOpCount[] = {") - macro_instrdef_names = set() - max_instr_len = 0 - for name, instr_def in self.instrs.items(): - if (macro_def := instr_def.inst) in self.macro_instdefs: - u_insts = macro_def.u_insts - instr_len = len(u_insts) - max_instr_len = max(instr_len, max_instr_len) - self.out.emit(f"[{macro_def.name}] = {instr_len},") - macro_instrdef_names.add(macro_def.name) - else: - self.out.emit(f"[{name}] = 1,") - self.out.emit("};") - self.out.emit("") - self.out.emit(f"extern const int _Py_MacroOpToUOp[][{max_instr_len}] = {{") - for macro_def in self.macro_instdefs: - u_insts = macro_def.u_insts - self.out.emit(f"[{macro_def.name}] = {{{', '.join(u_insts)}}},") - self.out.emit("};") - - def write_uopguard_typedata(self): - """Write the type information expected of each uop typeguard.""" - uop_to_type_output = {} - max_types = 0 - for instr_def in self.u_insts: - types = [] - for output in instr_def.outputs: - if isinstance(output, StackEffect) and output.type: - types.append(output.type) - if types: - max_types = max(max_types, len(types)) - uop_to_type_output[instr_def.name] = types - if max_types > 0: - self.out.emit(f"extern const PyTypeObject *_Py_UOpGuardTypes[][{max_types}] = {{") - for name, types in uop_to_type_output.items(): - self.out.emit(f"[{name}] = {{{', '.join(['&' + type_ for type_ in types])}}},") - self.out.emit("};") - def write_typepropagator(self) -> None: """Write the type propagator""" @@ -1206,7 +1137,7 @@ def write_typepropagator(self) -> None: with open(self.output_filename, "w") as f: # Write provenance header f.write(f"// This file is generated by {THIS} @TODO: make this a seperate argument\n") - f.write(f"// from {os.path.relpath(self.filename, ROOT).replace(os.path.sep, posixpath.sep)}\n") + f.write(self.from_source_files()) f.write(f"// Do not edit!\n") # Create formatter From ed371385bb7cfc1ca50756a26235a5a4e6f7f4ea Mon Sep 17 00:00:00 2001 From: Julia Date: Thu, 9 Mar 2023 12:30:47 +0800 Subject: [PATCH 061/280] Refactor: Setup parser.py and generate_cases.py in preparation for the more general type prop --- Python/bytecodes.c | 2 +- Tools/cases_generator/generate_cases.py | 20 +++++++++++----- Tools/cases_generator/parser.py | 32 ++++++++++++++++++------- 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 3f3593b49e51bd..f08711f527ca9c 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -298,7 +298,7 @@ dummy_func( U_INST(BINARY_OP_ADD_INT_REST); } - inst(BINARY_CHECK_INT, (left, right -- left : PyLong_Type, right : PyLong_Type)) { + inst(BINARY_CHECK_INT, (left, right -- left : <<= PyLong_Type, right : <<= PyLong_Type)) { assert(cframe.use_tracing == 0); bb_test = PyLong_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 5495b3c9f08f94..3064a68f40513c 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -16,7 +16,8 @@ from enum import Enum, auto import parser -from parser import StackEffect, StackVarTypeLiteral, StackVarTypeIndex, StackVarInputVar +from parser import StackEffect +from parser import TypeLiteralAnnotation, TypeIndexAnnotation, TypeInputAnnotation, TypeDerefAnnotation from parser import LocalEffect, LocalEffectVarLiteral, LocalEffectVarStack HERE = os.path.dirname(__file__) @@ -342,8 +343,8 @@ def write_typeprop(self, out: Formatter) -> None: # Stack input is used in output effect for oeffect in self.output_effects: if not (typ := oeffect.type_annotation): continue - if not isinstance(typ, StackVarInputVar): continue - if oeffect.name in self.unmoved_names: + if not isinstance(typ, TypeInputAnnotation): continue + if oeffect.name in self.unmoved_names and oeffect.name == typ.name: print( f"Warn: {self.name} type annotation for {oeffect.name} will be ignored " "as it is unmoved") @@ -407,17 +408,24 @@ def write_typeprop(self, out: Formatter) -> None: # Check if there's type info if typ := oeffect.type_annotation: match typ: - case StackVarTypeLiteral(literal=val): + case TypeLiteralAnnotation(literal=val): if val != "NULL": val = f"&{val}" - case StackVarTypeIndex(array=arr, index=idx): + case TypeIndexAnnotation(array=arr, index=idx): val = f"{'TYPELOCALS_GET' if arr == 'locals' else 'TYPECONST_GET'}({idx})" - case StackVarInputVar(name=val): + case TypeInputAnnotation(name=val): # We determined above that we don't need to write this stack effect if val not in need_to_declare: continue # Unmoved var, don't need to write if oeffect.name in self.unmoved_names: continue + case TypeDerefAnnotation(typeval=typeval): + match typeval: + case TypeLiteralAnnotation(literal=val): + # TODO + continue + case _: + typing.assert_never(typeval) case _: typing.assert_never(typ) if oeffect.cond: diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index 26b55869a0c191..372929f760ca43 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -69,28 +69,36 @@ class Block(Node): @dataclass -class StackVarTypeLiteral(Node): +class TypeLiteralAnnotation(Node): literal: str @dataclass -class StackVarTypeIndex(Node): +class TypeIndexAnnotation(Node): array: Literal["locals", "consts"] index: str @dataclass -class StackVarInputVar(Node): +class TypeInputAnnotation(Node): name: str +@dataclass +class TypeDerefAnnotation(Node): + typeval: TypeLiteralAnnotation # Support more types as needed -StackVarType: TypeAlias = StackVarTypeLiteral | StackVarTypeIndex | StackVarInputVar +TypeAnnotation: TypeAlias = ( + TypeLiteralAnnotation + | TypeIndexAnnotation + | TypeInputAnnotation + | TypeDerefAnnotation +) @dataclass class StackEffect(Node): name: str type: str = "" # Optional `:type` - type_annotation: StackVarType | None = None # Default is None + type_annotation: TypeAnnotation | None = None # Default is None cond: str = "" # Optional `if (cond)` size: str = "" # Optional `[size]` # Note: size cannot be combined with type or cond @@ -348,21 +356,27 @@ def stack_effect(self) -> StackEffect | None: return StackEffect(tkn.text, _type, type_annotation, cond_text, size_text) @contextual - def stackvar_type(self) -> StackVarType | None: + def stackvar_type(self) -> TypeAnnotation | None: if id := self.expect(lx.IDENTIFIER): idstr = id.text.strip() if not self.expect(lx.LBRACKET): - return StackVarTypeLiteral(idstr) + return TypeLiteralAnnotation(idstr) if idstr not in ["locals", "consts"]: return if id := self.expect(lx.IDENTIFIER): index = id.text.strip() self.require(lx.RBRACKET) - return StackVarTypeIndex( + return TypeIndexAnnotation( "locals" if idstr == "locals" else "consts", index) elif self.expect(lx.TIMES): id = self.require(lx.IDENTIFIER) - return StackVarInputVar(id.text.strip()) + return TypeInputAnnotation(id.text.strip()) + elif self.expect(lx.LSHIFTEQUAL): + typeval = self.stackvar_type() + # TODO: Support other type annotations as needed + assert isinstance(typeval, TypeLiteralAnnotation), \ + "TypeDerefAnnotation only supports Type Literals" + return TypeDerefAnnotation(typeval) @contextual From 066df400e2eec62f54a068a0ee3fcb841b1b8979 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 13 Mar 2023 00:25:56 +0800 Subject: [PATCH 062/280] Add dis support for tier 2 code objects --- Include/cpython/code.h | 2 -- Lib/dis.py | 25 +++++++++++++++++-------- Objects/codeobject.c | 11 +++++++++++ Python/tier2.c | 3 ++- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 69adfcefd82722..69ceeb8d1bddfb 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -86,8 +86,6 @@ typedef struct _PyTier2BBSpace { _Py_CODEUNIT u_code[1]; } _PyTier2BBSpace; -#define _PyTier2BBSpace_NBYTES_USED(space) sizeof(_PyTier2BBSpace) + space->max_capacity - // Tier 2 info stored in the code object. Lazily allocated. typedef struct _PyTier2Info { /* the tier 2 basic block to execute (if any) */ diff --git a/Lib/dis.py b/Lib/dis.py index 9edde6ae8258da..8f7d3de20ec257 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -13,6 +13,7 @@ _nb_ops, _specializations, _specialized_instructions, + _uops, ) __all__ = ["code_info", "dis", "disassemble", "distb", "disco", @@ -52,6 +53,10 @@ _all_opname[spec_op] = specialized _all_opmap[specialized] = spec_op +_empty_slot = [slot for slot, name in enumerate(_all_opname) if name.startswith("<")] +for uop_opcode, uop in zip(_empty_slot, _uops): + _all_opname[uop_opcode] = uop + deoptmap = { specialized: base for base, family in _specializations.items() for specialized in family } @@ -69,7 +74,8 @@ def _try_compile(source, name): c = compile(source, name, 'exec') return c -def dis(x=None, *, file=None, depth=None, show_caches=False, adaptive=False): +def dis(x=None, *, file=None, depth=None, show_caches=False, adaptive=False, + tier2=False): """Disassemble classes, methods, functions, and other compiled objects. With no argument, disassemble the last traceback. @@ -105,7 +111,7 @@ def dis(x=None, *, file=None, depth=None, show_caches=False, adaptive=False): print("Sorry:", msg, file=file) print(file=file) elif hasattr(x, 'co_code'): # Code object - _disassemble_recursive(x, file=file, depth=depth, show_caches=show_caches, adaptive=adaptive) + _disassemble_recursive(x, file=file, depth=depth, show_caches=show_caches, adaptive=adaptive, tier2=tier2) elif isinstance(x, (bytes, bytearray)): # Raw bytecode _disassemble_bytes(x, file=file, show_caches=show_caches) elif isinstance(x, str): # Source code @@ -188,7 +194,9 @@ def _deoptop(op): name = _all_opname[op] return _all_opmap[deoptmap[name]] if name in deoptmap else op -def _get_code_array(co, adaptive): +def _get_code_array(co, adaptive, tier2=False): + if tier2: + return co._co_code_tier2 return co._co_code_adaptive if adaptive else co.co_code def code_info(x): @@ -525,18 +533,18 @@ def _get_instructions_bytes(code, varname_from_oparg=None, Positions(*next(co_positions, ())) ) -def disassemble(co, lasti=-1, *, file=None, show_caches=False, adaptive=False): +def disassemble(co, lasti=-1, *, file=None, show_caches=False, adaptive=False, tier2=False): """Disassemble a code object.""" linestarts = dict(findlinestarts(co)) exception_entries = _parse_exception_table(co) - _disassemble_bytes(_get_code_array(co, adaptive), + _disassemble_bytes(_get_code_array(co, adaptive, tier2), lasti, co._varname_from_oparg, co.co_names, co.co_consts, linestarts, file=file, exception_entries=exception_entries, co_positions=co.co_positions(), show_caches=show_caches) -def _disassemble_recursive(co, *, file=None, depth=None, show_caches=False, adaptive=False): - disassemble(co, file=file, show_caches=show_caches, adaptive=adaptive) +def _disassemble_recursive(co, *, file=None, depth=None, show_caches=False, adaptive=False, tier2=False): + disassemble(co, file=file, show_caches=show_caches, adaptive=adaptive, tier2=tier2) if depth is None or depth > 0: if depth is not None: depth = depth - 1 @@ -545,7 +553,8 @@ def _disassemble_recursive(co, *, file=None, depth=None, show_caches=False, adap print(file=file) print("Disassembly of %r:" % (x,), file=file) _disassemble_recursive( - x, file=file, depth=depth, show_caches=show_caches, adaptive=adaptive + x, file=file, depth=depth, show_caches=show_caches, adaptive=adaptive, + tier2=tier2 ) def _disassemble_bytes(code, lasti=-1, varname_from_oparg=None, diff --git a/Objects/codeobject.c b/Objects/codeobject.c index f5f5f6c1db802d..18f294134e7084 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1998,9 +1998,20 @@ code_getcode(PyCodeObject *code, void *closure) return _PyCode_GetCode(code); } +static PyObject * +code_getcodetier2(PyCodeObject *code, void *closure) +{ + if (code->_tier2_info == NULL) { + return PyBytes_FromStringAndSize("", 0); + } + return PyBytes_FromStringAndSize(code->_tier2_info->_bb_space->u_code, + code->_tier2_info->_bb_space->water_level); +} + static PyGetSetDef code_getsetlist[] = { {"co_lnotab", (getter)code_getlnotab, NULL, NULL}, {"_co_code_adaptive", (getter)code_getcodeadaptive, NULL, NULL}, + {"_co_code_tier2", (getter)code_getcodetier2, NULL, NULL}, // The following old names are kept for backward compatibility. {"co_varnames", (getter)code_getvarnames, NULL, NULL}, {"co_cellvars", (getter)code_getcellvars, NULL, NULL}, diff --git a/Python/tier2.c b/Python/tier2.c index c49ee8eea1dda8..aa0be4b90489f9 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -821,11 +821,12 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, } } + _PyTier2TypeContext *type_context_copy = NULL; end: // Create the tier 2 BB // Make a copy of the type context - _PyTier2TypeContext *type_context_copy = _PyTier2TypeContext_Copy(starting_type_context); + type_context_copy = _PyTier2TypeContext_Copy(starting_type_context); if (type_context_copy == NULL) { return NULL; } From abb95481611db188cf393c811f3a595bb2823be1 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 13 Mar 2023 02:31:15 +0800 Subject: [PATCH 063/280] Add Jump offsets to dis --- Lib/dis.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/Lib/dis.py b/Lib/dis.py index 8f7d3de20ec257..6648e477cbe565 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -53,9 +53,14 @@ _all_opname[spec_op] = specialized _all_opmap[specialized] = spec_op +_bb_jumps = [] +_uop_hasoparg = [] _empty_slot = [slot for slot, name in enumerate(_all_opname) if name.startswith("<")] for uop_opcode, uop in zip(_empty_slot, _uops): _all_opname[uop_opcode] = uop + if uop.startswith('BB_BRANCH') or uop.startswith('BB_JUMP'): + _bb_jumps.append(uop_opcode) + _uop_hasoparg.append(uop_opcode) deoptmap = { specialized: base for base, family in _specializations.items() for specialized in family @@ -339,7 +344,8 @@ def _disassemble(self, lineno_width=3, mark_as_current=False, offset_width=4): return ' '.join(fields).rstrip() -def get_instructions(x, *, first_line=None, show_caches=False, adaptive=False): +def get_instructions(x, *, first_line=None, show_caches=False, adaptive=False, + tier2=False): """Iterator for the opcodes in methods, functions or code Generates a series of Instruction named tuples giving the details of @@ -356,7 +362,7 @@ def get_instructions(x, *, first_line=None, show_caches=False, adaptive=False): line_offset = first_line - co.co_firstlineno else: line_offset = 0 - return _get_instructions_bytes(_get_code_array(co, adaptive), + return _get_instructions_bytes(_get_code_array(co, adaptive, tier2), co._varname_from_oparg, co.co_names, co.co_consts, linestarts, line_offset, @@ -485,6 +491,12 @@ def _get_instructions_bytes(code, varname_from_oparg=None, elif deop in hasjabs: argval = arg*2 argrepr = "to " + repr(argval) + elif deop in _bb_jumps: + print("HI") + signed_arg = -arg if _is_backward_jump(deop) else arg + argval = offset + 2 + signed_arg*2 + argval += 2 * caches + argrepr = "to " + repr(argval) elif deop in hasjrel: signed_arg = -arg if _is_backward_jump(deop) else arg argval = offset + 2 + signed_arg*2 @@ -620,7 +632,7 @@ def _unpack_opargs(code): op = code[i] deop = _deoptop(op) caches = _inline_cache_entries[deop] - if deop in hasarg: + if deop in hasarg or deop in _uop_hasoparg: arg = code[i+1] | extended_arg extended_arg = (arg << 8) if deop == EXTENDED_ARG else 0 # The oparg is stored as a signed integer @@ -715,7 +727,8 @@ class Bytecode: Iterating over this yields the bytecode operations as Instruction instances. """ - def __init__(self, x, *, first_line=None, current_offset=None, show_caches=False, adaptive=False): + def __init__(self, x, *, first_line=None, current_offset=None, show_caches=False, + adaptive=False, tier2=False): self.codeobj = co = _get_code_object(x) if first_line is None: self.first_line = co.co_firstlineno @@ -729,10 +742,11 @@ def __init__(self, x, *, first_line=None, current_offset=None, show_caches=False self.exception_entries = _parse_exception_table(co) self.show_caches = show_caches self.adaptive = adaptive + self.tier2 = tier2 def __iter__(self): co = self.codeobj - return _get_instructions_bytes(_get_code_array(co, self.adaptive), + return _get_instructions_bytes(_get_code_array(co, self.adaptive, self.tier2), co._varname_from_oparg, co.co_names, co.co_consts, self._linestarts, @@ -766,7 +780,7 @@ def dis(self): else: offset = -1 with io.StringIO() as output: - _disassemble_bytes(_get_code_array(co, self.adaptive), + _disassemble_bytes(_get_code_array(co, self.adaptive, self.tier2), varname_from_oparg=co._varname_from_oparg, names=co.co_names, co_consts=co.co_consts, linestarts=self._linestarts, From 52994f16a9d94739b13fcff2dc72639ee64bbb13 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 13 Mar 2023 18:51:48 +0800 Subject: [PATCH 064/280] Use type propagation to generate branchless ops --- Include/internal/pycore_code.h | 13 ++- Lib/dis.py | 3 +- Python/bytecodes.c | 16 +-- Python/ceval.c | 4 +- Python/generated_cases.c.h | 16 +-- Python/tier2.c | 189 ++++++++++++++++++++++++++++----- 6 files changed, 194 insertions(+), 47 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index f31a607d23f268..8d1b5599972de0 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -9,7 +9,9 @@ extern "C" { typedef struct { // Unique ID (for this code object) for this basic block. This indexes into // the PyTier2Info bb_data field. - uint16_t bb_id; + // The LSB indicates whether the bb branch is a type guard or not. + // To get the actual BB ID, do a right bit shift by one. + uint16_t bb_id_tagged; } _PyBBBranchCache; #define INLINE_CACHE_ENTRIES_BB_BRANCH CACHE_ENTRIES(_PyBBBranchCache) @@ -258,8 +260,13 @@ extern int _PyStaticCode_Init(PyCodeObject *co); extern _Py_CODEUNIT *_PyCode_Tier2Warmup(struct _PyInterpreterFrame *, _Py_CODEUNIT *); extern _Py_CODEUNIT *_PyTier2_GenerateNextBB( - struct _PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, - _Py_CODEUNIT **tier1_fallback, char gen_bb_requires_pop); + struct _PyInterpreterFrame *frame, + uint16_t bb_id_tagged, + _Py_CODEUNIT *curr_executing_instr, + int jumpby, + _Py_CODEUNIT **tier1_fallback, + char gen_bb_requires_pop, + char gen_bb_is_successor); extern _Py_CODEUNIT *_PyTier2_LocateJumpBackwardsBB( struct _PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, _Py_CODEUNIT **tier1_fallback); diff --git a/Lib/dis.py b/Lib/dis.py index 6648e477cbe565..9295e58d35f103 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -59,7 +59,8 @@ for uop_opcode, uop in zip(_empty_slot, _uops): _all_opname[uop_opcode] = uop if uop.startswith('BB_BRANCH') or uop.startswith('BB_JUMP'): - _bb_jumps.append(uop_opcode) + if uop.startswith('BB_JUMP'): + _bb_jumps.append(uop_opcode) _uop_hasoparg.append(uop_opcode) deoptmap = { diff --git a/Python/bytecodes.c b/Python/bytecodes.c index c1aa0d894f058a..3ceb2e622a73e1 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3300,7 +3300,8 @@ dummy_func( _py_set_opcode(next_instr - 1, BB_BRANCH_IF_FLAG_UNSET); // Generate consequent. t2_nextinstr = _PyTier2_GenerateNextBB( - frame, cache->bb_id, 0, &tier1_fallback, gen_bb_requires_pop); + frame, cache->bb_id_tagged, next_instr - 1, + 0, &tier1_fallback, gen_bb_requires_pop, bb_test); gen_bb_requires_pop = false; if (t2_nextinstr == NULL) { // Fall back to tier 1. @@ -3311,9 +3312,10 @@ dummy_func( else { // Rewrite self _py_set_opcode(next_instr - 1, BB_BRANCH_IF_FLAG_SET); - // Generate predicate. + // Generate alternative. t2_nextinstr = _PyTier2_GenerateNextBB( - frame, cache->bb_id, oparg, &tier1_fallback, gen_bb_requires_pop); + frame, cache->bb_id_tagged, next_instr - 1, + oparg, &tier1_fallback, gen_bb_requires_pop, bb_test); gen_bb_requires_pop = false; if (t2_nextinstr == NULL) { // Fall back to tier 1. @@ -3336,7 +3338,8 @@ dummy_func( _Py_CODEUNIT *tier1_fallback = NULL; t2_nextinstr = _PyTier2_GenerateNextBB( - frame, cache->bb_id, oparg, &tier1_fallback, gen_bb_requires_pop); + frame, cache->bb_id_tagged, next_instr - 1, + oparg, &tier1_fallback, gen_bb_requires_pop, bb_test); gen_bb_requires_pop = false; if (t2_nextinstr == NULL) { // Fall back to tier 1. @@ -3368,7 +3371,8 @@ dummy_func( // @TODO: Rewrite TEST intruction above to a JUMP above.. t2_nextinstr = _PyTier2_GenerateNextBB( - frame, cache->bb_id, oparg, &tier1_fallback, gen_bb_requires_pop); + frame, cache->bb_id_tagged, next_instr - 1, + oparg, &tier1_fallback, gen_bb_requires_pop, bb_test); gen_bb_requires_pop = false; if (t2_nextinstr == NULL) { // Fall back to tier 1. @@ -3398,7 +3402,7 @@ dummy_func( _Py_CODEUNIT *tier1_fallback = NULL; t2_nextinstr = _PyTier2_LocateJumpBackwardsBB( - frame, cache->bb_id, -oparg, &tier1_fallback); + frame, cache->bb_id_tagged, -oparg, &tier1_fallback); if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; diff --git a/Python/ceval.c b/Python/ceval.c index 4031dbbe427702..017f5e9aeb977e 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -726,12 +726,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int PyObject *kwnames = NULL; // Borrowed reference. Reset by CALL instructions. // true = successor // false = alternate - bool bb_test = true; + char bb_test = true; // For tier2 type propagation, handling of jump instructions with // runtime-dependent stack effect. // This flag is used to determine if the type context of a new bb // requires a stack element to be popped. - bool gen_bb_requires_pop = false; + char gen_bb_requires_pop = false; /* WARNING: Because the _PyCFrame lives on the C stack, * but can be accessed from a heap allocated object (tstate) diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index a0334ecee28441..e513ccd8963b54 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -4131,7 +4131,8 @@ _py_set_opcode(next_instr - 1, BB_BRANCH_IF_FLAG_UNSET); // Generate consequent. t2_nextinstr = _PyTier2_GenerateNextBB( - frame, cache->bb_id, 0, &tier1_fallback, gen_bb_requires_pop); + frame, cache->bb_id_tagged, next_instr - 1, + 0, &tier1_fallback, gen_bb_requires_pop, bb_test); gen_bb_requires_pop = false; if (t2_nextinstr == NULL) { // Fall back to tier 1. @@ -4142,9 +4143,10 @@ else { // Rewrite self _py_set_opcode(next_instr - 1, BB_BRANCH_IF_FLAG_SET); - // Generate predicate. + // Generate alternative. t2_nextinstr = _PyTier2_GenerateNextBB( - frame, cache->bb_id, oparg, &tier1_fallback, gen_bb_requires_pop); + frame, cache->bb_id_tagged, next_instr - 1, + oparg, &tier1_fallback, gen_bb_requires_pop, bb_test); gen_bb_requires_pop = false; if (t2_nextinstr == NULL) { // Fall back to tier 1. @@ -4167,7 +4169,8 @@ _Py_CODEUNIT *tier1_fallback = NULL; t2_nextinstr = _PyTier2_GenerateNextBB( - frame, cache->bb_id, oparg, &tier1_fallback, gen_bb_requires_pop); + frame, cache->bb_id_tagged, next_instr - 1, + oparg, &tier1_fallback, gen_bb_requires_pop, bb_test); gen_bb_requires_pop = false; if (t2_nextinstr == NULL) { // Fall back to tier 1. @@ -4203,7 +4206,8 @@ // @TODO: Rewrite TEST intruction above to a JUMP above.. t2_nextinstr = _PyTier2_GenerateNextBB( - frame, cache->bb_id, oparg, &tier1_fallback, gen_bb_requires_pop); + frame, cache->bb_id_tagged, next_instr - 1, + oparg, &tier1_fallback, gen_bb_requires_pop, bb_test); gen_bb_requires_pop = false; if (t2_nextinstr == NULL) { // Fall back to tier 1. @@ -4236,7 +4240,7 @@ _Py_CODEUNIT *tier1_fallback = NULL; t2_nextinstr = _PyTier2_LocateJumpBackwardsBB( - frame, cache->bb_id, -oparg, &tier1_fallback); + frame, cache->bb_id_tagged, -oparg, &tier1_fallback); if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; diff --git a/Python/tier2.c b/Python/tier2.c index aa0be4b90489f9..e808352c76a39a 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -435,25 +435,57 @@ emit_cache_entries(_Py_CODEUNIT *write_curr, int cache_entries) return write_curr; } +static inline void +write_bb_id(_PyBBBranchCache *cache, int bb_id, bool is_type_guard) { + assert((uint16_t)(bb_id) == bb_id); + uint16_t bb_id16 = (uint16_t)bb_id; + // Make sure MSB is unset, because we need to shift it. + assert((bb_id16 & 0x8000) == 0); + bb_id16 <<= 1; + bb_id16 |= is_type_guard; + cache->bb_id_tagged = bb_id16; +} + +#define BB_ID(bb_id_raw) (bb_id_raw >> 1) +#define BB_IS_TYPE_BRANCH(bb_id_raw) (bb_id_raw & 1) + + +static int type_guard_ladder[256] = { + BINARY_CHECK_INT, + -1, +}; + +static int type_guard_to_index[256] = { + [BINARY_CHECK_INT] = 0, +}; + + static inline _Py_CODEUNIT * -emit_type_guard(_Py_CODEUNIT *write_curr, _Py_CODEUNIT guard, int bb_id) +emit_type_guard(_Py_CODEUNIT *write_curr, int guard_opcode, int bb_id) { - *write_curr = guard; +#if BB_DEBUG + fprintf(stderr, "emitted type guard %p %s\n", write_curr, + _PyOpcode_OpName[guard_opcode]); +#endif + write_curr->op.code = guard_opcode; + write_curr->op.arg = type_guard_to_index[BINARY_CHECK_INT]; write_curr++; - //_py_set_opcode(write_curr, EXTENDED_ARG); - //write_curr->oparg = 0; - //write_curr++; _py_set_opcode(write_curr, BB_BRANCH); write_curr->op.arg = 0; write_curr++; _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_BB_BRANCH); - assert((uint16_t)(bb_id) == bb_id); - cache->bb_id = (uint16_t)(bb_id); + write_bb_id(cache, bb_id, true); return write_curr; } // Converts the tier 1 branch bytecode to tier 2 branch bytecode. +// This converts sequence of instructions like +// JUMP_IF_FALSE_OR_POP +// to +// BB_TEST_IF_FALSE_OR_POP +// BB_BRANCH +// CACHE (bb_id of the current BB << 1 | is_type_branch) static inline _Py_CODEUNIT * emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) { @@ -527,8 +559,7 @@ emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, write_curr++; _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_BB_BRANCH); - assert((uint16_t)(bb_id) == bb_id); - cache->bb_id = (uint16_t)(bb_id); + write_bb_id(cache, bb_id, false); return write_curr; } // FOR_ITER is also a special jump @@ -552,8 +583,7 @@ emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, write_curr++; _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_BB_BRANCH); - assert((uint16_t)(bb_id) == bb_id); - cache->bb_id = (uint16_t)(bb_id); + write_bb_id(cache, bb_id, false); return write_curr; } else { @@ -570,8 +600,7 @@ emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, write_curr++; _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_BB_BRANCH); - assert((uint16_t)(bb_id) == bb_id); - cache->bb_id = (uint16_t)(bb_id); + write_bb_id(cache, bb_id, false); return write_curr; } } @@ -676,6 +705,55 @@ add_metadata_to_jump_2d_array(_PyTier2Info *t2_info, _PyTier2BBMetadata *meta, return 0; } +// This converts sequence of instructions like +// BINARY_OP (ADD) +// to +// BINARY_CHECK_INT +// BB_BRANCH +// CACHE (bb_id of the current BB << 1 | is_type_branch) +// // The BINARY_ADD then goes to the next BB +static inline _Py_CODEUNIT * +infer_BINARY_OP_ADD( + bool *needs_guard, + _Py_CODEUNIT *prev_type_guard, + _Py_CODEUNIT raw_op, + _Py_CODEUNIT *write_curr, + _PyTier2TypeContext *type_context, + int bb_id) +{ + *needs_guard = false; + PyTypeObject *right = type_context->type_stack_ptr[-1]; + PyTypeObject *left = type_context->type_stack_ptr[-2]; + if (left == &PyLong_Type) { + if (right == &PyLong_Type) { + write_curr->op.code = BINARY_OP_ADD_INT_REST; + write_curr++; + type_propagate(BINARY_OP_ADD_INT_REST, 0, type_context, NULL); + return write_curr; + } + } + // Unknown, time to emit the chain of guards. + // First, we guesstimate using the current specialised op + *needs_guard = true; + if (raw_op.op.code == BINARY_OP_ADD_INT) { + return emit_type_guard(write_curr, BINARY_CHECK_INT, bb_id); + } + // If there current op isn't specialised, we just do the general ladder. + if (prev_type_guard == NULL) { + return emit_type_guard(write_curr, BINARY_CHECK_INT, bb_id); + } + else { + int next_guard = type_guard_ladder[type_guard_to_index[prev_type_guard->op.code] + 1]; + if (next_guard != -1) { + return emit_type_guard(write_curr, next_guard, bb_id); + } + // End of ladder, fall through + } + // Unknown, just emit the same opcode, don't bother emitting guard. + // Fall through and let the code generator handle. + return NULL; +} + // Detects a BB from the current instruction start to the end of the first basic block it sees. // Then emits the instructions into the bb space. // @@ -688,12 +766,17 @@ add_metadata_to_jump_2d_array(_PyTier2Info *t2_info, _PyTier2BBMetadata *meta, // // Note: a BB end also includes a type guard. _PyTier2BBMetadata * -_PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, +_PyTier2_Code_DetectAndEmitBB( + PyCodeObject *co, + _PyTier2BBSpace *bb_space, + _Py_CODEUNIT *prev_type_guard, _Py_CODEUNIT *tier1_start, // starting_type_context will be modified in this function, // do make a copy if needed before calling this function _PyTier2TypeContext *starting_type_context) { + assert(prev_type_guard == NULL || + prev_type_guard->op.code == BINARY_CHECK_INT); #define END() goto end; #define JUMPBY(x) i += x + 1; #define DISPATCH() write_i = emit_i(write_i, opcode, oparg); \ @@ -708,6 +791,7 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // There are only two cases that a BB ends. // 1. If there's a branch instruction / scope exit. // 2. If there's a type guard. + bool needs_guard = 0; _PyTier2BBMetadata *meta = NULL; _PyTier2BBMetadata *temp_meta = NULL; @@ -734,9 +818,6 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // Just because an instruction requires a guard doesn't mean it's the end of a BB. // We need to check whether we can eliminate the guard based on the current type context. - // int how_many_guards = 0; - // _Py_CODEUNIT guard_instr; - // _Py_CODEUNIT action; dispatch_opcode: switch (opcode) { @@ -753,6 +834,29 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, // So we tell the BB to skip over it. t2_start++; DISPATCH(); + case BINARY_OP: + if (oparg == NB_ADD) { + // Add operation. Need to check if we can infer types. + _Py_CODEUNIT *possible_next = infer_BINARY_OP_ADD(&needs_guard, + prev_type_guard, + *curr, + write_i, starting_type_context, + co->_tier2_info->bb_data_curr); + if (possible_next == NULL) { + DISPATCH(); + } + write_i = possible_next; + if (needs_guard) { + // Point to the same instruction, because in this BB we emit + // the guard. + // The next BB emits the instruction. + i--; + END(); + } + i += caches; + continue; + } + DISPATCH() default: #if BB_DEBUG || TYPEPROP_DEBUG fprintf(stderr, "offset: %Id\n", curr - _PyCode_CODE(co)); @@ -844,7 +948,8 @@ _PyTier2_Code_DetectAndEmitBB(PyCodeObject *co, _PyTier2BBSpace *bb_space, } if (starts_with_backwards_jump_target) { // Add the basic block to the jump ids - if (add_metadata_to_jump_2d_array(t2_info, temp_meta, backwards_jump_target_offset) < 0) { + if (add_metadata_to_jump_2d_array(t2_info, temp_meta, + backwards_jump_target_offset) < 0) { PyMem_Free(meta); if (meta != temp_meta) { PyMem_Free(temp_meta); @@ -1114,7 +1219,7 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) goto cleanup; } _PyTier2BBMetadata *meta = _PyTier2_Code_DetectAndEmitBB( - co, bb_space, + co, bb_space, NULL, _PyCode_CODE(co), type_context); if (meta == NULL) { _PyTier2TypeContext_Free(type_context); @@ -1165,20 +1270,27 @@ _PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) // The first basic block created will always be directly after the current tier 2 code. // The second basic block created will always require a jump. _Py_CODEUNIT * -_PyTier2_GenerateNextBB(_PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, - _Py_CODEUNIT **tier1_fallback, char gen_bb_requires_pop) +_PyTier2_GenerateNextBB( + _PyInterpreterFrame *frame, + uint16_t bb_id_tagged, + _Py_CODEUNIT *curr_executing_instr, + int jumpby, + _Py_CODEUNIT **tier1_fallback, + char gen_bb_requires_pop, + char gen_bb_is_successor) { PyCodeObject *co = frame->f_code; assert(co->_tier2_info != NULL); - assert(bb_id <= co->_tier2_info->bb_data_curr); - _PyTier2BBMetadata *meta = co->_tier2_info->bb_data[bb_id]; + assert(BB_ID(bb_id_tagged) <= co->_tier2_info->bb_data_curr); + _PyTier2BBMetadata *meta = co->_tier2_info->bb_data[BB_ID(bb_id_tagged)]; _Py_CODEUNIT *tier1_end = meta->tier1_end + jumpby; *tier1_fallback = tier1_end; // Be a pessimist and assume we need to write the entire rest of code into the BB. // The size of the BB generated will definitely be equal to or smaller than this. _PyTier2BBSpace *space = _PyTier2_BBSpaceCheckAndReallocIfNeeded( frame->f_code, - _PyCode_NBYTES(co) - (tier1_end - _PyCode_CODE(co)) * sizeof(_Py_CODEUNIT)); + _PyCode_NBYTES(co) - + (tier1_end - _PyCode_CODE(co)) * sizeof(_Py_CODEUNIT)); if (space == NULL) { // DEOPTIMIZE TO TIER 1? return NULL; @@ -1196,8 +1308,26 @@ _PyTier2_GenerateNextBB(_PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, if (gen_bb_requires_pop) { type_context_copy->type_stack_ptr--; } + // For type branches, they directly precede the bb branch instruction + _Py_CODEUNIT *prev_type_guard = BB_IS_TYPE_BRANCH(bb_id_tagged) + ? curr_executing_instr - 1 : NULL; + if (gen_bb_is_successor && prev_type_guard != NULL) { + // Is a type branch, so the previous instruction shouldn't be + // one of those conditional pops. + assert(!gen_bb_requires_pop); + // Propagate the type guard information. +#ifdef TYPEPROP_DEBUG + fprintf(stderr, + " [-] Previous predicate BB ended with a type guard: %s\n", + _PyOpcode_OpName[prev_type_guard->op.code]); +#endif + type_propagate(prev_type_guard->op.code, + prev_type_guard->op.arg, type_context_copy, NULL); + } _PyTier2BBMetadata *metadata = _PyTier2_Code_DetectAndEmitBB( - frame->f_code, space, tier1_end, + frame->f_code, space, + prev_type_guard, + tier1_end, type_context_copy); if (metadata == NULL) { _PyTier2TypeContext_Free(type_context_copy); @@ -1207,13 +1337,13 @@ _PyTier2_GenerateNextBB(_PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, } _Py_CODEUNIT * -_PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, +_PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id_tagged, int jumpby, _Py_CODEUNIT **tier1_fallback) { PyCodeObject *co = frame->f_code; assert(co->_tier2_info != NULL); - assert(bb_id <= co->_tier2_info->bb_data_curr); - _PyTier2BBMetadata *meta = co->_tier2_info->bb_data[bb_id]; + assert(BB_ID(bb_id_tagged) <= co->_tier2_info->bb_data_curr); + _PyTier2BBMetadata *meta = co->_tier2_info->bb_data[BB_ID(bb_id_tagged)]; // The jump target _Py_CODEUNIT *tier1_jump_target = meta->tier1_end + jumpby; *tier1_fallback = tier1_jump_target; @@ -1221,7 +1351,8 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id, int j // The size of the BB generated will definitely be equal to or smaller than this. _PyTier2BBSpace *space = _PyTier2_BBSpaceCheckAndReallocIfNeeded( frame->f_code, - _PyCode_NBYTES(co) - (tier1_jump_target - _PyCode_CODE(co)) * sizeof(_Py_CODEUNIT)); + _PyCode_NBYTES(co) - + (tier1_jump_target - _PyCode_CODE(co)) * sizeof(_Py_CODEUNIT)); if (space == NULL) { // DEOPTIMIZE TO TIER 1? return NULL; From 1351aef5e225b0f10912157c797e9cef521186ca Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 13 Mar 2023 21:49:37 +0800 Subject: [PATCH 065/280] Copy specialised ops, ladder the type guards --- Lib/dis.py | 2 ++ Python/tier2.c | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Lib/dis.py b/Lib/dis.py index 9295e58d35f103..9d3cc60e7f57f7 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -61,6 +61,8 @@ if uop.startswith('BB_BRANCH') or uop.startswith('BB_JUMP'): if uop.startswith('BB_JUMP'): _bb_jumps.append(uop_opcode) + if uop.startswith('BB_BRANCH'): + _inline_cache_entries[uop_opcode] = 1 _uop_hasoparg.append(uop_opcode) deoptmap = { diff --git a/Python/tier2.c b/Python/tier2.c index e808352c76a39a..08f4896d84c30a 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -735,7 +735,7 @@ infer_BINARY_OP_ADD( // Unknown, time to emit the chain of guards. // First, we guesstimate using the current specialised op *needs_guard = true; - if (raw_op.op.code == BINARY_OP_ADD_INT) { + if (raw_op.op.code == BINARY_OP_ADD_INT && prev_type_guard == NULL) { return emit_type_guard(write_curr, BINARY_CHECK_INT, bb_id); } // If there current op isn't specialised, we just do the general ladder. @@ -779,7 +779,7 @@ _PyTier2_Code_DetectAndEmitBB( prev_type_guard->op.code == BINARY_CHECK_INT); #define END() goto end; #define JUMPBY(x) i += x + 1; -#define DISPATCH() write_i = emit_i(write_i, opcode, oparg); \ +#define DISPATCH() write_i = emit_i(write_i, specop, oparg); \ write_i = copy_cache_entries(write_i, curr+1, caches); \ i += caches; \ type_propagate(opcode, oparg, starting_type_context, consts); \ @@ -812,7 +812,8 @@ _PyTier2_Code_DetectAndEmitBB( for (; i < Py_SIZE(co); i++) { _Py_CODEUNIT *curr = _PyCode_CODE(co) + i; _Py_CODEUNIT *next_instr = curr + 1; - int opcode = _PyOpcode_Deopt[_Py_OPCODE(*curr)]; + int specop = _Py_OPCODE(*curr); + int opcode = _PyOpcode_Deopt[specop]; int oparg = _Py_OPARG(*curr); int caches = _PyOpcode_Caches[opcode]; From eccd7e1729ba957cdc0ba7daa7d3bb15d3efb059 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 13 Mar 2023 22:28:59 +0800 Subject: [PATCH 066/280] Add float support --- Include/internal/pycore_opcode.h | 6 ++---- Include/opcode.h | 4 +++- Lib/opcode.py | 5 +++-- Python/bytecodes.c | 9 +++++++++ Python/generated_cases.c.h | 28 +++++++++++++++++++++++++++- Python/opcode_metadata.h | 10 ++++++++++ Python/tier2.c | 30 ++++++++++++++++++++---------- Python/tier2_typepropagator.c.h | 12 ++++++++++++ 8 files changed, 86 insertions(+), 18 deletions(-) diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index ce742bad98f079..5be22719a3aec6 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -427,9 +427,9 @@ static const char *const _PyOpcode_OpName[263] = { [BB_TEST_POP_IF_NONE] = "BB_TEST_POP_IF_NONE", [BB_JUMP_BACKWARD_LAZY] = "BB_JUMP_BACKWARD_LAZY", [BINARY_CHECK_INT] = "BINARY_CHECK_INT", + [BINARY_CHECK_FLOAT] = "BINARY_CHECK_FLOAT", [BINARY_OP_ADD_INT_REST] = "BINARY_OP_ADD_INT_REST", - [191] = "<191>", - [192] = "<192>", + [BINARY_OP_ADD_FLOAT_REST] = "BINARY_OP_ADD_FLOAT_REST", [193] = "<193>", [194] = "<194>", [195] = "<195>", @@ -505,8 +505,6 @@ static const char *const _PyOpcode_OpName[263] = { #define EXTRA_CASES \ - case 191: \ - case 192: \ case 193: \ case 194: \ case 195: \ diff --git a/Include/opcode.h b/Include/opcode.h index 7f0b02ab7687e2..f5c6d7c5138c09 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -279,7 +279,9 @@ extern "C" { #define BB_TEST_POP_IF_NONE 187 #define BB_JUMP_BACKWARD_LAZY 188 #define BINARY_CHECK_INT 189 -#define BINARY_OP_ADD_INT_REST 190 +#define BINARY_CHECK_FLOAT 190 +#define BINARY_OP_ADD_INT_REST 191 +#define BINARY_OP_ADD_FLOAT_REST 192 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/opcode.py b/Lib/opcode.py index 890982aaa85f67..2652223a50919d 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -458,6 +458,7 @@ def pseudo_op(name, op, real_ops): _macro_ops = [ 'BINARY_OP_ADD_INT', + 'BINARY_OP_ADD_FLOAT', ] _uops = [ # Tier 2 BB opcodes @@ -502,8 +503,8 @@ def pseudo_op(name, op, real_ops): # The benefit is that they save some dispatch overhead versus the # single operand forms. 'BINARY_CHECK_INT', - # 'BINARY_CHECK_FLOAT', + 'BINARY_CHECK_FLOAT', # 'BINARY_CHECK_STR', - # BINARY_OP_ADD_INT, 'BINARY_OP_ADD_INT_REST', + 'BINARY_OP_ADD_FLOAT_REST', ] diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 806c15123e3958..7e93f7acfa29f9 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -276,6 +276,15 @@ dummy_func( assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); + U_INST(BINARY_OP_ADD_FLOAT_REST); + } + + inst(BINARY_CHECK_FLOAT, (left, right -- left : PyFloat_Type, right : PyFloat_Type)) { + assert(cframe.use_tracing == 0); + bb_test = PyFloat_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); + } + + u_inst(BINARY_OP_ADD_FLOAT_REST, (left, right -- sum : PyFloat_Type)) { STAT_INC(BINARY_OP, hit); double dsum = ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 2281dad0534e1e..56a7fbb050b03e 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3,6 +3,14 @@ // Python/bytecodes.c // Do not edit! + #define UOP_BINARY_OP_ADD_FLOAT_REST() \ + do { \ + STAT_INC(BINARY_OP, hit);\ + double dsum = ((PyFloatObject *)left)->ob_fval +\ + ((PyFloatObject *)right)->ob_fval;\ + DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsum, sum);\ + } while (0) + #define UOP_BINARY_OP_ADD_INT_REST() \ do { \ STAT_INC(BINARY_OP, hit);\ @@ -380,13 +388,31 @@ assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); + UOP_BINARY_OP_ADD_FLOAT_REST(); + STACK_SHRINK(1); + stack_pointer[-1] = sum; + next_instr += 1; + DISPATCH(); + } + + TARGET(BINARY_CHECK_FLOAT) { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + assert(cframe.use_tracing == 0); + bb_test = PyFloat_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); + DISPATCH(); + } + + TARGET(BINARY_OP_ADD_FLOAT_REST) { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *sum; STAT_INC(BINARY_OP, hit); double dsum = ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsum, sum); STACK_SHRINK(1); stack_pointer[-1] = sum; - next_instr += 1; DISPATCH(); } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index c530134c2791cb..4a7209e7cf6c0d 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -61,6 +61,10 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 2; case BINARY_OP_ADD_FLOAT: return 2; + case BINARY_CHECK_FLOAT: + return 2; + case BINARY_OP_ADD_FLOAT_REST: + return 2; case BINARY_OP_ADD_INT: return 2; case BINARY_CHECK_INT: @@ -447,6 +451,10 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case BINARY_OP_ADD_FLOAT: return 1; + case BINARY_CHECK_FLOAT: + return 2; + case BINARY_OP_ADD_FLOAT_REST: + return 1; case BINARY_OP_ADD_INT: return 1; case BINARY_CHECK_INT: @@ -815,6 +823,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [BINARY_OP_ADD_UNICODE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, [BINARY_OP_INPLACE_ADD_UNICODE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [BINARY_OP_ADD_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, + [BINARY_CHECK_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [BINARY_OP_ADD_FLOAT_REST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [BINARY_OP_ADD_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, [BINARY_CHECK_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [BINARY_OP_ADD_INT_REST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, diff --git a/Python/tier2.c b/Python/tier2.c index 08f4896d84c30a..7b1a6d29d45461 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -450,13 +450,20 @@ write_bb_id(_PyBBBranchCache *cache, int bb_id, bool is_type_guard) { #define BB_IS_TYPE_BRANCH(bb_id_raw) (bb_id_raw & 1) +// The order/hierarchy to emit type guards +// NEED TO ADD TO THIS EVERY TIME WE ADD A NEW ONE. static int type_guard_ladder[256] = { + -1, BINARY_CHECK_INT, + BINARY_CHECK_FLOAT, -1, }; +// Type guard to index in the ladder. +// KEEP IN SYNC WITH INDEX IN type_guard_ladder static int type_guard_to_index[256] = { - [BINARY_CHECK_INT] = 0, + [BINARY_CHECK_INT] = 1, + [BINARY_CHECK_FLOAT] = 2, }; @@ -733,17 +740,13 @@ infer_BINARY_OP_ADD( } } // Unknown, time to emit the chain of guards. - // First, we guesstimate using the current specialised op *needs_guard = true; - if (raw_op.op.code == BINARY_OP_ADD_INT && prev_type_guard == NULL) { - return emit_type_guard(write_curr, BINARY_CHECK_INT, bb_id); - } - // If there current op isn't specialised, we just do the general ladder. if (prev_type_guard == NULL) { return emit_type_guard(write_curr, BINARY_CHECK_INT, bb_id); } else { - int next_guard = type_guard_ladder[type_guard_to_index[prev_type_guard->op.code] + 1]; + int next_guard = type_guard_ladder[ + type_guard_to_index[prev_type_guard->op.code] + 1]; if (next_guard != -1) { return emit_type_guard(write_curr, next_guard, bb_id); } @@ -775,8 +778,11 @@ _PyTier2_Code_DetectAndEmitBB( // do make a copy if needed before calling this function _PyTier2TypeContext *starting_type_context) { - assert(prev_type_guard == NULL || - prev_type_guard->op.code == BINARY_CHECK_INT); + assert( + prev_type_guard == NULL || + prev_type_guard->op.code == BINARY_CHECK_INT || + prev_type_guard->op.code == BINARY_CHECK_FLOAT + ); #define END() goto end; #define JUMPBY(x) i += x + 1; #define DISPATCH() write_i = emit_i(write_i, specop, oparg); \ @@ -827,6 +833,7 @@ _PyTier2_Code_DetectAndEmitBB( DISPATCH(); case COMPARE_AND_BRANCH: opcode = COMPARE_OP; + specop = COMPARE_OP; DISPATCH(); case END_FOR: // Assert that we are the start of a BB @@ -1177,13 +1184,16 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) int optimizable = 0; for (Py_ssize_t curr = 0; curr < Py_SIZE(co); curr++) { _Py_CODEUNIT *curr_instr = _PyCode_CODE(co) + curr; - if (IS_FORBIDDEN_OPCODE(_PyOpcode_Deopt[_Py_OPCODE(*curr_instr)])) { + int deopt = _PyOpcode_Deopt[_Py_OPCODE(*curr_instr)]; + if (IS_FORBIDDEN_OPCODE(deopt)) { #if BB_DEBUG fprintf(stderr, "FORBIDDEN OPCODE %d\n", _Py_OPCODE(*curr_instr)); #endif return NULL; } optimizable |= IS_OPTIMIZABLE_OPCODE(_Py_OPCODE(*curr_instr), _Py_OPARG(*curr_instr)); + // Skip the cache entries + curr += _PyOpcode_Caches[deopt]; } if (!optimizable) { diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index ffbc68a62ae403..eb83b84f92b67c 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -123,6 +123,18 @@ break; } + TARGET(BINARY_CHECK_FLOAT) { + TYPESTACK_POKE(1, &PyFloat_Type); + TYPESTACK_POKE(2, &PyFloat_Type); + break; + } + + TARGET(BINARY_OP_ADD_FLOAT_REST) { + STACK_SHRINK(1); + TYPESTACK_POKE(1, &PyFloat_Type); + break; + } + TARGET(BINARY_OP_ADD_INT) { STACK_SHRINK(1); TYPESTACK_POKE(1, &PyLong_Type); From 448f82f4c876e46ac8cf90b983aa550972e34392 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu, 16 Mar 2023 15:45:33 +0800 Subject: [PATCH 067/280] Fix a bunch of compiler warnings --- Objects/codeobject.c | 3 ++- Python/tier2.c | 20 ++++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 18f294134e7084..ea72668a5f210c 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -2004,7 +2004,8 @@ code_getcodetier2(PyCodeObject *code, void *closure) if (code->_tier2_info == NULL) { return PyBytes_FromStringAndSize("", 0); } - return PyBytes_FromStringAndSize(code->_tier2_info->_bb_space->u_code, + return PyBytes_FromStringAndSize( + (const char *)code->_tier2_info->_bb_space->u_code, code->_tier2_info->_bb_space->water_level); } diff --git a/Python/tier2.c b/Python/tier2.c index 7b1a6d29d45461..607dd58f98880b 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -136,8 +136,9 @@ type_propagate( #define STACK_GROW(idx) STACK_ADJUST((idx)) #define STACK_SHRINK(idx) STACK_ADJUST(-(idx)) -#ifdef TYPEPROP_DEBUG - fprintf(stderr, " [-] Type stack bef: %llu\n", ((uint64_t)type_stackptr - (uint64_t)type_stack) / sizeof(PyTypeObject *)); +#if TYPEPROP_DEBUG + fprintf(stderr, " [-] Type stack bef: %llu\n", + ((uint64_t)type_stackptr - (uint64_t)type_stack) / sizeof(PyTypeObject *)); #ifdef Py_DEBUG fprintf(stderr, " [-] Type propagating across: %s : %d\n", _PyOpcode_OpName[opcode], oparg); #endif @@ -150,8 +151,9 @@ type_propagate( Py_UNREACHABLE(); } -#ifdef TYPEPROP_DEBUG - fprintf(stderr, " [-] Type stack aft: %llu\n", ((uint64_t)type_stackptr - (uint64_t)type_stack) / sizeof(PyTypeObject *)); +#if TYPEPROP_DEBUG + fprintf(stderr, " [-] Type stack aft: %llu\n", + ((uint64_t)type_stackptr - (uint64_t)type_stack) / sizeof(PyTypeObject *)); #endif type_context->type_stack_ptr = type_stackptr; @@ -880,7 +882,7 @@ _PyTier2_Code_DetectAndEmitBB( fprintf(stderr, "Emitted virtual start of basic block\n"); #endif starts_with_backwards_jump_target = true; - backwards_jump_target_offset = curr - _PyCode_CODE(co); + backwards_jump_target_offset = (int)(curr - _PyCode_CODE(co)); virtual_start = false; goto fall_through; } @@ -970,7 +972,7 @@ _PyTier2_Code_DetectAndEmitBB( // -1 becaues write_i points to the instruction AFTER the end bb_space->water_level += (write_i - t2_start) * sizeof(_Py_CODEUNIT); #if BB_DEBUG - fprintf(stderr, "Generated BB T2 Start: %p, T1 offset: %d\n", meta->tier2_start, + fprintf(stderr, "Generated BB T2 Start: %p, T1 offset: %zu\n", meta->tier2_start, meta->tier1_end - _PyCode_CODE(co)); #endif return meta; @@ -1047,8 +1049,10 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) PyMem_Free(backward_jump_offsets); return 1; } - if (allocate_jump_offset_2d_array(backwards_jump_count, backward_jump_target_bb_ids)) { + if (allocate_jump_offset_2d_array((int)backwards_jump_count, + backward_jump_target_bb_ids)) { PyMem_Free(backward_jump_offsets); + PyMem_Free(backward_jump_target_bb_ids); return 1; } @@ -1327,7 +1331,7 @@ _PyTier2_GenerateNextBB( // one of those conditional pops. assert(!gen_bb_requires_pop); // Propagate the type guard information. -#ifdef TYPEPROP_DEBUG +#if TYPEPROP_DEBUG fprintf(stderr, " [-] Previous predicate BB ended with a type guard: %s\n", _PyOpcode_OpName[prev_type_guard->op.code]); From 417b725cd508481d99b8603c02fdb8282df28c53 Mon Sep 17 00:00:00 2001 From: Julia Date: Fri, 17 Mar 2023 13:44:38 +0800 Subject: [PATCH 068/280] Refactor: Again Setup parser.py and generate_cases.py in preparation for the more general type prop --- Tools/cases_generator/generate_cases.py | 35 ++++++++-------- Tools/cases_generator/parser.py | 56 ++++++++++++++----------- 2 files changed, 49 insertions(+), 42 deletions(-) diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 3064a68f40513c..2fa61432f19234 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -17,7 +17,7 @@ import parser from parser import StackEffect -from parser import TypeLiteralAnnotation, TypeIndexAnnotation, TypeInputAnnotation, TypeDerefAnnotation +from parser import TypeAnnotation, TypeSrcLiteral, TypeSrcConst, TypeSrcLocals, TypeSrcStackInput from parser import LocalEffect, LocalEffectVarLiteral, LocalEffectVarStack HERE = os.path.dirname(__file__) @@ -343,13 +343,13 @@ def write_typeprop(self, out: Formatter) -> None: # Stack input is used in output effect for oeffect in self.output_effects: if not (typ := oeffect.type_annotation): continue - if not isinstance(typ, TypeInputAnnotation): continue - if oeffect.name in self.unmoved_names and oeffect.name == typ.name: + if not isinstance(src := typ.src, TypeSrcStackInput): continue + if oeffect.name in self.unmoved_names and oeffect.name == src.name: print( f"Warn: {self.name} type annotation for {oeffect.name} will be ignored " "as it is unmoved") continue - need_to_declare.append(typ.name) + need_to_declare.append(src.name) # Write input stack effect variable declarations and initializations ieffects = list(reversed(self.input_effects)) @@ -404,28 +404,29 @@ def write_typeprop(self, out: Formatter) -> None: # Check if it's even used if oeffect.name == UNUSED: continue - + # Check if there's type info if typ := oeffect.type_annotation: - match typ: - case TypeLiteralAnnotation(literal=val): + + if typ.op == "TYPE_SET": + # TODO + continue + + # typ.op == "TYPE_OVERWRITE" + match typ.src: + case TypeSrcLiteral(literal=val): if val != "NULL": val = f"&{val}" - case TypeIndexAnnotation(array=arr, index=idx): - val = f"{'TYPELOCALS_GET' if arr == 'locals' else 'TYPECONST_GET'}({idx})" - case TypeInputAnnotation(name=val): + case TypeSrcLocals(index=idx): + val = f"TYPELOCALS_GET({idx})" + case TypeSrcConst(index=idx): + val = f"TYPECONST_GET({idx})" + case TypeSrcStackInput(name=val): # We determined above that we don't need to write this stack effect if val not in need_to_declare: continue # Unmoved var, don't need to write if oeffect.name in self.unmoved_names: continue - case TypeDerefAnnotation(typeval=typeval): - match typeval: - case TypeLiteralAnnotation(literal=val): - # TODO - continue - case _: - typing.assert_never(typeval) case _: typing.assert_never(typ) if oeffect.cond: diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index 372929f760ca43..f9b4f0fe4426b9 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -69,31 +69,34 @@ class Block(Node): @dataclass -class TypeLiteralAnnotation(Node): +class TypeSrcLiteral(Node): literal: str @dataclass -class TypeIndexAnnotation(Node): - array: Literal["locals", "consts"] +class TypeSrcConst(Node): index: str @dataclass -class TypeInputAnnotation(Node): - name: str +class TypeSrcLocals(Node): + index: str @dataclass -class TypeDerefAnnotation(Node): - typeval: TypeLiteralAnnotation # Support more types as needed - +class TypeSrcStackInput(Node): + name: str -TypeAnnotation: TypeAlias = ( - TypeLiteralAnnotation - | TypeIndexAnnotation - | TypeInputAnnotation - | TypeDerefAnnotation +TypeSrc: TypeAlias = ( + TypeSrcLiteral + | TypeSrcConst + | TypeSrcLocals + | TypeSrcStackInput ) +@dataclass +class TypeAnnotation(Node): + op: Literal["TYPE_SET", "TYPE_OVERWRITE"] + src: TypeSrc + @dataclass class StackEffect(Node): name: str @@ -356,28 +359,31 @@ def stack_effect(self) -> StackEffect | None: return StackEffect(tkn.text, _type, type_annotation, cond_text, size_text) @contextual - def stackvar_type(self) -> TypeAnnotation | None: + def stackvar_typesrc(self) -> TypeSrc | None: if id := self.expect(lx.IDENTIFIER): idstr = id.text.strip() if not self.expect(lx.LBRACKET): - return TypeLiteralAnnotation(idstr) + return TypeSrcLiteral(idstr) if idstr not in ["locals", "consts"]: return if id := self.expect(lx.IDENTIFIER): index = id.text.strip() self.require(lx.RBRACKET) - return TypeIndexAnnotation( - "locals" if idstr == "locals" else "consts", - index) + if idstr == "locals": + return TypeSrcLocals(index) + return TypeSrcConst(index) elif self.expect(lx.TIMES): id = self.require(lx.IDENTIFIER) - return TypeInputAnnotation(id.text.strip()) - elif self.expect(lx.LSHIFTEQUAL): - typeval = self.stackvar_type() - # TODO: Support other type annotations as needed - assert isinstance(typeval, TypeLiteralAnnotation), \ - "TypeDerefAnnotation only supports Type Literals" - return TypeDerefAnnotation(typeval) + return TypeSrcStackInput(id.text.strip()) + @contextual + def stackvar_type(self) -> TypeAnnotation | None: + if self.expect(lx.LSHIFTEQUAL): + src = self.stackvar_typesrc() + if src is None: return None + return TypeAnnotation("TYPE_SET", src) + src = self.stackvar_typesrc() + if src is None: return None + return TypeAnnotation("TYPE_OVERWRITE", src) @contextual def local_effect(self) -> LocalEffect | None: From 52513f9a896f2acfb9b7eb6dbe8af4de5ed4968b Mon Sep 17 00:00:00 2001 From: Julia Date: Fri, 17 Mar 2023 13:46:01 +0800 Subject: [PATCH 069/280] Style: parser.py --- Tools/cases_generator/parser.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index f9b4f0fe4426b9..0f082fd2742f0e 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -77,14 +77,17 @@ class TypeSrcLiteral(Node): class TypeSrcConst(Node): index: str + @dataclass class TypeSrcLocals(Node): index: str + @dataclass class TypeSrcStackInput(Node): name: str + TypeSrc: TypeAlias = ( TypeSrcLiteral | TypeSrcConst @@ -92,11 +95,13 @@ class TypeSrcStackInput(Node): | TypeSrcStackInput ) + @dataclass class TypeAnnotation(Node): op: Literal["TYPE_SET", "TYPE_OVERWRITE"] src: TypeSrc + @dataclass class StackEffect(Node): name: str From 5d1a01e2a0ee5355417a9b516f0c575b427fdcb5 Mon Sep 17 00:00:00 2001 From: Julia Date: Sat, 18 Mar 2023 15:41:33 +0800 Subject: [PATCH 070/280] Feat: Improved referenced-based type propagator TODO: Add debugging mechanisms --- Include/cpython/code.h | 27 ++- Python/tier2.c | 251 +++++++++++++++++++++--- Python/tier2_typepropagator.c.h | 230 +++++++++++----------- Tools/cases_generator/generate_cases.py | 92 +++++---- Tools/cases_generator/parser.py | 19 +- 5 files changed, 425 insertions(+), 194 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 3d97fbf7028913..ee02dc1192b534 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -56,14 +56,35 @@ typedef struct { PyObject *_co_freevars; } _PyCoCached; +// TYPENODE is a tagged pointer that uses the last 2 LSB as the tag +#define _Py_TYPENODE_t uintptr_t + +// TYPENODE Tags +typedef enum _Py_TypeNodeTags { + // Node is unused + TYPE_NULL = 0, + // TYPE_ROOT can point to a PyTypeObject or be a NULL + TYPE_ROOT = 1, + // TYPE_REF points to a TYPE_ROOT or a TYPE_REF + TYPE_REF = 2 +} _Py_TypeNodeTags; + +#define _Py_TYPENODE_NULL 0 +#define _Py_TYPENODE_GET_TAG(typenode) ((typenode) & (0b11)) +#define _Py_TYPENODE_CLEAR_TAG(typenode) ((typenode) & (~(uintptr_t)(0b11))) + +#define _Py_TYPENODE_MAKE_NULL() _Py_TYPENODE_NULL +#define _Py_TYPENODE_MAKE_ROOT(ptr) (_Py_TYPENODE_CLEAR_TAG(ptr) | TYPE_ROOT) +#define _Py_TYPENODE_MAKE_REF(ptr) (_Py_TYPENODE_CLEAR_TAG(ptr) | TYPE_REF) + // Tier 2 types meta interpreter typedef struct _PyTier2TypeContext { // points into type_stack, points to one element after the stack - PyTypeObject** type_stack_ptr; + _Py_TYPENODE_t *type_stack_ptr; int type_locals_len; int type_stack_len; - PyTypeObject** type_stack; - PyTypeObject** type_locals; + _Py_TYPENODE_t *type_stack; + _Py_TYPENODE_t *type_locals; } _PyTier2TypeContext; // Tier 2 interpreter information diff --git a/Python/tier2.c b/Python/tier2.c index c49ee8eea1dda8..369d13bc6a3d4f 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -32,11 +32,11 @@ initialize_type_context(const PyCodeObject *co) int nlocals = co->co_nlocals; int nstack = co->co_stacksize; - PyTypeObject **type_locals = PyMem_Malloc(nlocals * sizeof(PyTypeObject *)); + _Py_TYPENODE_t *type_locals = PyMem_Malloc(nlocals * sizeof(_Py_TYPENODE_t)); if (type_locals == NULL) { return NULL; } - PyTypeObject **type_stack = PyMem_Malloc(nstack * sizeof(PyTypeObject *)); + _Py_TYPENODE_t *type_stack = PyMem_Malloc(nstack * sizeof(_Py_TYPENODE_t)); if (type_stack == NULL) { PyMem_Free(type_locals); return NULL; @@ -44,10 +44,10 @@ initialize_type_context(const PyCodeObject *co) // Initialize to unknown type. for (int i = 0; i < nlocals; i++) { - type_locals[i] = NULL; + type_locals[i] = _Py_TYPENODE_NULL; } for (int i = 0; i < nstack; i++) { - type_stack[i] = NULL; + type_stack[i] = _Py_TYPENODE_NULL; } _PyTier2TypeContext *type_context = PyMem_Malloc(sizeof(_PyTier2TypeContext)); @@ -75,18 +75,18 @@ _PyTier2TypeContext_Copy(const _PyTier2TypeContext *type_context) int nlocals = type_context->type_locals_len; int nstack = type_context->type_stack_len; - PyTypeObject **type_locals = PyMem_Malloc(nlocals * sizeof(PyTypeObject *)); + _Py_TYPENODE_t *type_locals = PyMem_Malloc(nlocals * sizeof(_Py_TYPENODE_t)); if (type_locals == NULL) { return NULL; } - PyTypeObject **type_stack = PyMem_Malloc(nstack * sizeof(PyTypeObject *)); + _Py_TYPENODE_t *type_stack = PyMem_Malloc(nstack * sizeof(_Py_TYPENODE_t)); if (type_stack == NULL) { PyMem_Free(type_locals); return NULL; } - memcpy(type_locals, type_context->type_locals, nlocals * sizeof(PyTypeObject *)); - memcpy(type_stack, type_context->type_stack, nstack * sizeof(PyTypeObject *)); + memcpy(type_locals, type_context->type_locals, nlocals * sizeof(_Py_TYPENODE_t)); + memcpy(type_stack, type_context->type_stack, nstack * sizeof(_Py_TYPENODE_t)); _PyTier2TypeContext *new_type_context = PyMem_Malloc(sizeof(_PyTier2TypeContext)); if (new_type_context == NULL) { @@ -115,6 +115,200 @@ _PyTier2TypeContext_Free(_PyTier2TypeContext *type_context) PyMem_Free(type_context); } +static void +__type_stack_shrink(_Py_TYPENODE_t **type_stackptr, int idx) +{ + while (idx--) { + **type_stackptr = _Py_TYPENODE_MAKE_NULL(); + *type_stackptr -= 1; + } +} + +static _Py_TYPENODE_t* +__type_typenode_get_rootptr(_Py_TYPENODE_t ref) +{ + uintptr_t tag; + _Py_TYPENODE_t *ref_ptr; + do { + ref_ptr = (_Py_TYPENODE_t *)(ref); + ref = *ref_ptr; + tag = _Py_TYPENODE_GET_TAG(ref); + } while (tag != TYPE_ROOT); + return ref_ptr; +} + +static void +__type_propagate_TYPE_SET( + _Py_TYPENODE_t *src, _Py_TYPENODE_t *dst, bool src_is_new) +{ + +#ifdef Py_DEBUG + // If `src_is_new` is set: + // - `src` doesn't belong inside the type context yet. + // - `src` has to be a TYPE_ROOT + // - `src` is to be interpreted as a _Py_TYPENODE_t + if (src_is_new) { + assert(_Py_TYPENODE_GET_TAG((_Py_TYPENODE_t)src) == TYPE_ROOT); + } +#endif + + uintptr_t tag = _Py_TYPENODE_GET_TAG(*dst); + switch (tag) { + case TYPE_NULL: + case TYPE_ROOT: { + if (!src_is_new) { + // Make dst a reference to src + *dst = _Py_TYPENODE_MAKE_REF( + _Py_TYPENODE_CLEAR_TAG((_Py_TYPENODE_t)src)); + break; + } + // Make dst the src + *dst = (_Py_TYPENODE_t)src; + break; + } + case TYPE_REF: { + _Py_TYPENODE_t *rootref = __type_typenode_get_rootptr(*dst); + if (!src_is_new) { + // Traverse up to the root of dst, make root a reference to src + *rootref = _Py_TYPENODE_MAKE_REF( + _Py_TYPENODE_CLEAR_TAG((_Py_TYPENODE_t)src)); + break; + } + // Make root of dst the src + *rootref = (_Py_TYPENODE_t)src; + break; + } + } +} + +static void +__type_propagate_TYPE_OVERWRITE( + _PyTier2TypeContext *type_context, + _Py_TYPENODE_t* src, _Py_TYPENODE_t* dst, bool src_is_new) +{ + +#ifdef Py_DEBUG + // See: __type_propagate_TYPE_SET + if (src_is_new) { + assert(_Py_TYPENODE_GET_TAG((_Py_TYPENODE_t)src) == TYPE_ROOT); + } +#endif + + uintptr_t tag = _Py_TYPENODE_GET_TAG(*dst); + switch (tag) { + case TYPE_NULL: { + if (!src_is_new) { + // Make dst a reference to src + *dst = _Py_TYPENODE_MAKE_REF( + _Py_TYPENODE_CLEAR_TAG((_Py_TYPENODE_t)src)); + break; + } + // Make dst the src + *dst = (_Py_TYPENODE_t)src; + break; + } + case TYPE_ROOT: { + + _Py_TYPENODE_t old_dst = *dst; + if (!src_is_new) { + // Make dst a reference to src + *dst = _Py_TYPENODE_MAKE_REF( + _Py_TYPENODE_CLEAR_TAG((_Py_TYPENODE_t)src)); + } + else { + // Make dst the src + *dst = (_Py_TYPENODE_t)src; + } + + /* Pick one child of dst andmake that the new root of the dst tree */ + + // Children of dst will have this form + _Py_TYPENODE_t child_test = _Py_TYPENODE_MAKE_REF( + _Py_TYPENODE_CLEAR_TAG((_Py_TYPENODE_t)dst)); + // Will be initialised to the first child we find (ptr to the new root) + _Py_TYPENODE_t *new_root_ptr = NULL; + + // Search locals for children + int nlocals = type_context->type_locals_len; + for (int i = 0; i < nlocals; i++) { + _Py_TYPENODE_t *node_ptr = &(type_context->type_locals[i]); + if (*node_ptr == child_test) { + if (new_root_ptr == NULL) { + // First child encountered! initialise root + new_root_ptr = node_ptr; + *node_ptr = old_dst; + } + else { + // Not the first child encounted, point it to the new root + *node_ptr = _Py_TYPENODE_MAKE_REF( + _Py_TYPENODE_CLEAR_TAG((_Py_TYPENODE_t)new_root_ptr)); + } + } + } + + // Search stack for children + int nstack = (int)(type_context->type_stack_ptr - type_context->type_stack); + for (int i = 0; i < nstack; i++) { + _Py_TYPENODE_t *node_ptr = &(type_context->type_stack[i]); + if (*node_ptr == child_test) { + if (new_root_ptr == NULL) { + // First child encountered! initialise root + new_root_ptr = node_ptr; + *node_ptr = old_dst; + } + else { + // Not the first child encounted, point it to the new root + *node_ptr = _Py_TYPENODE_MAKE_REF( + _Py_TYPENODE_CLEAR_TAG((_Py_TYPENODE_t)new_root_ptr)); + } + } + } + break; + } + case TYPE_REF: { + + // Make dst a reference to src + _Py_TYPENODE_t old_dst = *dst; + if (!src_is_new) { + // Make dst a reference to src + *dst = _Py_TYPENODE_MAKE_REF( + _Py_TYPENODE_CLEAR_TAG((_Py_TYPENODE_t)src)); + } + else { + // Make dst the src + *dst = (_Py_TYPENODE_t)src; + } + + /* Make all child of src be a reference to the parent of dst */ + + // Children of dst will have this form + _Py_TYPENODE_t child_test = _Py_TYPENODE_MAKE_REF( + _Py_TYPENODE_CLEAR_TAG((_Py_TYPENODE_t)dst)); + + // Search locals for children + int nlocals = type_context->type_locals_len; + for (int i = 0; i < nlocals; i++) { + _Py_TYPENODE_t *node_ptr = &(type_context->type_locals[i]); + if (*node_ptr == child_test) { + // Is a child of dst. Point it to the parent of dst + *node_ptr = old_dst; + } + } + + // Search stack for children + int nstack = (int)(type_context->type_stack_ptr - type_context->type_stack); + for (int i = 0; i < nstack; i++) { + _Py_TYPENODE_t *node_ptr = &(type_context->type_stack[i]); + if (*node_ptr == child_test) { + // Is a child of dst. Point it to the parent of dst + *node_ptr = old_dst; + } + } + break; + } + } +} + // Type propagates across a single function. static void type_propagate( @@ -122,22 +316,29 @@ type_propagate( _PyTier2TypeContext *type_context, const PyObject *consts) { - PyTypeObject **type_stack = type_context->type_stack; - PyTypeObject **type_locals = type_context->type_locals; - PyTypeObject **type_stackptr = type_context->type_stack_ptr; - -#define TARGET(op) case op: -#define TYPESTACK_PEEK(idx) (type_stackptr[-(idx)]) -#define TYPESTACK_POKE(idx, v) type_stackptr[-(idx)] = (v) -#define TYPELOCALS_SET(idx, v) type_locals[idx] = v; -#define TYPELOCALS_GET(idx) (type_locals[idx]) -#define TYPECONST_GET(idx) Py_TYPE(_PyTuple_CAST(consts)->ob_item[(idx)]) -#define STACK_ADJUST(idx) type_stackptr += (idx) -#define STACK_GROW(idx) STACK_ADJUST((idx)) -#define STACK_SHRINK(idx) STACK_ADJUST(-(idx)) + _Py_TYPENODE_t *type_stack = type_context->type_stack; + _Py_TYPENODE_t *type_locals = type_context->type_locals; + _Py_TYPENODE_t *type_stackptr = type_context->type_stack_ptr; + +#define TARGET(op) case op: +#define TYPESTACK_PEEK(idx) (&(type_stackptr[-(idx)])) +#define TYPELOCALS_GET(idx) (&(type_locals[idx])) + +// Get the type of the const and make into a TYPENODE ROOT +#define TYPECONST_GET(idx) _Py_TYPENODE_MAKE_ROOT( \ + (_Py_TYPENODE_t)Py_TYPE( \ + _PyTuple_CAST(consts)->ob_item[(idx)])) + +#define TYPE_SET(src, dst, flag) __type_propagate_TYPE_SET((src), (dst), (flag)) +#define TYPE_OVERWRITE(src, dst, flag) __type_propagate_TYPE_OVERWRITE(type_context, (src), (dst), (flag)) + +#define STACK_GROW(idx) type_stackptr += (idx) + +// Stack shrinking has to NULL the nodes +#define STACK_SHRINK(idx) __type_stack_shrink(&type_stackptr, (idx)) #ifdef TYPEPROP_DEBUG - fprintf(stderr, " [-] Type stack bef: %llu\n", ((uint64_t)type_stackptr - (uint64_t)type_stack) / sizeof(PyTypeObject *)); + fprintf(stderr, " [-] Type stack bef: %llu\n", (uint64_t)(type_stackptr - type_stack)); #ifdef Py_DEBUG fprintf(stderr, " [-] Type propagating across: %s : %d\n", _PyOpcode_OpName[opcode], oparg); #endif @@ -151,17 +352,17 @@ type_propagate( } #ifdef TYPEPROP_DEBUG - fprintf(stderr, " [-] Type stack aft: %llu\n", ((uint64_t)type_stackptr - (uint64_t)type_stack) / sizeof(PyTypeObject *)); + fprintf(stderr, " [-] Type stack aft: %llu\n", (uint64_t)(type_stackptr - type_stack)); #endif type_context->type_stack_ptr = type_stackptr; #undef TARGET #undef TYPESTACK_PEEK -#undef TYPESTACK_POKE -#undef TYPELOCALS_SET #undef TYPELOCALS_GET #undef TYPECONST_GET +#undef TYPE_SET +#undef TYPE_OVERWRITE #undef STACK_ADJUST #undef STACK_GROW #undef STACK_SHRINK diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index ffbc68a62ae403..7504adcd5dc829 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -17,31 +17,31 @@ TARGET(LOAD_CLOSURE) { STACK_GROW(1); - TYPESTACK_POKE(1, TYPELOCALS_GET(oparg)); + TYPE_OVERWRITE(TYPELOCALS_GET(oparg), TYPESTACK_PEEK(1), false); break; } TARGET(LOAD_FAST_CHECK) { STACK_GROW(1); - TYPESTACK_POKE(1, TYPELOCALS_GET(oparg)); + TYPE_OVERWRITE(TYPELOCALS_GET(oparg), TYPESTACK_PEEK(1), false); break; } TARGET(LOAD_FAST) { STACK_GROW(1); - TYPESTACK_POKE(1, TYPELOCALS_GET(oparg)); + TYPE_OVERWRITE(TYPELOCALS_GET(oparg), TYPESTACK_PEEK(1), false); break; } TARGET(LOAD_CONST) { STACK_GROW(1); - TYPESTACK_POKE(1, TYPECONST_GET(oparg)); + TYPE_OVERWRITE((_Py_TYPENODE_t *)TYPECONST_GET(oparg), TYPESTACK_PEEK(1), true); break; } TARGET(STORE_FAST) { - PyTypeObject *value = TYPESTACK_PEEK(1); - TYPELOCALS_SET(oparg, value) + _Py_TYPENODE_t *value = TYPESTACK_PEEK(1); + TYPE_OVERWRITE(value, TYPELOCALS_GET(oparg), false); STACK_SHRINK(1); break; } @@ -53,7 +53,7 @@ TARGET(PUSH_NULL) { STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } @@ -68,47 +68,47 @@ } TARGET(UNARY_NEGATIVE) { - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(UNARY_NOT) { - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(UNARY_INVERT) { - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(BINARY_OP_MULTIPLY_INT) { STACK_SHRINK(1); - TYPESTACK_POKE(1, &PyLong_Type); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyLong_Type), TYPESTACK_PEEK(1), true); break; } TARGET(BINARY_OP_MULTIPLY_FLOAT) { STACK_SHRINK(1); - TYPESTACK_POKE(1, &PyFloat_Type); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(1), true); break; } TARGET(BINARY_OP_SUBTRACT_INT) { STACK_SHRINK(1); - TYPESTACK_POKE(1, &PyLong_Type); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyLong_Type), TYPESTACK_PEEK(1), true); break; } TARGET(BINARY_OP_SUBTRACT_FLOAT) { STACK_SHRINK(1); - TYPESTACK_POKE(1, &PyFloat_Type); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(1), true); break; } TARGET(BINARY_OP_ADD_UNICODE) { STACK_SHRINK(1); - TYPESTACK_POKE(1, &PyUnicode_Type); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyUnicode_Type), TYPESTACK_PEEK(1), true); break; } @@ -119,37 +119,37 @@ TARGET(BINARY_OP_ADD_FLOAT) { STACK_SHRINK(1); - TYPESTACK_POKE(1, &PyFloat_Type); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(1), true); break; } TARGET(BINARY_OP_ADD_INT) { STACK_SHRINK(1); - TYPESTACK_POKE(1, &PyLong_Type); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyLong_Type), TYPESTACK_PEEK(1), true); break; } TARGET(BINARY_CHECK_INT) { - TYPESTACK_POKE(1, &PyLong_Type); - TYPESTACK_POKE(2, &PyLong_Type); + TYPE_SET((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyLong_Type), TYPESTACK_PEEK(1), true); + TYPE_SET((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyLong_Type), TYPESTACK_PEEK(2), true); break; } TARGET(BINARY_OP_ADD_INT_REST) { STACK_SHRINK(1); - TYPESTACK_POKE(1, &PyLong_Type); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyLong_Type), TYPESTACK_PEEK(1), true); break; } TARGET(BINARY_SUBSCR) { STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(BINARY_SLICE) { STACK_SHRINK(2); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } @@ -160,19 +160,19 @@ TARGET(BINARY_SUBSCR_LIST_INT) { STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(BINARY_SUBSCR_TUPLE_INT) { STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(BINARY_SUBSCR_DICT) { STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } @@ -212,13 +212,13 @@ } TARGET(CALL_INTRINSIC_1) { - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(CALL_INTRINSIC_2) { STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } @@ -243,18 +243,18 @@ } TARGET(GET_AITER) { - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(GET_ANEXT) { STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(GET_AWAITABLE) { - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } @@ -295,20 +295,20 @@ TARGET(CLEANUP_THROW) { STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); - TYPESTACK_POKE(2, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(2), true); break; } TARGET(LOAD_ASSERTION_ERROR) { STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(LOAD_BUILD_CLASS) { STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } @@ -330,21 +330,21 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { STACK_SHRINK(1); STACK_GROW(oparg); - TYPESTACK_POKE(oparg, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(oparg), true); break; } TARGET(UNPACK_SEQUENCE_TUPLE) { STACK_SHRINK(1); STACK_GROW(oparg); - TYPESTACK_POKE(oparg, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(oparg), true); break; } TARGET(UNPACK_SEQUENCE_LIST) { STACK_SHRINK(1); STACK_GROW(oparg); - TYPESTACK_POKE(oparg, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(oparg), true); break; } @@ -374,31 +374,31 @@ TARGET(LOAD_NAME) { STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(LOAD_GLOBAL) { STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPESTACK_POKE(1, NULL); - if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } TARGET(LOAD_GLOBAL_MODULE) { STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPESTACK_POKE(1, NULL); - if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } TARGET(LOAD_GLOBAL_BUILTIN) { STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPESTACK_POKE(1, NULL); - if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } @@ -420,7 +420,7 @@ TARGET(LOAD_CLASSDEREF) { STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } @@ -442,21 +442,21 @@ TARGET(BUILD_STRING) { STACK_SHRINK(oparg); STACK_GROW(1); - TYPESTACK_POKE(1, &PyUnicode_Type); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyUnicode_Type), TYPESTACK_PEEK(1), true); break; } TARGET(BUILD_TUPLE) { STACK_SHRINK(oparg); STACK_GROW(1); - TYPESTACK_POKE(1, &PyTuple_Type); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyTuple_Type), TYPESTACK_PEEK(1), true); break; } TARGET(BUILD_LIST) { STACK_SHRINK(oparg); STACK_GROW(1); - TYPESTACK_POKE(1, &PyList_Type); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyList_Type), TYPESTACK_PEEK(1), true); break; } @@ -473,14 +473,14 @@ TARGET(BUILD_SET) { STACK_SHRINK(oparg); STACK_GROW(1); - TYPESTACK_POKE(1, &PySet_Type); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PySet_Type), TYPESTACK_PEEK(1), true); break; } TARGET(BUILD_MAP) { STACK_SHRINK(oparg*2); STACK_GROW(1); - TYPESTACK_POKE(1, &PyDict_Type); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyDict_Type), TYPESTACK_PEEK(1), true); break; } @@ -490,7 +490,7 @@ TARGET(BUILD_CONST_KEY_MAP) { STACK_SHRINK(oparg); - TYPESTACK_POKE(1, &PyDict_Type); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyDict_Type), TYPESTACK_PEEK(1), true); break; } @@ -511,43 +511,43 @@ TARGET(LOAD_ATTR) { STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPESTACK_POKE(1, NULL); - if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } TARGET(LOAD_ATTR_INSTANCE_VALUE) { STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPESTACK_POKE(1, NULL); - if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } TARGET(LOAD_ATTR_MODULE) { STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPESTACK_POKE(1, NULL); - if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } TARGET(LOAD_ATTR_WITH_HINT) { STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPESTACK_POKE(1, NULL); - if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } TARGET(LOAD_ATTR_SLOT) { STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPESTACK_POKE(1, NULL); - if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } TARGET(LOAD_ATTR_CLASS) { STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPESTACK_POKE(1, NULL); - if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } @@ -578,7 +578,7 @@ TARGET(COMPARE_OP) { STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } @@ -604,36 +604,36 @@ TARGET(IS_OP) { STACK_SHRINK(1); - TYPESTACK_POKE(1, &PyBool_Type); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyBool_Type), TYPESTACK_PEEK(1), true); break; } TARGET(CONTAINS_OP) { STACK_SHRINK(1); - TYPESTACK_POKE(1, &PyBool_Type); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyBool_Type), TYPESTACK_PEEK(1), true); break; } TARGET(CHECK_EG_MATCH) { - TYPESTACK_POKE(1, NULL); - TYPESTACK_POKE(2, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(2), true); break; } TARGET(CHECK_EXC_MATCH) { - TYPESTACK_POKE(1, &PyBool_Type); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyBool_Type), TYPESTACK_PEEK(1), true); break; } TARGET(IMPORT_NAME) { STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(IMPORT_FROM) { STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } @@ -719,13 +719,13 @@ TARGET(GET_LEN) { STACK_GROW(1); - TYPESTACK_POKE(1, &PyLong_Type); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyLong_Type), TYPESTACK_PEEK(1), true); break; } TARGET(MATCH_CLASS) { STACK_SHRINK(2); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } @@ -748,42 +748,42 @@ } TARGET(GET_ITER) { - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(GET_YIELD_FROM_ITER) { - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(FOR_ITER) { STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(BB_TEST_ITER) { STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(FOR_ITER_LIST) { STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(FOR_ITER_TUPLE) { STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(FOR_ITER_RANGE) { STACK_GROW(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } @@ -794,15 +794,15 @@ TARGET(BEFORE_ASYNC_WITH) { STACK_GROW(1); - TYPESTACK_POKE(1, NULL); - TYPESTACK_POKE(2, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(2), true); break; } TARGET(BEFORE_WITH) { STACK_GROW(1); - TYPESTACK_POKE(1, NULL); - TYPESTACK_POKE(2, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(2), true); break; } @@ -820,22 +820,22 @@ TARGET(LOAD_ATTR_METHOD_WITH_VALUES) { STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPESTACK_POKE(1, NULL); - if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } TARGET(LOAD_ATTR_METHOD_NO_DICT) { STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPESTACK_POKE(1, NULL); - if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } TARGET(LOAD_ATTR_METHOD_LAZY_DICT) { STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPESTACK_POKE(1, NULL); - if (oparg & 1) { TYPESTACK_POKE(1 + ((oparg & 1) ? 1 : 0), NULL); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } @@ -846,7 +846,7 @@ TARGET(CALL) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } @@ -871,63 +871,63 @@ TARGET(CALL_NO_KW_TYPE_1) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(CALL_NO_KW_STR_1) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(CALL_NO_KW_TUPLE_1) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(CALL_BUILTIN_CLASS) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(CALL_NO_KW_BUILTIN_O) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(CALL_NO_KW_BUILTIN_FAST) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(CALL_BUILTIN_FAST_WITH_KEYWORDS) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(CALL_NO_KW_LEN) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(CALL_NO_KW_ISINSTANCE) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } @@ -940,41 +940,41 @@ TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_FAST) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(CALL_FUNCTION_EX) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(MAKE_FUNCTION) { STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } @@ -985,34 +985,34 @@ TARGET(BUILD_SLICE) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(FORMAT_VALUE) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(COPY) { - PyTypeObject *bottom = TYPESTACK_PEEK(1 + (oparg-1)); + _Py_TYPENODE_t *bottom = TYPESTACK_PEEK(1 + (oparg-1)); STACK_GROW(1); - TYPESTACK_POKE(1, bottom); + TYPE_OVERWRITE(bottom, TYPESTACK_PEEK(1), false); break; } TARGET(BINARY_OP) { STACK_SHRINK(1); - TYPESTACK_POKE(1, NULL); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); break; } TARGET(SWAP) { - PyTypeObject *top = TYPESTACK_PEEK(1); - PyTypeObject *bottom = TYPESTACK_PEEK(2 + (oparg-2)); - TYPESTACK_POKE(1, bottom); - TYPESTACK_POKE(2 + (oparg-2), top); + _Py_TYPENODE_t *top = TYPESTACK_PEEK(1); + _Py_TYPENODE_t *bottom = TYPESTACK_PEEK(2 + (oparg-2)); + TYPE_OVERWRITE(bottom, TYPESTACK_PEEK(1), false); + TYPE_OVERWRITE(top, TYPESTACK_PEEK(2 + (oparg-2)), false); break; } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 2fa61432f19234..14045e7ceabcb8 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -17,8 +17,8 @@ import parser from parser import StackEffect -from parser import TypeAnnotation, TypeSrcLiteral, TypeSrcConst, TypeSrcLocals, TypeSrcStackInput -from parser import LocalEffect, LocalEffectVarLiteral, LocalEffectVarStack +from parser import TypeSrcLiteral, TypeSrcConst, TypeSrcLocals, TypeSrcStackInput +from parser import LocalEffect HERE = os.path.dirname(__file__) ROOT = os.path.join(HERE, "../..") @@ -338,7 +338,7 @@ def write_typeprop(self, out: Formatter) -> None: need_to_declare = [] # Stack input is used in local effect if self.local_effects and \ - isinstance(val := self.local_effects.value, LocalEffectVarStack): + isinstance(val := self.local_effects.value, TypeSrcStackInput): need_to_declare.append(val.name) # Stack input is used in output effect for oeffect in self.output_effects: @@ -363,30 +363,46 @@ def write_typeprop(self, out: Formatter) -> None: list_effect_size([ieff for ieff in ieffects[: i + 1]]) ) all_input_effect_names[ieffect.name] = (ieffect, i) - dst = StackEffect(ieffect.name, "PyTypeObject *") + dst = StackEffect(ieffect.name, "_Py_TYPENODE_t *") if ieffect.size: - src = StackEffect(f"&TYPESTACK_PEEK({isize})", "PyTypeObject **") - dst = StackEffect(ieffect.name, "PyTypeObject **") + # TODO: Support more cases as needed + raise Exception("Type propagation across sized input effect not implemented") elif ieffect.cond: - src = StackEffect(f"({ieffect.cond}) ? TYPESTACK_PEEK({isize}) : NULL", "PyTypeObject *") + src = StackEffect(f"({ieffect.cond}) ? TYPESTACK_PEEK({isize}) : NULL", "_Py_TYPENODE_t *") else: usable_for_local_effect[ieffect.name] = ieffect - src = StackEffect(f"TYPESTACK_PEEK({isize})", "PyTypeObject *") + src = StackEffect(f"TYPESTACK_PEEK({isize})", "_Py_TYPENODE_t *") out.declare(dst, src) # Write localarr effect if self.local_effects: + idx = self.local_effects.index val = self.local_effects.value + + typ_op = "TYPE_OVERWRITE" + dst = f"TYPELOCALS_GET({idx})" match val: - case LocalEffectVarLiteral(name=valstr): - if valstr != "NULL": valstr = f"&{valstr}" - case LocalEffectVarStack(name=valstr): + case TypeSrcLiteral(name=valstr): + if valstr == "NULL": + src = "(_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL)" + flag = "true" + else: + src = f"(_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&{valstr})" + flag = "true" + case TypeSrcStackInput(name=valstr): assert valstr in usable_for_local_effect, \ "`cond` and `size` stackvar not supported for localeffect" + src = valstr + flag = "false" + # TODO: Support more cases as needed + case TypeSrcConst(): + raise Exception("Not implemented") + case TypeSrcLocals(): + raise Exception("Not implemented") case _: typing.assert_never(val) - out.emit(f"TYPELOCALS_SET({idx}, {valstr})") + out.emit(f"{typ_op}({src}, {dst}, {flag});") # Update stack size out.stack_adjust( @@ -401,38 +417,40 @@ def write_typeprop(self, out: Formatter) -> None: osize = string_effect_size( list_effect_size([oeff for oeff in oeffects[: i + 1]]) ) + dst = f"TYPESTACK_PEEK({osize})" # Check if it's even used if oeffect.name == UNUSED: continue # Check if there's type info if typ := oeffect.type_annotation: - - if typ.op == "TYPE_SET": - # TODO - continue - - # typ.op == "TYPE_OVERWRITE" match typ.src: - case TypeSrcLiteral(literal=val): - if val != "NULL": val = f"&{val}" - case TypeSrcLocals(index=idx): - val = f"TYPELOCALS_GET({idx})" + case TypeSrcLiteral(literal=valstr): + if valstr == "NULL": + src = "(_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL)" + flag = "true" + else: + src = f"(_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&{valstr})" + flag = "true" + case TypeSrcStackInput(name=valstr): + assert valstr in need_to_declare + assert oeffect.name not in self.unmoved_names + src = valstr + flag = "false" case TypeSrcConst(index=idx): - val = f"TYPECONST_GET({idx})" - case TypeSrcStackInput(name=val): - # We determined above that we don't need to write this stack effect - if val not in need_to_declare: - continue - # Unmoved var, don't need to write - if oeffect.name in self.unmoved_names: - continue + src = f"(_Py_TYPENODE_t *)TYPECONST_GET({idx})" + flag = "true" + case TypeSrcLocals(index=idx): + src = f"TYPELOCALS_GET({idx})" + flag = "false" case _: - typing.assert_never(typ) + typing.assert_never(typ.src) + + opstr = f"{typ.op}({src}, {dst}, {flag})" if oeffect.cond: - out.emit(f"if ({oeffect.cond}) {{ TYPESTACK_POKE({osize}, {val}); }}") + out.emit(f"if ({oeffect.cond}) {{ {opstr}; }}") else: - out.emit(f"TYPESTACK_POKE({osize}, {val});") + out.emit(f"{opstr};") continue # Don't touch unmoved stack vars @@ -440,10 +458,14 @@ def write_typeprop(self, out: Formatter) -> None: continue # Just output null + typ_op = "TYPE_OVERWRITE" + src = "(_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL)" + flag = "true" + opstr = f"{typ_op}({src}, {dst}, {flag})" if oeffect.cond: - out.emit(f"if ({oeffect.cond}) {{ TYPESTACK_POKE({osize}, NULL); }}") + out.emit(f"if ({oeffect.cond}) {{ {opstr}; }}") else: - out.emit(f"TYPESTACK_POKE({osize}, NULL);") + out.emit(f"{opstr};") def write(self, out: Formatter) -> None: """Write one instruction, sans prologue and epilogue.""" diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index 0f082fd2742f0e..48ad3cefa0fef4 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -126,23 +126,10 @@ class CacheEffect(Node): size: int -@dataclass -class LocalEffectVarLiteral(Node): - name: str - - -@dataclass -class LocalEffectVarStack(Node): - name: str - - -LocalEffectVar: TypeAlias = LocalEffectVarLiteral | LocalEffectVarStack - - @dataclass class LocalEffect(Node): index: str - value: LocalEffectVar + value: TypeSrc @dataclass @@ -404,12 +391,12 @@ def local_effect(self) -> LocalEffect | None: value = self.require(lx.IDENTIFIER).text.strip() return LocalEffect( index, - LocalEffectVarStack(value) + TypeSrcStackInput(value) ) value = self.require(lx.IDENTIFIER).text.strip() return LocalEffect( index, - LocalEffectVarLiteral(value) + TypeSrcLiteral(value) ) @contextual From 49b09eb20abeddc878ba2628af9c4d3ac70b2650 Mon Sep 17 00:00:00 2001 From: Julia Date: Sat, 18 Mar 2023 18:02:03 +0800 Subject: [PATCH 071/280] Fix+Debug: Fixed bugs and print type context --- Include/cpython/code.h | 4 ++- Python/tier2.c | 65 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index ee02dc1192b534..d08bf48b9b4e8b 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -69,7 +69,6 @@ typedef enum _Py_TypeNodeTags { TYPE_REF = 2 } _Py_TypeNodeTags; -#define _Py_TYPENODE_NULL 0 #define _Py_TYPENODE_GET_TAG(typenode) ((typenode) & (0b11)) #define _Py_TYPENODE_CLEAR_TAG(typenode) ((typenode) & (~(uintptr_t)(0b11))) @@ -77,6 +76,9 @@ typedef enum _Py_TypeNodeTags { #define _Py_TYPENODE_MAKE_ROOT(ptr) (_Py_TYPENODE_CLEAR_TAG(ptr) | TYPE_ROOT) #define _Py_TYPENODE_MAKE_REF(ptr) (_Py_TYPENODE_CLEAR_TAG(ptr) | TYPE_REF) +#define _Py_TYPENODE_NULL 0 +#define _Py_TYPENODE_NULLROOT _Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL) + // Tier 2 types meta interpreter typedef struct _PyTier2TypeContext { // points into type_stack, points to one element after the stack diff --git a/Python/tier2.c b/Python/tier2.c index 369d13bc6a3d4f..fe7a9a2dc8577e 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -44,10 +44,10 @@ initialize_type_context(const PyCodeObject *co) // Initialize to unknown type. for (int i = 0; i < nlocals; i++) { - type_locals[i] = _Py_TYPENODE_NULL; + type_locals[i] = _Py_TYPENODE_NULLROOT; } for (int i = 0; i < nstack; i++) { - type_stack[i] = _Py_TYPENODE_NULL; + type_stack[i] = _Py_TYPENODE_NULLROOT; } _PyTier2TypeContext *type_context = PyMem_Malloc(sizeof(_PyTier2TypeContext)); @@ -125,18 +125,38 @@ __type_stack_shrink(_Py_TYPENODE_t **type_stackptr, int idx) } static _Py_TYPENODE_t* -__type_typenode_get_rootptr(_Py_TYPENODE_t ref) +__typenode_get_rootptr(_Py_TYPENODE_t ref) { uintptr_t tag; _Py_TYPENODE_t *ref_ptr; do { - ref_ptr = (_Py_TYPENODE_t *)(ref); + ref_ptr = (_Py_TYPENODE_t *)(_Py_TYPENODE_CLEAR_TAG(ref)); ref = *ref_ptr; tag = _Py_TYPENODE_GET_TAG(ref); } while (tag != TYPE_ROOT); return ref_ptr; } +static PyTypeObject* +_typenode_get_type(_Py_TYPENODE_t node) +{ + uintptr_t tag = _Py_TYPENODE_GET_TAG(node); + switch (tag) { + case TYPE_NULL: return NULL; + case TYPE_ROOT: { + PyTypeObject *ret = (PyTypeObject *)_Py_TYPENODE_CLEAR_TAG(node); + return ret; + } + case TYPE_REF: { + _Py_TYPENODE_t *root_ref = __typenode_get_rootptr(node); + PyTypeObject *ret = (PyTypeObject *)_Py_TYPENODE_CLEAR_TAG(*root_ref); + return ret; + } + default: + Py_UNREACHABLE(); + } +} + static void __type_propagate_TYPE_SET( _Py_TYPENODE_t *src, _Py_TYPENODE_t *dst, bool src_is_new) @@ -167,7 +187,7 @@ __type_propagate_TYPE_SET( break; } case TYPE_REF: { - _Py_TYPENODE_t *rootref = __type_typenode_get_rootptr(*dst); + _Py_TYPENODE_t *rootref = __typenode_get_rootptr(*dst); if (!src_is_new) { // Traverse up to the root of dst, make root a reference to src *rootref = _Py_TYPENODE_MAKE_REF( @@ -178,6 +198,8 @@ __type_propagate_TYPE_SET( *rootref = (_Py_TYPENODE_t)src; break; } + default: + Py_UNREACHABLE(); } } @@ -306,8 +328,33 @@ __type_propagate_TYPE_OVERWRITE( } break; } + default: + Py_UNREACHABLE(); + } +} + +#if TYPEPROP_DEBUG +static void print_typestack(const _PyTier2TypeContext *type_context) +{ + _Py_TYPENODE_t *type_stack = type_context->type_stack; + _Py_TYPENODE_t *type_locals = type_context->type_locals; + _Py_TYPENODE_t *type_stackptr = type_context->type_stack_ptr; + + int nstack = (int)(type_stackptr - type_stack); + fprintf(stderr, " Stack: ["); + for (int i = 0; i < nstack; i++) { + PyTypeObject *type = _typenode_get_type(type_stack[i]); + fprintf(stderr, "%s, ", type == NULL ? "?" : type->tp_name); + } + fprintf(stderr, "]\n"); + fprintf(stderr, " Locals: ["); + for (int i = 0; i < type_context->type_locals_len; i++) { + PyTypeObject *type = _typenode_get_type(type_locals[i]); + fprintf(stderr, "%s, ", type == NULL ? "?" : type->tp_name); } + fprintf(stderr, "]\n"); } +#endif // Type propagates across a single function. static void @@ -337,7 +384,7 @@ type_propagate( // Stack shrinking has to NULL the nodes #define STACK_SHRINK(idx) __type_stack_shrink(&type_stackptr, (idx)) -#ifdef TYPEPROP_DEBUG +#if TYPEPROP_DEBUG fprintf(stderr, " [-] Type stack bef: %llu\n", (uint64_t)(type_stackptr - type_stack)); #ifdef Py_DEBUG fprintf(stderr, " [-] Type propagating across: %s : %d\n", _PyOpcode_OpName[opcode], oparg); @@ -350,13 +397,13 @@ type_propagate( fprintf(stderr, "Unsupported opcode in type propagator: %d\n", opcode); Py_UNREACHABLE(); } + type_context->type_stack_ptr = type_stackptr; -#ifdef TYPEPROP_DEBUG +#if TYPEPROP_DEBUG fprintf(stderr, " [-] Type stack aft: %llu\n", (uint64_t)(type_stackptr - type_stack)); + print_typestack(type_context); #endif - type_context->type_stack_ptr = type_stackptr; - #undef TARGET #undef TYPESTACK_PEEK #undef TYPELOCALS_GET From f0ed274088353c67346c90d8722d5a79bcf5bb7c Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 20 Mar 2023 17:20:47 +0800 Subject: [PATCH 072/280] Fix: Bug fixes to the new type prop --- Include/cpython/code.h | 1 - Python/bytecodes.c | 2 +- Python/tier2.c | 160 ++++++++++++++-------- Python/tier2_typepropagator.c.h | 172 ++++++++++++------------ Tools/cases_generator/generate_cases.py | 6 +- 5 files changed, 196 insertions(+), 145 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 5eeeef6d473d8e..4079cd565cfb74 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -72,7 +72,6 @@ typedef enum _Py_TypeNodeTags { #define _Py_TYPENODE_GET_TAG(typenode) ((typenode) & (0b11)) #define _Py_TYPENODE_CLEAR_TAG(typenode) ((typenode) & (~(uintptr_t)(0b11))) -#define _Py_TYPENODE_MAKE_NULL() _Py_TYPENODE_NULL #define _Py_TYPENODE_MAKE_ROOT(ptr) (_Py_TYPENODE_CLEAR_TAG(ptr) | TYPE_ROOT) #define _Py_TYPENODE_MAKE_REF(ptr) (_Py_TYPENODE_CLEAR_TAG(ptr) | TYPE_REF) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index fd19017a58891e..72ba844f017f41 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -279,7 +279,7 @@ dummy_func( U_INST(BINARY_OP_ADD_FLOAT_REST); } - inst(BINARY_CHECK_FLOAT, (left, right -- left : PyFloat_Type, right : PyFloat_Type)) { + inst(BINARY_CHECK_FLOAT, (left, right -- left : <<= PyFloat_Type, right : <<= PyFloat_Type)) { assert(cframe.use_tracing == 0); bb_test = PyFloat_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); } diff --git a/Python/tier2.c b/Python/tier2.c index 6219cd6e036106..9a86c55ba1fc10 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -72,6 +72,8 @@ _PyTier2TypeContext_Copy(const _PyTier2TypeContext *type_context) fprintf(stderr, " [*] Copying type context\n"); #endif + _Py_TYPENODE_t *orig_type_locals = type_context->type_locals; + _Py_TYPENODE_t *orig_type_stack = type_context->type_stack; int nlocals = type_context->type_locals_len; int nstack = type_context->type_stack_len; @@ -85,15 +87,65 @@ _PyTier2TypeContext_Copy(const _PyTier2TypeContext *type_context) return NULL; } - memcpy(type_locals, type_context->type_locals, nlocals * sizeof(_Py_TYPENODE_t)); - memcpy(type_stack, type_context->type_stack, nstack * sizeof(_Py_TYPENODE_t)); - _PyTier2TypeContext *new_type_context = PyMem_Malloc(sizeof(_PyTier2TypeContext)); if (new_type_context == NULL) { PyMem_Free(type_locals); PyMem_Free(type_stack); return NULL; } + + for (int i = 0; i < nlocals; i++) { + _Py_TYPENODE_t node = type_context->type_locals[i]; + switch _Py_TYPENODE_GET_TAG(node) + { + case TYPE_ROOT: + type_locals[i] = node; + break; + case TYPE_REF: { + // Check if part of locals + _Py_TYPENODE_t *parent = (_Py_TYPENODE_t *)_Py_TYPENODE_CLEAR_TAG(node); + + // Check if part of locals + if (parent - type_context->type_locals < nlocals) { + type_locals[i] = node - (uintptr_t)orig_type_locals + (uintptr_t)type_locals; + } + // Is part of stack + else { + type_locals[i] = node - (uintptr_t)orig_type_stack + (uintptr_t)type_stack; + } + break; + } + default: + Py_UNREACHABLE(); + } + } + + for (int i = 0; i < nstack; i++) { + _Py_TYPENODE_t node = type_context->type_stack[i]; + switch _Py_TYPENODE_GET_TAG(node) + { + case TYPE_ROOT: + type_stack[i] = node; + break; + case TYPE_REF: { + // Check if part of locals + _Py_TYPENODE_t *parent = (_Py_TYPENODE_t *)_Py_TYPENODE_CLEAR_TAG(node); + + // Check if part of locals + if (parent - type_context->type_locals < nlocals) { + type_stack[i] = node - (uintptr_t)orig_type_locals + (uintptr_t)type_locals; + } + // Is part of stack + else { + type_stack[i] = node - (uintptr_t)orig_type_stack + (uintptr_t)type_stack; + } + break; + } + default: + Py_UNREACHABLE(); + } + } + new_type_context->type_locals_len = nlocals; new_type_context->type_stack_len = nstack; new_type_context->type_locals = type_locals; @@ -115,15 +167,6 @@ _PyTier2TypeContext_Free(_PyTier2TypeContext *type_context) PyMem_Free(type_context); } -static void -__type_stack_shrink(_Py_TYPENODE_t **type_stackptr, int idx) -{ - while (idx--) { - **type_stackptr = _Py_TYPENODE_MAKE_NULL(); - *type_stackptr -= 1; - } -} - static _Py_TYPENODE_t* __typenode_get_rootptr(_Py_TYPENODE_t ref) { @@ -142,7 +185,6 @@ _typenode_get_type(_Py_TYPENODE_t node) { uintptr_t tag = _Py_TYPENODE_GET_TAG(node); switch (tag) { - case TYPE_NULL: return NULL; case TYPE_ROOT: { PyTypeObject *ret = (PyTypeObject *)_Py_TYPENODE_CLEAR_TAG(node); return ret; @@ -174,12 +216,10 @@ __type_propagate_TYPE_SET( uintptr_t tag = _Py_TYPENODE_GET_TAG(*dst); switch (tag) { - case TYPE_NULL: case TYPE_ROOT: { if (!src_is_new) { // Make dst a reference to src - *dst = _Py_TYPENODE_MAKE_REF( - _Py_TYPENODE_CLEAR_TAG((_Py_TYPENODE_t)src)); + *dst = _Py_TYPENODE_MAKE_REF((_Py_TYPENODE_t)src); break; } // Make dst the src @@ -190,8 +230,7 @@ __type_propagate_TYPE_SET( _Py_TYPENODE_t *rootref = __typenode_get_rootptr(*dst); if (!src_is_new) { // Traverse up to the root of dst, make root a reference to src - *rootref = _Py_TYPENODE_MAKE_REF( - _Py_TYPENODE_CLEAR_TAG((_Py_TYPENODE_t)src)); + *rootref = _Py_TYPENODE_MAKE_REF((_Py_TYPENODE_t)src); break; } // Make root of dst the src @@ -218,24 +257,12 @@ __type_propagate_TYPE_OVERWRITE( uintptr_t tag = _Py_TYPENODE_GET_TAG(*dst); switch (tag) { - case TYPE_NULL: { - if (!src_is_new) { - // Make dst a reference to src - *dst = _Py_TYPENODE_MAKE_REF( - _Py_TYPENODE_CLEAR_TAG((_Py_TYPENODE_t)src)); - break; - } - // Make dst the src - *dst = (_Py_TYPENODE_t)src; - break; - } case TYPE_ROOT: { _Py_TYPENODE_t old_dst = *dst; if (!src_is_new) { // Make dst a reference to src - *dst = _Py_TYPENODE_MAKE_REF( - _Py_TYPENODE_CLEAR_TAG((_Py_TYPENODE_t)src)); + *dst = _Py_TYPENODE_MAKE_REF((_Py_TYPENODE_t)src); } else { // Make dst the src @@ -262,14 +289,13 @@ __type_propagate_TYPE_OVERWRITE( } else { // Not the first child encounted, point it to the new root - *node_ptr = _Py_TYPENODE_MAKE_REF( - _Py_TYPENODE_CLEAR_TAG((_Py_TYPENODE_t)new_root_ptr)); + *node_ptr = _Py_TYPENODE_MAKE_REF((_Py_TYPENODE_t)new_root_ptr); } } } // Search stack for children - int nstack = (int)(type_context->type_stack_ptr - type_context->type_stack); + int nstack = type_context->type_stack_len; for (int i = 0; i < nstack; i++) { _Py_TYPENODE_t *node_ptr = &(type_context->type_stack[i]); if (*node_ptr == child_test) { @@ -280,8 +306,7 @@ __type_propagate_TYPE_OVERWRITE( } else { // Not the first child encounted, point it to the new root - *node_ptr = _Py_TYPENODE_MAKE_REF( - _Py_TYPENODE_CLEAR_TAG((_Py_TYPENODE_t)new_root_ptr)); + *node_ptr = _Py_TYPENODE_MAKE_REF((_Py_TYPENODE_t)new_root_ptr); } } } @@ -293,8 +318,7 @@ __type_propagate_TYPE_OVERWRITE( _Py_TYPENODE_t old_dst = *dst; if (!src_is_new) { // Make dst a reference to src - *dst = _Py_TYPENODE_MAKE_REF( - _Py_TYPENODE_CLEAR_TAG((_Py_TYPENODE_t)src)); + *dst = _Py_TYPENODE_MAKE_REF((_Py_TYPENODE_t)src); } else { // Make dst the src @@ -318,7 +342,7 @@ __type_propagate_TYPE_OVERWRITE( } // Search stack for children - int nstack = (int)(type_context->type_stack_ptr - type_context->type_stack); + int nstack = type_context->type_stack_len; for (int i = 0; i < nstack; i++) { _Py_TYPENODE_t *node_ptr = &(type_context->type_stack[i]); if (*node_ptr == child_test) { @@ -333,24 +357,53 @@ __type_propagate_TYPE_OVERWRITE( } } +static void +__type_stack_shrink(_PyTier2TypeContext *type_context, _Py_TYPENODE_t **type_stackptr, int idx) +{ + while (idx--) { + // TODO: + // If we don't touch the stack elements + // when shrinking, we need to check for references + // on these elements. + // Otherwise, if we NULL these elements, we need to refactor + // the type propagator to perform shrinking last. + // + // __type_propagate_TYPE_OVERWRITE( + // type_context, + // (_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, *type_stackptr, + // true); + *type_stackptr -= 1; + } +} + #if TYPEPROP_DEBUG -static void print_typestack(const _PyTier2TypeContext *type_context) + +static void +print_typestack(const _PyTier2TypeContext *type_context) { _Py_TYPENODE_t *type_stack = type_context->type_stack; _Py_TYPENODE_t *type_locals = type_context->type_locals; _Py_TYPENODE_t *type_stackptr = type_context->type_stack_ptr; - int nstack = (int)(type_stackptr - type_stack); - fprintf(stderr, " Stack: ["); + int nstack_use = (int)(type_stackptr - type_stack); + int nstack = type_context->type_stack_len; + fprintf(stderr, " Stack: %p: [", type_stack); for (int i = 0; i < nstack; i++) { PyTypeObject *type = _typenode_get_type(type_stack[i]); - fprintf(stderr, "%s, ", type == NULL ? "?" : type->tp_name); + _Py_TYPENODE_t tag = _Py_TYPENODE_GET_TAG(type_stack[i]); + fprintf(stderr, "%s%s%s", + i == nstack_use ? "." : " ", + type == NULL ? "?" : type->tp_name, + tag == TYPE_REF ? "*" : ""); } fprintf(stderr, "]\n"); - fprintf(stderr, " Locals: ["); + fprintf(stderr, " Locals %p: [", type_locals); for (int i = 0; i < type_context->type_locals_len; i++) { PyTypeObject *type = _typenode_get_type(type_locals[i]); - fprintf(stderr, "%s, ", type == NULL ? "?" : type->tp_name); + _Py_TYPENODE_t tag = _Py_TYPENODE_GET_TAG(type_locals[i]); + fprintf(stderr, "%s%s ", + type == NULL ? "?" : type->tp_name, + tag == TYPE_REF ? "*" : ""); } fprintf(stderr, "]\n"); } @@ -365,10 +418,10 @@ type_propagate( { _Py_TYPENODE_t *type_stack = type_context->type_stack; _Py_TYPENODE_t *type_locals = type_context->type_locals; - _Py_TYPENODE_t *type_stackptr = type_context->type_stack_ptr; + _Py_TYPENODE_t **type_stackptr = &type_context->type_stack_ptr; #define TARGET(op) case op: -#define TYPESTACK_PEEK(idx) (&(type_stackptr[-(idx)])) +#define TYPESTACK_PEEK(idx) (&((*type_stackptr)[-(idx)])) #define TYPELOCALS_GET(idx) (&(type_locals[idx])) // Get the type of the const and make into a TYPENODE ROOT @@ -379,13 +432,13 @@ type_propagate( #define TYPE_SET(src, dst, flag) __type_propagate_TYPE_SET((src), (dst), (flag)) #define TYPE_OVERWRITE(src, dst, flag) __type_propagate_TYPE_OVERWRITE(type_context, (src), (dst), (flag)) -#define STACK_GROW(idx) type_stackptr += (idx) +#define STACK_GROW(idx) *type_stackptr += (idx) // Stack shrinking has to NULL the nodes -#define STACK_SHRINK(idx) __type_stack_shrink(&type_stackptr, (idx)) +#define STACK_SHRINK(idx) __type_stack_shrink(type_context, type_stackptr, (idx)) #if TYPEPROP_DEBUG - fprintf(stderr, " [-] Type stack bef: %llu\n", (uint64_t)(type_stackptr - type_stack)); + fprintf(stderr, " [-] Type stack bef: %llu\n", (uint64_t)(*type_stackptr - type_stack)); #ifdef Py_DEBUG fprintf(stderr, " [-] Type propagating across: %s : %d\n", _PyOpcode_OpName[opcode], oparg); #endif @@ -397,10 +450,9 @@ type_propagate( fprintf(stderr, "Unsupported opcode in type propagator: %d\n", opcode); Py_UNREACHABLE(); } - type_context->type_stack_ptr = type_stackptr; #if TYPEPROP_DEBUG - fprintf(stderr, " [-] Type stack aft: %llu\n", (uint64_t)(type_stackptr - type_stack)); + fprintf(stderr, " [-] Type stack aft: %llu\n", (uint64_t)(*type_stackptr - type_stack)); print_typestack(type_context); #endif @@ -977,8 +1029,8 @@ infer_BINARY_OP_ADD( int bb_id) { *needs_guard = false; - PyTypeObject *right = type_context->type_stack_ptr[-1]; - PyTypeObject *left = type_context->type_stack_ptr[-2]; + PyTypeObject *right = _typenode_get_type(type_context->type_stack_ptr[-1]); + PyTypeObject *left = _typenode_get_type(type_context->type_stack_ptr[-2]); if (left == &PyLong_Type) { if (right == &PyLong_Type) { write_curr->op.code = BINARY_OP_ADD_INT_REST; diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index 196eb912d9b281..72c7eb9cc4d60f 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -53,7 +53,7 @@ TARGET(PUSH_NULL) { STACK_GROW(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } @@ -68,17 +68,17 @@ } TARGET(UNARY_NEGATIVE) { - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(UNARY_NOT) { - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(UNARY_INVERT) { - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } @@ -124,14 +124,14 @@ } TARGET(BINARY_CHECK_FLOAT) { - TYPESTACK_POKE(1, &PyFloat_Type); - TYPESTACK_POKE(2, &PyFloat_Type); + TYPE_SET((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(1), true); + TYPE_SET((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(2), true); break; } TARGET(BINARY_OP_ADD_FLOAT_REST) { STACK_SHRINK(1); - TYPESTACK_POKE(1, &PyFloat_Type); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(1), true); break; } @@ -155,13 +155,13 @@ TARGET(BINARY_SUBSCR) { STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(BINARY_SLICE) { STACK_SHRINK(2); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } @@ -172,19 +172,19 @@ TARGET(BINARY_SUBSCR_LIST_INT) { STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(BINARY_SUBSCR_TUPLE_INT) { STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(BINARY_SUBSCR_DICT) { STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } @@ -224,13 +224,13 @@ } TARGET(CALL_INTRINSIC_1) { - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(CALL_INTRINSIC_2) { STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } @@ -255,18 +255,18 @@ } TARGET(GET_AITER) { - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(GET_ANEXT) { STACK_GROW(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(GET_AWAITABLE) { - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } @@ -307,20 +307,20 @@ TARGET(CLEANUP_THROW) { STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(2), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(2), true); break; } TARGET(LOAD_ASSERTION_ERROR) { STACK_GROW(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(LOAD_BUILD_CLASS) { STACK_GROW(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } @@ -342,21 +342,21 @@ TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { STACK_SHRINK(1); STACK_GROW(oparg); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(oparg), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(oparg), true); break; } TARGET(UNPACK_SEQUENCE_TUPLE) { STACK_SHRINK(1); STACK_GROW(oparg); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(oparg), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(oparg), true); break; } TARGET(UNPACK_SEQUENCE_LIST) { STACK_SHRINK(1); STACK_GROW(oparg); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(oparg), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(oparg), true); break; } @@ -386,31 +386,31 @@ TARGET(LOAD_NAME) { STACK_GROW(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(LOAD_GLOBAL) { STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); - if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } TARGET(LOAD_GLOBAL_MODULE) { STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); - if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } TARGET(LOAD_GLOBAL_BUILTIN) { STACK_GROW(1); STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); - if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } @@ -432,7 +432,7 @@ TARGET(LOAD_CLASSDEREF) { STACK_GROW(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } @@ -523,43 +523,43 @@ TARGET(LOAD_ATTR) { STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); - if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } TARGET(LOAD_ATTR_INSTANCE_VALUE) { STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); - if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } TARGET(LOAD_ATTR_MODULE) { STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); - if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } TARGET(LOAD_ATTR_WITH_HINT) { STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); - if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } TARGET(LOAD_ATTR_SLOT) { STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); - if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } TARGET(LOAD_ATTR_CLASS) { STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); - if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } @@ -590,7 +590,7 @@ TARGET(COMPARE_OP) { STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } @@ -627,8 +627,8 @@ } TARGET(CHECK_EG_MATCH) { - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(2), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(2), true); break; } @@ -639,13 +639,13 @@ TARGET(IMPORT_NAME) { STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(IMPORT_FROM) { STACK_GROW(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } @@ -737,7 +737,7 @@ TARGET(MATCH_CLASS) { STACK_SHRINK(2); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } @@ -760,42 +760,42 @@ } TARGET(GET_ITER) { - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(GET_YIELD_FROM_ITER) { - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(FOR_ITER) { STACK_GROW(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(BB_TEST_ITER) { STACK_GROW(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(FOR_ITER_LIST) { STACK_GROW(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(FOR_ITER_TUPLE) { STACK_GROW(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(FOR_ITER_RANGE) { STACK_GROW(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } @@ -806,15 +806,15 @@ TARGET(BEFORE_ASYNC_WITH) { STACK_GROW(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(2), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(2), true); break; } TARGET(BEFORE_WITH) { STACK_GROW(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(2), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(2), true); break; } @@ -832,22 +832,22 @@ TARGET(LOAD_ATTR_METHOD_WITH_VALUES) { STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); - if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } TARGET(LOAD_ATTR_METHOD_NO_DICT) { STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); - if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } TARGET(LOAD_ATTR_METHOD_LAZY_DICT) { STACK_GROW(((oparg & 1) ? 1 : 0)); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); - if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } break; } @@ -858,7 +858,7 @@ TARGET(CALL) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } @@ -883,63 +883,63 @@ TARGET(CALL_NO_KW_TYPE_1) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(CALL_NO_KW_STR_1) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(CALL_NO_KW_TUPLE_1) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(CALL_BUILTIN_CLASS) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(CALL_NO_KW_BUILTIN_O) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(CALL_NO_KW_BUILTIN_FAST) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(CALL_BUILTIN_FAST_WITH_KEYWORDS) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(CALL_NO_KW_LEN) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(CALL_NO_KW_ISINSTANCE) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } @@ -952,41 +952,41 @@ TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_FAST) { STACK_SHRINK(oparg); STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(CALL_FUNCTION_EX) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(MAKE_FUNCTION) { STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } @@ -997,13 +997,13 @@ TARGET(BUILD_SLICE) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(FORMAT_VALUE) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } @@ -1016,7 +1016,7 @@ TARGET(BINARY_OP) { STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 14045e7ceabcb8..e67608a83ffea3 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -385,7 +385,7 @@ def write_typeprop(self, out: Formatter) -> None: match val: case TypeSrcLiteral(name=valstr): if valstr == "NULL": - src = "(_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL)" + src = "(_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT" flag = "true" else: src = f"(_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&{valstr})" @@ -427,7 +427,7 @@ def write_typeprop(self, out: Formatter) -> None: match typ.src: case TypeSrcLiteral(literal=valstr): if valstr == "NULL": - src = "(_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL)" + src = "(_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT" flag = "true" else: src = f"(_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&{valstr})" @@ -459,7 +459,7 @@ def write_typeprop(self, out: Formatter) -> None: # Just output null typ_op = "TYPE_OVERWRITE" - src = "(_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT(_Py_TYPENODE_NULL)" + src = "(_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT" flag = "true" opstr = f"{typ_op}({src}, {dst}, {flag})" if oeffect.cond: From 63fa5bbe3f32bfc46f64eb1b6c3d43775c3b7bf7 Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 20 Mar 2023 17:44:02 +0800 Subject: [PATCH 073/280] Refactor: rename _typenode_get_type to typenode_get_type --- Python/tier2.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index 9a86c55ba1fc10..325bd99728a556 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -181,7 +181,7 @@ __typenode_get_rootptr(_Py_TYPENODE_t ref) } static PyTypeObject* -_typenode_get_type(_Py_TYPENODE_t node) +typenode_get_type(_Py_TYPENODE_t node) { uintptr_t tag = _Py_TYPENODE_GET_TAG(node); switch (tag) { @@ -389,7 +389,7 @@ print_typestack(const _PyTier2TypeContext *type_context) int nstack = type_context->type_stack_len; fprintf(stderr, " Stack: %p: [", type_stack); for (int i = 0; i < nstack; i++) { - PyTypeObject *type = _typenode_get_type(type_stack[i]); + PyTypeObject *type = typenode_get_type(type_stack[i]); _Py_TYPENODE_t tag = _Py_TYPENODE_GET_TAG(type_stack[i]); fprintf(stderr, "%s%s%s", i == nstack_use ? "." : " ", @@ -399,7 +399,7 @@ print_typestack(const _PyTier2TypeContext *type_context) fprintf(stderr, "]\n"); fprintf(stderr, " Locals %p: [", type_locals); for (int i = 0; i < type_context->type_locals_len; i++) { - PyTypeObject *type = _typenode_get_type(type_locals[i]); + PyTypeObject *type = typenode_get_type(type_locals[i]); _Py_TYPENODE_t tag = _Py_TYPENODE_GET_TAG(type_locals[i]); fprintf(stderr, "%s%s ", type == NULL ? "?" : type->tp_name, @@ -1029,8 +1029,8 @@ infer_BINARY_OP_ADD( int bb_id) { *needs_guard = false; - PyTypeObject *right = _typenode_get_type(type_context->type_stack_ptr[-1]); - PyTypeObject *left = _typenode_get_type(type_context->type_stack_ptr[-2]); + PyTypeObject *right = typenode_get_type(type_context->type_stack_ptr[-1]); + PyTypeObject *left = typenode_get_type(type_context->type_stack_ptr[-2]); if (left == &PyLong_Type) { if (right == &PyLong_Type) { write_curr->op.code = BINARY_OP_ADD_INT_REST; From e7e69be8f795b849a4f2f18a09adf9350f168183 Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 20 Mar 2023 18:26:40 +0800 Subject: [PATCH 074/280] Refactor: Simplify __type_stack_shrink --- Python/tier2.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index 325bd99728a556..a681dae6c31946 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -360,20 +360,20 @@ __type_propagate_TYPE_OVERWRITE( static void __type_stack_shrink(_PyTier2TypeContext *type_context, _Py_TYPENODE_t **type_stackptr, int idx) { - while (idx--) { - // TODO: - // If we don't touch the stack elements - // when shrinking, we need to check for references - // on these elements. - // Otherwise, if we NULL these elements, we need to refactor - // the type propagator to perform shrinking last. - // - // __type_propagate_TYPE_OVERWRITE( - // type_context, - // (_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, *type_stackptr, - // true); - *type_stackptr -= 1; - } + // TODO: + // If we don't touch the stack elements + // when shrinking, we need to check for references + // on these elements. + // Otherwise, if we NULL these elements, we need to refactor + // the type propagator to perform shrinking last. + //while (idx--) { + // __type_propagate_TYPE_OVERWRITE( + // type_context, + // (_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, *type_stackptr, + // true); + // *type_stackptr -= 1; + //} + *type_stackptr -= idx; } #if TYPEPROP_DEBUG From bed5b8aac0e5bc7fe6395eaf678ef2e27b820d80 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 20 Mar 2023 19:56:23 +0800 Subject: [PATCH 075/280] fix allocation issues --- Python/tier2.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index 607dd58f98880b..0b33b89e4e4490 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -204,12 +204,12 @@ _PyCode_GetLogicalEnd(PyCodeObject *co) static _PyTier2BBSpace * _PyTier2_CreateBBSpace(Py_ssize_t space_to_alloc) { - _PyTier2BBSpace *bb_space = PyMem_Malloc(space_to_alloc); + _PyTier2BBSpace *bb_space = PyMem_Malloc(space_to_alloc + sizeof(_PyTier2BBSpace)); if (bb_space == NULL) { return NULL; } bb_space->water_level = 0; - bb_space->max_capacity = (space_to_alloc - sizeof(_PyTier2BBSpace)); + bb_space->max_capacity = space_to_alloc; return bb_space; } @@ -226,13 +226,15 @@ _PyTier2_BBSpaceCheckAndReallocIfNeeded(PyCodeObject *co, Py_ssize_t space_reque if (curr->water_level + space_requested > curr->max_capacity) { // Note: overallocate Py_ssize_t new_size = sizeof(_PyTier2BBSpace) + (curr->water_level + space_requested) * 2; +#if BB_DEBUG + fprintf(stderr, "Allocating new BB of size %lld\n", new_size); +#endif _PyTier2BBSpace *new_space = PyMem_Realloc(curr, new_size); if (new_space == NULL) { return NULL; } co->_tier2_info->_bb_space = new_space; new_space->max_capacity = new_size; - PyMem_Free(curr); return new_space; } // We have enouogh space. Don't do anything, j From d144e35f14573e2af89e374e4d4730beb92b1a21 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 20 Mar 2023 20:30:34 +0800 Subject: [PATCH 076/280] temp commit --- Python/bytecodes.c | 8 +++++++- Python/generated_cases.c.h | 10 ++++++++++ Python/tier2_typepropagator.c.h | 4 ++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 7e93f7acfa29f9..2af655962b46f3 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -279,9 +279,15 @@ dummy_func( U_INST(BINARY_OP_ADD_FLOAT_REST); } - inst(BINARY_CHECK_FLOAT, (left, right -- left : PyFloat_Type, right : PyFloat_Type)) { + inst(BINARY_CHECK_FLOAT, (left, right -- left_unboxed : PyRawFloat_Type, left_unboxed : PyRawFloat_Type)) { assert(cframe.use_tracing == 0); bb_test = PyFloat_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); + left_unboxed = (bb_test + ? *((PyObject **)(&(((PyFloatObject *)left)->ob_fval))) + : left); + right_unboxed = (bb_test + ? *((PyObject **)(&(((PyFloatObject *)right)->ob_fval))) + : right); } u_inst(BINARY_OP_ADD_FLOAT_REST, (left, right -- sum : PyFloat_Type)) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 56a7fbb050b03e..e4565444a4500b 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -398,8 +398,18 @@ TARGET(BINARY_CHECK_FLOAT) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; + PyObject *left_unboxed; + PyObject *left_unboxed; assert(cframe.use_tracing == 0); bb_test = PyFloat_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); + left_unboxed = (bb_test + ? *((PyObject **)(&(((PyFloatObject *)left)->ob_fval))) + : left); + right_unboxed = (bb_test + ? *((PyObject **)(&(((PyFloatObject *)right)->ob_fval))) + : right); + stack_pointer[-1] = left_unboxed; + stack_pointer[-2] = left_unboxed; DISPATCH(); } diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index eb83b84f92b67c..6dcabba76bfd15 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -124,8 +124,8 @@ } TARGET(BINARY_CHECK_FLOAT) { - TYPESTACK_POKE(1, &PyFloat_Type); - TYPESTACK_POKE(2, &PyFloat_Type); + TYPESTACK_POKE(1, &PyRawFloat_Type); + TYPESTACK_POKE(2, &PyRawFloat_Type); break; } From 183d0094e0114bb66b7b35cf192cd8063b43f804 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 20 Mar 2023 21:06:57 +0800 Subject: [PATCH 077/280] Support unboxed floats --- Include/internal/pycore_code.h | 4 - Include/internal/pycore_frame.h | 17 +++- Include/internal/pycore_opcode.h | 23 ++--- Include/opcode.h | 11 +- Lib/opcode.py | 15 ++- Objects/codeobject.c | 5 +- Python/bytecodes.c | 46 +++++++-- Python/ceval_macros.h | 2 + Python/frame.c | 4 + Python/generated_cases.c.h | 79 ++++++++++++--- Python/opcode_metadata.h | 41 +++++++- Python/tier2.c | 168 +++++++++++++++++++++++++++++-- Python/tier2_typepropagator.c.h | 46 ++++++++- Tools/build/deepfreeze.py | 3 +- 14 files changed, 401 insertions(+), 63 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 8d1b5599972de0..bfda105c61d4dc 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -529,10 +529,6 @@ extern uint32_t _Py_next_func_version; #define COMPARISON_NOT_EQUALS (COMPARISON_UNORDERED | COMPARISON_LESS_THAN | COMPARISON_GREATER_THAN) - -#define BB_SUC 1 -#define BB_ALT 0 - #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index b8710bd627e67c..b60bd5e25aa3d7 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -62,7 +62,7 @@ typedef struct _PyInterpreterFrame { int stacktop; /* Offset of TOS from localsplus */ uint16_t yield_offset; char owner; - /* Locals and stack */ + /* Locals and stack and unboxed bit mask */ PyObject *localsplus[1]; } _PyInterpreterFrame; @@ -105,7 +105,10 @@ _PyFrame_NumSlotsForCodeObject(PyCodeObject *code) /* This function needs to remain in sync with the calculation of * co_framesize in Tools/build/deepfreeze.py */ assert(code->co_framesize >= FRAME_SPECIALS_SIZE); - return code->co_framesize - FRAME_SPECIALS_SIZE; + int res = code->co_framesize - FRAME_SPECIALS_SIZE - + (code->co_nlocalsplus * sizeof(char) / sizeof(PyObject *) + 1); + assert(res > 0); + return res; } void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest); @@ -126,7 +129,6 @@ _PyFrame_Initialize( frame->f_locals = locals; frame->stacktop = code->co_nlocalsplus; frame->frame_obj = NULL; - // @TODO CHANGE ME if (code->_tier2_info != NULL) { frame->prev_instr = code->_tier2_info->_entry_bb->tier2_start - 1; } @@ -141,6 +143,15 @@ _PyFrame_Initialize( } } +// The unboxed bitmask. true indicates an unboxed value. false indicates a normal PyObject. +static inline char* +_PyFrame_GetUnboxedBitMask(_PyInterpreterFrame *frame) +{ + PyCodeObject *co = frame->f_code; + return (char *)(frame + co->co_framesize - + (co->co_nlocalsplus * sizeof(char) / sizeof(PyObject *) + 1)); +} + /* Gets the pointer to the locals array * that precedes this frame. */ diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 5be22719a3aec6..ab2ff150d4bede 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -428,15 +428,15 @@ static const char *const _PyOpcode_OpName[263] = { [BB_JUMP_BACKWARD_LAZY] = "BB_JUMP_BACKWARD_LAZY", [BINARY_CHECK_INT] = "BINARY_CHECK_INT", [BINARY_CHECK_FLOAT] = "BINARY_CHECK_FLOAT", + [UNARY_CHECK_FLOAT] = "UNARY_CHECK_FLOAT", [BINARY_OP_ADD_INT_REST] = "BINARY_OP_ADD_INT_REST", - [BINARY_OP_ADD_FLOAT_REST] = "BINARY_OP_ADD_FLOAT_REST", - [193] = "<193>", - [194] = "<194>", - [195] = "<195>", - [196] = "<196>", - [197] = "<197>", - [198] = "<198>", - [199] = "<199>", + [BINARY_OP_ADD_FLOAT_UNBOXED] = "BINARY_OP_ADD_FLOAT_UNBOXED", + [UNBOX_FLOAT] = "UNBOX_FLOAT", + [BOX_FLOAT] = "BOX_FLOAT", + [LOAD_FAST_NO_INCREF] = "LOAD_FAST_NO_INCREF", + [STORE_FAST_BOXED_UNBOXED] = "STORE_FAST_BOXED_UNBOXED", + [STORE_FAST_UNBOXED_BOXED] = "STORE_FAST_UNBOXED_BOXED", + [STORE_FAST_UNBOXED_UNBOXED] = "STORE_FAST_UNBOXED_UNBOXED", [200] = "<200>", [201] = "<201>", [202] = "<202>", @@ -505,13 +505,6 @@ static const char *const _PyOpcode_OpName[263] = { #define EXTRA_CASES \ - case 193: \ - case 194: \ - case 195: \ - case 196: \ - case 197: \ - case 198: \ - case 199: \ case 200: \ case 201: \ case 202: \ diff --git a/Include/opcode.h b/Include/opcode.h index f5c6d7c5138c09..a1570a55260b07 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -280,8 +280,15 @@ extern "C" { #define BB_JUMP_BACKWARD_LAZY 188 #define BINARY_CHECK_INT 189 #define BINARY_CHECK_FLOAT 190 -#define BINARY_OP_ADD_INT_REST 191 -#define BINARY_OP_ADD_FLOAT_REST 192 +#define UNARY_CHECK_FLOAT 191 +#define BINARY_OP_ADD_INT_REST 192 +#define BINARY_OP_ADD_FLOAT_UNBOXED 193 +#define UNBOX_FLOAT 194 +#define BOX_FLOAT 195 +#define LOAD_FAST_NO_INCREF 196 +#define STORE_FAST_BOXED_UNBOXED 197 +#define STORE_FAST_UNBOXED_BOXED 198 +#define STORE_FAST_UNBOXED_UNBOXED 199 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/opcode.py b/Lib/opcode.py index 2652223a50919d..aa1b33a5187c72 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -504,7 +504,20 @@ def pseudo_op(name, op, real_ops): # single operand forms. 'BINARY_CHECK_INT', 'BINARY_CHECK_FLOAT', + 'UNARY_CHECK_FLOAT', # 'BINARY_CHECK_STR', 'BINARY_OP_ADD_INT_REST', - 'BINARY_OP_ADD_FLOAT_REST', + 'BINARY_OP_ADD_FLOAT_UNBOXED', + + # Boxing / unboxing ops + 'UNBOX_FLOAT', + 'BOX_FLOAT', + 'LOAD_FAST_NO_INCREF', + # Storing a boxed value, overwriting an unboxed local. + 'STORE_FAST_BOXED_UNBOXED', + # Storing an unboxed value, overwriting a boxed local. + 'STORE_FAST_UNBOXED_BOXED', + # Storing an unboxed value, overwriting an unboxed local. + 'STORE_FAST_UNBOXED_UNBOXED', + # The traditional STORE_FAST is storing a boxed value, overwriting a boxed local. ] diff --git a/Objects/codeobject.c b/Objects/codeobject.c index ea72668a5f210c..3b1edc08f54786 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -424,7 +424,10 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con) /* derived values */ co->co_nlocalsplus = nlocalsplus; co->co_nlocals = nlocals; - co->co_framesize = nlocalsplus + con->stacksize + FRAME_SPECIALS_SIZE; + co->co_framesize = nlocalsplus + con->stacksize + FRAME_SPECIALS_SIZE + + // + this because at the end of the frame, we store the bit masks + // that indicate whether this value is unboxed or not + (nlocalsplus * sizeof(char) / sizeof(PyObject *) + 1); co->co_ncellvars = ncellvars; co->co_nfreevars = nfreevars; co->co_version = _Py_next_func_version; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 2af655962b46f3..9870ba98db1009 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -121,6 +121,10 @@ dummy_func( Py_INCREF(value); } + inst(LOAD_FAST_NO_INCREF, (-- value : locals[oparg])) { + value = GETLOCAL(oparg); + } + inst(LOAD_CONST, (-- value : consts[oparg])) { value = GETITEM(consts, oparg); Py_INCREF(value); @@ -130,6 +134,20 @@ dummy_func( SETLOCAL(oparg, value); } + inst(STORE_FAST_BOXED_UNBOXED, (value --), locals[oparg] = *value) { + SETLOCAL_NO_DECREF(oparg, value); + _PyFrame_GetUnboxedBitMask(frame)[oparg] = false; + } + + inst(STORE_FAST_UNBOXED_BOXED, (value--), locals[oparg] = *value) { + SETLOCAL(oparg, value); + _PyFrame_GetUnboxedBitMask(frame)[oparg] = true; + } + + inst(STORE_FAST_UNBOXED_UNBOXED, (value--), locals[oparg] = *value) { + SETLOCAL_NO_DECREF(oparg, value); + } + super(LOAD_FAST__LOAD_FAST) = LOAD_FAST + LOAD_FAST; super(LOAD_FAST__LOAD_CONST) = LOAD_FAST + LOAD_CONST; super(STORE_FAST__LOAD_FAST) = STORE_FAST + LOAD_FAST; @@ -276,10 +294,13 @@ dummy_func( assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); - U_INST(BINARY_OP_ADD_FLOAT_REST); + STAT_INC(BINARY_OP, hit); + double dsum = ((PyFloatObject *)left)->ob_fval + + ((PyFloatObject *)right)->ob_fval; + DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsum, sum); } - inst(BINARY_CHECK_FLOAT, (left, right -- left_unboxed : PyRawFloat_Type, left_unboxed : PyRawFloat_Type)) { + inst(BINARY_CHECK_FLOAT, (left, right -- left_unboxed : PyRawFloat_Type, right_unboxed : PyRawFloat_Type)) { assert(cframe.use_tracing == 0); bb_test = PyFloat_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); left_unboxed = (bb_test @@ -290,11 +311,24 @@ dummy_func( : right); } - u_inst(BINARY_OP_ADD_FLOAT_REST, (left, right -- sum : PyFloat_Type)) { + inst(UNARY_CHECK_FLOAT, (arg, unused[oparg] -- arg : PyFloat_Type, unused[oparg])) { + assert(cframe.use_tracing == 0); + bb_test = PyFloat_CheckExact(arg); + } + + inst(BINARY_OP_ADD_FLOAT_UNBOXED, (left, right -- sum : PyRawFloat_Type)) { STAT_INC(BINARY_OP, hit); - double dsum = ((PyFloatObject *)left)->ob_fval + - ((PyFloatObject *)right)->ob_fval; - DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsum, sum); + double temp = *(double *)(&(left)) + *(double *)(&(right)); + sum = *(PyObject **)(&temp); + } + + inst(UNBOX_FLOAT, (boxed_float, unused[oparg] -- unboxed_float : PyRawFloat_Type, unused[oparg])) { + double temp = ((PyFloatObject *)boxed_float)->ob_fval; + unboxed_float = (*(PyObject **)(&temp)); + } + + inst(BOX_FLOAT, (raw_float, unused[oparg] -- boxed_float : PyFloat_Type, unused[oparg])) { + boxed_float = PyFloat_FromDouble(*(double *)(&(raw_float))); } macro_inst(BINARY_OP_ADD_INT, (unused/1, left, right -- sum: PyLong_Type)) { diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 429d2b5c54fe1e..9fbec87988e4ae 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -251,6 +251,8 @@ GETITEM(PyObject *v, Py_ssize_t i) { #define SETLOCAL(i, value) do { PyObject *tmp = GETLOCAL(i); \ GETLOCAL(i) = value; \ Py_XDECREF(tmp); } while (0) +#define SETLOCAL_NO_DECREF(i, value) do { PyObject *tmp = GETLOCAL(i); \ + GETLOCAL(i) = value;} while (0) #define GO_TO_INSTRUCTION(op) goto PREDICT_ID(op) diff --git a/Python/frame.c b/Python/frame.c index c2c0be30113912..1adc7a328792a5 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -136,7 +136,11 @@ _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame) Py_DECREF(f); } assert(frame->stacktop >= 0); + char *unboxed_bitmask = _PyFrame_GetUnboxedBitMask(frame); for (int i = 0; i < frame->stacktop; i++) { + if (unboxed_bitmask[i]) { + continue; + } Py_XDECREF(frame->localsplus[i]); } Py_XDECREF(frame->frame_obj); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index e4565444a4500b..509c18a45ec8e3 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3,14 +3,6 @@ // Python/bytecodes.c // Do not edit! - #define UOP_BINARY_OP_ADD_FLOAT_REST() \ - do { \ - STAT_INC(BINARY_OP, hit);\ - double dsum = ((PyFloatObject *)left)->ob_fval +\ - ((PyFloatObject *)right)->ob_fval;\ - DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsum, sum);\ - } while (0) - #define UOP_BINARY_OP_ADD_INT_REST() \ do { \ STAT_INC(BINARY_OP, hit);\ @@ -72,6 +64,14 @@ DISPATCH(); } + TARGET(LOAD_FAST_NO_INCREF) { + PyObject *value; + value = GETLOCAL(oparg); + STACK_GROW(1); + stack_pointer[-1] = value; + DISPATCH(); + } + TARGET(LOAD_CONST) { PREDICTED(LOAD_CONST); PyObject *value; @@ -89,6 +89,29 @@ DISPATCH(); } + TARGET(STORE_FAST_BOXED_UNBOXED) { + PyObject *value = stack_pointer[-1]; + SETLOCAL_NO_DECREF(oparg, value); + _PyFrame_GetUnboxedBitMask(frame)[oparg] = false; + STACK_SHRINK(1); + DISPATCH(); + } + + TARGET(STORE_FAST_UNBOXED_BOXED) { + PyObject *value = stack_pointer[-1]; + SETLOCAL(oparg, value); + _PyFrame_GetUnboxedBitMask(frame)[oparg] = true; + STACK_SHRINK(1); + DISPATCH(); + } + + TARGET(STORE_FAST_UNBOXED_UNBOXED) { + PyObject *value = stack_pointer[-1]; + SETLOCAL_NO_DECREF(oparg, value); + STACK_SHRINK(1); + DISPATCH(); + } + TARGET(LOAD_FAST__LOAD_FAST) { PyObject *_tmp_1; PyObject *_tmp_2; @@ -388,7 +411,10 @@ assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); - UOP_BINARY_OP_ADD_FLOAT_REST(); + STAT_INC(BINARY_OP, hit); + double dsum = ((PyFloatObject *)left)->ob_fval + + ((PyFloatObject *)right)->ob_fval; + DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsum, sum); STACK_SHRINK(1); stack_pointer[-1] = sum; next_instr += 1; @@ -399,7 +425,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *left_unboxed; - PyObject *left_unboxed; + PyObject *right_unboxed; assert(cframe.use_tracing == 0); bb_test = PyFloat_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); left_unboxed = (bb_test @@ -408,24 +434,47 @@ right_unboxed = (bb_test ? *((PyObject **)(&(((PyFloatObject *)right)->ob_fval))) : right); - stack_pointer[-1] = left_unboxed; + stack_pointer[-1] = right_unboxed; stack_pointer[-2] = left_unboxed; DISPATCH(); } - TARGET(BINARY_OP_ADD_FLOAT_REST) { + TARGET(UNARY_CHECK_FLOAT) { + PyObject *arg = stack_pointer[-(1 + oparg)]; + assert(cframe.use_tracing == 0); + bb_test = PyFloat_CheckExact(arg); + DISPATCH(); + } + + TARGET(BINARY_OP_ADD_FLOAT_UNBOXED) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *sum; STAT_INC(BINARY_OP, hit); - double dsum = ((PyFloatObject *)left)->ob_fval + - ((PyFloatObject *)right)->ob_fval; - DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsum, sum); + double temp = *(double *)(&(left)) + *(double *)(&(right)); + sum = *(PyObject **)(&temp); STACK_SHRINK(1); stack_pointer[-1] = sum; DISPATCH(); } + TARGET(UNBOX_FLOAT) { + PyObject *boxed_float = stack_pointer[-(1 + oparg)]; + PyObject *unboxed_float; + double temp = ((PyFloatObject *)boxed_float)->ob_fval; + unboxed_float = (*(PyObject **)(&temp)); + stack_pointer[-(1 + oparg)] = unboxed_float; + DISPATCH(); + } + + TARGET(BOX_FLOAT) { + PyObject *raw_float = stack_pointer[-(1 + oparg)]; + PyObject *boxed_float; + boxed_float = PyFloat_FromDouble(*(double *)(&(raw_float))); + stack_pointer[-(1 + oparg)] = boxed_float; + DISPATCH(); + } + TARGET(BINARY_OP_ADD_INT) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 4a7209e7cf6c0d..9a14cd4e009cb6 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -21,10 +21,18 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 0; case LOAD_FAST: return 0; + case LOAD_FAST_NO_INCREF: + return 0; case LOAD_CONST: return 0; case STORE_FAST: return 1; + case STORE_FAST_BOXED_UNBOXED: + return 1; + case STORE_FAST_UNBOXED_BOXED: + return 1; + case STORE_FAST_UNBOXED_UNBOXED: + return 1; case LOAD_FAST__LOAD_FAST: return 0+0; case LOAD_FAST__LOAD_CONST: @@ -63,8 +71,14 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 2; case BINARY_CHECK_FLOAT: return 2; - case BINARY_OP_ADD_FLOAT_REST: + case UNARY_CHECK_FLOAT: + return oparg + 1; + case BINARY_OP_ADD_FLOAT_UNBOXED: return 2; + case UNBOX_FLOAT: + return oparg + 1; + case BOX_FLOAT: + return oparg + 1; case BINARY_OP_ADD_INT: return 2; case BINARY_CHECK_INT: @@ -411,10 +425,18 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 1; case LOAD_FAST: return 1; + case LOAD_FAST_NO_INCREF: + return 1; case LOAD_CONST: return 1; case STORE_FAST: return 0; + case STORE_FAST_BOXED_UNBOXED: + return 0; + case STORE_FAST_UNBOXED_BOXED: + return 0; + case STORE_FAST_UNBOXED_UNBOXED: + return 0; case LOAD_FAST__LOAD_FAST: return 1+1; case LOAD_FAST__LOAD_CONST: @@ -453,8 +475,14 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 1; case BINARY_CHECK_FLOAT: return 2; - case BINARY_OP_ADD_FLOAT_REST: + case UNARY_CHECK_FLOAT: + return oparg + 1; + case BINARY_OP_ADD_FLOAT_UNBOXED: return 1; + case UNBOX_FLOAT: + return oparg + 1; + case BOX_FLOAT: + return oparg + 1; case BINARY_OP_ADD_INT: return 1; case BINARY_CHECK_INT: @@ -803,8 +831,12 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [LOAD_CLOSURE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [LOAD_FAST_CHECK] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [LOAD_FAST_NO_INCREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [LOAD_CONST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [STORE_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [STORE_FAST_BOXED_UNBOXED] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [STORE_FAST_UNBOXED_BOXED] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [STORE_FAST_UNBOXED_UNBOXED] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [LOAD_FAST__LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, [LOAD_FAST__LOAD_CONST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, [STORE_FAST__LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, @@ -824,7 +856,10 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [BINARY_OP_INPLACE_ADD_UNICODE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [BINARY_OP_ADD_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, [BINARY_CHECK_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BINARY_OP_ADD_FLOAT_REST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [UNARY_CHECK_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [BINARY_OP_ADD_FLOAT_UNBOXED] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [UNBOX_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [BOX_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [BINARY_OP_ADD_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, [BINARY_CHECK_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [BINARY_OP_ADD_INT_REST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, diff --git a/Python/tier2.c b/Python/tier2.c index 0b33b89e4e4490..06d94e0c9c73b2 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -16,6 +16,13 @@ #define BB_EPILOG 0 +/* Dummy types used by the types propagator */ +PyTypeObject PyRawFloat_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "rawfloat", + sizeof(PyFloatObject), +}; + static inline int IS_SCOPE_EXIT_OPCODE(int opcode); @@ -159,11 +166,6 @@ type_propagate( type_context->type_stack_ptr = type_stackptr; #undef TARGET -#undef TYPESTACK_PEEK -#undef TYPESTACK_POKE -#undef TYPELOCALS_SET -#undef TYPELOCALS_GET -#undef TYPECONST_GET #undef STACK_ADJUST #undef STACK_GROW #undef STACK_SHRINK @@ -400,9 +402,23 @@ static inline int IS_FORBIDDEN_OPCODE(int opcode) { switch (opcode) { + // Modifying containers + case LIST_EXTEND: + case SET_UPDATE: + case DICT_UPDATE: + // f-strings + case FORMAT_VALUE: + // Type hinting + case SETUP_ANNOTATIONS: + // Context manager + case BEFORE_WITH: // Generators and coroutines case SEND: case YIELD_VALUE: + case GET_AITER: + case GET_ANEXT: + case BEFORE_ASYNC_WITH: + case END_ASYNC_FOR: // Raise keyword case RAISE_VARARGS: // Exceptions, we could support these theoretically. @@ -410,8 +426,11 @@ IS_FORBIDDEN_OPCODE(int opcode) case PUSH_EXC_INFO: case RERAISE: case POP_EXCEPT: + case CHECK_EXC_MATCH: + case CLEANUP_THROW: // Closures case LOAD_DEREF: + case LOAD_CLASSDEREF: case MAKE_CELL: // DELETE_FAST case DELETE_FAST: @@ -429,6 +448,24 @@ IS_FORBIDDEN_OPCODE(int opcode) } } +// Decides what values we need to rebox. +// num_elements is how many stack entries and thus how far from the TOS we want to rebox. +static inline _Py_CODEUNIT * +rebox_stack(_Py_CODEUNIT *write_curr, + _PyTier2TypeContext *type_context, int num_elements) +{ + for (int i = 0; i < num_elements; i++) { + PyTypeObject **curr = type_context->type_stack_ptr - 1 - i; + if (*curr == &PyRawFloat_Type) { + write_curr->op.code = BOX_FLOAT; + write_curr->op.arg = i; + write_curr++; + type_propagate(BOX_FLOAT, i, type_context, NULL); + } + } + return write_curr; +} + static inline _Py_CODEUNIT * emit_cache_entries(_Py_CODEUNIT *write_curr, int cache_entries) { @@ -617,10 +654,15 @@ emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, } static inline _Py_CODEUNIT * -emit_scope_exit(_Py_CODEUNIT *write_curr, _Py_CODEUNIT exit) +emit_scope_exit(_Py_CODEUNIT *write_curr, _Py_CODEUNIT exit, + _PyTier2TypeContext *type_context) { switch (_Py_OPCODE(exit)) { case RETURN_VALUE: + write_curr = rebox_stack(write_curr, type_context, 1); + *write_curr = exit; + write_curr++; + return write_curr; case RETURN_CONST: case INTERPRETER_EXIT: #if BB_DEBUG @@ -743,7 +785,16 @@ infer_BINARY_OP_ADD( return write_curr; } } + if (left == &PyRawFloat_Type) { + if (right == &PyRawFloat_Type) { + write_curr->op.code = BINARY_OP_ADD_FLOAT_UNBOXED; + write_curr++; + type_propagate(BINARY_OP_ADD_FLOAT_UNBOXED, 0, type_context, NULL); + return write_curr; + } + } // Unknown, time to emit the chain of guards. + write_curr = rebox_stack(write_curr, type_context, 2); *needs_guard = true; if (prev_type_guard == NULL) { return emit_type_guard(write_curr, BINARY_CHECK_INT, bb_id); @@ -761,6 +812,12 @@ infer_BINARY_OP_ADD( return NULL; } +static inline bool +is_unboxed_type(PyTypeObject *t) +{ + return t == &PyRawFloat_Type; +} + // Detects a BB from the current instruction start to the end of the first basic block it sees. // Then emits the instructions into the bb space. // @@ -836,8 +893,7 @@ _PyTier2_Code_DetectAndEmitBB( opcode = RESUME_QUICK; DISPATCH(); case COMPARE_AND_BRANCH: - opcode = COMPARE_OP; - specop = COMPARE_OP; + opcode = specop = COMPARE_OP; DISPATCH(); case END_FOR: // Assert that we are the start of a BB @@ -846,6 +902,73 @@ _PyTier2_Code_DetectAndEmitBB( // So we tell the BB to skip over it. t2_start++; DISPATCH(); + case LOAD_CONST: + if (TYPECONST_GET(oparg) == &PyFloat_Type) { + write_i->op.code = LOAD_CONST; + write_i->op.arg = oparg; + write_i++; + type_propagate(LOAD_CONST, oparg, starting_type_context, consts); + write_i->op.code = UNBOX_FLOAT; + write_i->op.arg = 0; + write_i++; + type_propagate(UNBOX_FLOAT, 0, starting_type_context, consts); + continue; + } + DISPATCH(); + case LOAD_FAST: { + // Read-only, only for us to inspect the types. DO NOT MODIFY HERE. + // ONLY THE TYPES PROPAGATOR SHOULD MODIFY THEIR INTERNAL VALUES. + PyTypeObject **type_stack = starting_type_context->type_stack; + PyTypeObject **type_locals = starting_type_context->type_locals; + PyTypeObject **type_stackptr = starting_type_context->type_stack_ptr; + // Writing unboxed val to a boxed val. + if (is_unboxed_type(TYPELOCALS_GET(oparg))) { + opcode = specop = LOAD_FAST_NO_INCREF; + } + else { + opcode = specop = LOAD_FAST; + } + DISPATCH(); + } + case STORE_FAST: { + // Read-only, only for us to inspect the types. DO NOT MODIFY HERE. + // ONLY THE TYPES PROPAGATOR SHOULD MODIFY THEIR INTERNAL VALUES. + PyTypeObject **type_stack = starting_type_context->type_stack; + PyTypeObject **type_locals = starting_type_context->type_locals; + PyTypeObject **type_stackptr = starting_type_context->type_stack_ptr; + // Writing unboxed val to a boxed val. + if (is_unboxed_type(TYPESTACK_PEEK(1))) { + if (!is_unboxed_type(TYPELOCALS_GET(oparg))) { + opcode = specop = STORE_FAST_UNBOXED_BOXED; + } + else { + opcode = specop = STORE_FAST_UNBOXED_UNBOXED; + } + } + else { + if (is_unboxed_type(TYPELOCALS_GET(oparg))) { + opcode = specop = STORE_FAST_BOXED_UNBOXED; + } + else { + opcode = specop = STORE_FAST; + } + } + DISPATCH(); + } + // Need to handle reboxing at these boundaries. + case CALL: + write_i = rebox_stack(write_i, starting_type_context, + oparg + 2); + DISPATCH(); + case BUILD_MAP: + write_i = rebox_stack(write_i, starting_type_context, + oparg * 2); + DISPATCH(); + case BUILD_STRING: + case BUILD_LIST: + write_i = rebox_stack(write_i, starting_type_context, + oparg); + DISPATCH(); case BINARY_OP: if (oparg == NB_ADD) { // Add operation. Need to check if we can infer types. @@ -868,7 +991,24 @@ _PyTier2_Code_DetectAndEmitBB( i += caches; continue; } + write_i = rebox_stack(write_i, starting_type_context, 2); DISPATCH() + case LOAD_ATTR: + case CALL_INTRINSIC_1: + case UNARY_NEGATIVE: + case UNARY_NOT: + case UNARY_INVERT: + case GET_LEN: + write_i = rebox_stack(write_i, starting_type_context, 1); + DISPATCH(); + case CALL_INTRINSIC_2: + case BINARY_SUBSCR: + case BINARY_SLICE: + write_i = rebox_stack(write_i, starting_type_context, 2); + DISPATCH(); + case STORE_SLICE: + write_i = rebox_stack(write_i, starting_type_context, 4); + DISPATCH(); default: #if BB_DEBUG || TYPEPROP_DEBUG fprintf(stderr, "offset: %Id\n", curr - _PyCode_CODE(co)); @@ -903,10 +1043,12 @@ _PyTier2_Code_DetectAndEmitBB( return NULL; } bb_space->water_level += (write_i - t2_start) * sizeof(_Py_CODEUNIT); - // Reset the start + // Reset all our values t2_start = write_i; i++; virtual_start = true; + starting_type_context = type_context_copy; + // Don't change opcode or oparg, let us handle it again. DISPATCH_GOTO(); } @@ -914,7 +1056,7 @@ _PyTier2_Code_DetectAndEmitBB( // These are definitely the end of a basic block. if (IS_SCOPE_EXIT_OPCODE(opcode)) { // Emit the scope exit instruction. - write_i = emit_scope_exit(write_i, *curr); + write_i = emit_scope_exit(write_i, *curr, starting_type_context); END(); } @@ -1513,3 +1655,9 @@ _PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *tar _py_set_opcode(write_curr, END_FOR); write_curr++; } + +#undef TYPESTACK_PEEK +#undef TYPESTACK_POKE +#undef TYPELOCALS_SET +#undef TYPELOCALS_GET +#undef TYPECONST_GET diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index 6dcabba76bfd15..94690bf372c7c4 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -33,6 +33,12 @@ break; } + TARGET(LOAD_FAST_NO_INCREF) { + STACK_GROW(1); + TYPESTACK_POKE(1, TYPELOCALS_GET(oparg)); + break; + } + TARGET(LOAD_CONST) { STACK_GROW(1); TYPESTACK_POKE(1, TYPECONST_GET(oparg)); @@ -46,6 +52,27 @@ break; } + TARGET(STORE_FAST_BOXED_UNBOXED) { + PyTypeObject *value = TYPESTACK_PEEK(1); + TYPELOCALS_SET(oparg, value) + STACK_SHRINK(1); + break; + } + + TARGET(STORE_FAST_UNBOXED_BOXED) { + PyTypeObject *value = TYPESTACK_PEEK(1); + TYPELOCALS_SET(oparg, value) + STACK_SHRINK(1); + break; + } + + TARGET(STORE_FAST_UNBOXED_UNBOXED) { + PyTypeObject *value = TYPESTACK_PEEK(1); + TYPELOCALS_SET(oparg, value) + STACK_SHRINK(1); + break; + } + TARGET(POP_TOP) { STACK_SHRINK(1); break; @@ -129,9 +156,24 @@ break; } - TARGET(BINARY_OP_ADD_FLOAT_REST) { + TARGET(UNARY_CHECK_FLOAT) { + TYPESTACK_POKE(1 + oparg, &PyFloat_Type); + break; + } + + TARGET(BINARY_OP_ADD_FLOAT_UNBOXED) { STACK_SHRINK(1); - TYPESTACK_POKE(1, &PyFloat_Type); + TYPESTACK_POKE(1, &PyRawFloat_Type); + break; + } + + TARGET(UNBOX_FLOAT) { + TYPESTACK_POKE(1 + oparg, &PyRawFloat_Type); + break; + } + + TARGET(BOX_FLOAT) { + TYPESTACK_POKE(1 + oparg, &PyFloat_Type); break; } diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py index 6718973702cdf0..26a1d3b99e1f7f 100644 --- a/Tools/build/deepfreeze.py +++ b/Tools/build/deepfreeze.py @@ -260,7 +260,8 @@ def generate_code(self, name: str, code: types.CodeType) -> str: self.field(code, "co_posonlyargcount") self.field(code, "co_kwonlyargcount") # The following should remain in sync with _PyFrame_NumSlotsForCodeObject - self.write(f".co_framesize = {code.co_stacksize + len(localsplusnames)} + FRAME_SPECIALS_SIZE,") + self.write(f".co_framesize = {code.co_stacksize + len(localsplusnames)} + FRAME_SPECIALS_SIZE" + f" + ({len(localsplusnames)} * sizeof(char) / sizeof(PyObject *) + 1),") self.field(code, "co_stacksize") self.field(code, "co_firstlineno") self.write(f".co_nlocalsplus = {len(localsplusnames)},") From 34cca1e0073dcc2a4644f51546b044c05ff94215 Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 20 Mar 2023 22:10:28 +0800 Subject: [PATCH 078/280] Feat: Allow multiple type operations per annotation --- Python/bytecodes.c | 6 ++- Python/tier2_typepropagator.c.h | 2 + Tools/cases_generator/generate_cases.py | 69 +++++++++++++------------ Tools/cases_generator/parser.py | 31 ++++++++--- 4 files changed, 68 insertions(+), 40 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 72ba844f017f41..face540aee1b1d 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -279,7 +279,11 @@ dummy_func( U_INST(BINARY_OP_ADD_FLOAT_REST); } - inst(BINARY_CHECK_FLOAT, (left, right -- left : <<= PyFloat_Type, right : <<= PyFloat_Type)) { + inst(BINARY_CHECK_FLOAT, ( + left, right + -- left : {<<= PyFloat_Type, PyRawFloat_Type}, + right: {<<= PyFloat_Type, PyRawFloat_Type}) + ) { assert(cframe.use_tracing == 0); bb_test = PyFloat_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); } diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index 72c7eb9cc4d60f..cf123dd6b2d59d 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -125,7 +125,9 @@ TARGET(BINARY_CHECK_FLOAT) { TYPE_SET((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyRawFloat_Type), TYPESTACK_PEEK(1), true); TYPE_SET((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(2), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyRawFloat_Type), TYPESTACK_PEEK(2), true); break; } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index e67608a83ffea3..16128dc85a7402 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -343,13 +343,15 @@ def write_typeprop(self, out: Formatter) -> None: # Stack input is used in output effect for oeffect in self.output_effects: if not (typ := oeffect.type_annotation): continue - if not isinstance(src := typ.src, TypeSrcStackInput): continue - if oeffect.name in self.unmoved_names and oeffect.name == src.name: - print( - f"Warn: {self.name} type annotation for {oeffect.name} will be ignored " - "as it is unmoved") - continue - need_to_declare.append(src.name) + ops = typ.ops + for op in ops: + if not isinstance(src := op.src, TypeSrcStackInput): continue + if oeffect.name in self.unmoved_names and oeffect.name == src.name: + print( + f"Warn: {self.name} type annotation for {oeffect.name} will be ignored " + "as it is unmoved") + continue + need_to_declare.append(src.name) # Write input stack effect variable declarations and initializations ieffects = list(reversed(self.input_effects)) @@ -424,33 +426,34 @@ def write_typeprop(self, out: Formatter) -> None: # Check if there's type info if typ := oeffect.type_annotation: - match typ.src: - case TypeSrcLiteral(literal=valstr): - if valstr == "NULL": - src = "(_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT" - flag = "true" - else: - src = f"(_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&{valstr})" + for op in typ.ops: + match op.src: + case TypeSrcLiteral(literal=valstr): + if valstr == "NULL": + src = "(_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT" + flag = "true" + else: + src = f"(_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&{valstr})" + flag = "true" + case TypeSrcStackInput(name=valstr): + assert valstr in need_to_declare + assert oeffect.name not in self.unmoved_names + src = valstr + flag = "false" + case TypeSrcConst(index=idx): + src = f"(_Py_TYPENODE_t *)TYPECONST_GET({idx})" flag = "true" - case TypeSrcStackInput(name=valstr): - assert valstr in need_to_declare - assert oeffect.name not in self.unmoved_names - src = valstr - flag = "false" - case TypeSrcConst(index=idx): - src = f"(_Py_TYPENODE_t *)TYPECONST_GET({idx})" - flag = "true" - case TypeSrcLocals(index=idx): - src = f"TYPELOCALS_GET({idx})" - flag = "false" - case _: - typing.assert_never(typ.src) - - opstr = f"{typ.op}({src}, {dst}, {flag})" - if oeffect.cond: - out.emit(f"if ({oeffect.cond}) {{ {opstr}; }}") - else: - out.emit(f"{opstr};") + case TypeSrcLocals(index=idx): + src = f"TYPELOCALS_GET({idx})" + flag = "false" + case _: + typing.assert_never(op.src) + + opstr = f"{op.op}({src}, {dst}, {flag})" + if oeffect.cond: + out.emit(f"if ({oeffect.cond}) {{ {opstr}; }}") + else: + out.emit(f"{opstr};") continue # Don't touch unmoved stack vars diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index 48ad3cefa0fef4..658b1b0d46c513 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -95,12 +95,14 @@ class TypeSrcStackInput(Node): | TypeSrcStackInput ) - @dataclass -class TypeAnnotation(Node): +class TypeOperation(Node): op: Literal["TYPE_SET", "TYPE_OVERWRITE"] src: TypeSrc +@dataclass +class TypeAnnotation(Node): + ops: tuple[TypeOperation] @dataclass class StackEffect(Node): @@ -331,7 +333,7 @@ def stack_effect(self) -> StackEffect | None: type_annotation = None if self.expect(lx.COLON): has_type_annotation = True - type_annotation = self.stackvar_type() + type_annotation = self.stackvar_typeannotation() cond_text = "" if self.expect(lx.IF): self.require(lx.LPAREN) @@ -368,14 +370,31 @@ def stackvar_typesrc(self) -> TypeSrc | None: return TypeSrcStackInput(id.text.strip()) @contextual - def stackvar_type(self) -> TypeAnnotation | None: + def stackvar_typeoperation(self) -> TypeOperation | None: if self.expect(lx.LSHIFTEQUAL): src = self.stackvar_typesrc() if src is None: return None - return TypeAnnotation("TYPE_SET", src) + return TypeOperation("TYPE_SET", src) src = self.stackvar_typesrc() if src is None: return None - return TypeAnnotation("TYPE_OVERWRITE", src) + return TypeOperation("TYPE_OVERWRITE", src) + + @contextual + def stackvar_typeannotation(self) -> TypeAnnotation | None: + ops = [] + if self.expect(lx.LBRACE): + while True: + typ = self.stackvar_typeoperation() + ops.append(typ) + if typ is None: return None + if self.expect(lx.RBRACE): + break + self.require(lx.COMMA) + else: + typ = self.stackvar_typeoperation() + if typ is None: return None + ops.append(typ) + return TypeAnnotation(tuple(ops)) @contextual def local_effect(self) -> LocalEffect | None: From 79a204c453eb1354b38550fd9e27beb9ce31e6ca Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 20 Mar 2023 22:59:41 +0800 Subject: [PATCH 079/280] unbox when loading from fastlocals --- Python/tier2.c | 22 +- Python/tier2_typepropagator.c.h | 1107 +++++++++++++++++++++++++++++++ 2 files changed, 1126 insertions(+), 3 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index f296c884121ac9..387d702b45ddee 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -529,6 +529,7 @@ _PyTier2_BBSpaceCheckAndReallocIfNeeded(PyCodeObject *co, Py_ssize_t space_reque #if BB_DEBUG fprintf(stderr, "Allocating new BB of size %lld\n", new_size); #endif + // @TODO We can't Realloc, we actually need to do the linked list method. _PyTier2BBSpace *new_space = PyMem_Realloc(curr, new_size); if (new_space == NULL) { return NULL; @@ -809,7 +810,7 @@ static int type_guard_to_index[256] = { static inline _Py_CODEUNIT * emit_type_guard(_Py_CODEUNIT *write_curr, int guard_opcode, int bb_id) { -#if BB_DEBUG +#if BB_DEBUG && defined(Py_DEBUG) fprintf(stderr, "emitted type guard %p %s\n", write_curr, _PyOpcode_OpName[guard_opcode]); #endif @@ -1200,7 +1201,10 @@ _PyTier2_Code_DetectAndEmitBB( // So we tell the BB to skip over it. t2_start++; DISPATCH(); - case LOAD_CONST: + case LOAD_CONST: { + _Py_TYPENODE_t *type_stack = starting_type_context->type_stack; + _Py_TYPENODE_t *type_locals = starting_type_context->type_locals; + _Py_TYPENODE_t **type_stackptr = &starting_type_context->type_stack_ptr; if (TYPECONST_GET(oparg) == &PyFloat_Type) { write_i->op.code = LOAD_CONST; write_i->op.arg = oparg; @@ -1213,6 +1217,7 @@ _PyTier2_Code_DetectAndEmitBB( continue; } DISPATCH(); + } case LOAD_FAST: { // Read-only, only for us to inspect the types. DO NOT MODIFY HERE. // ONLY THE TYPES PROPAGATOR SHOULD MODIFY THEIR INTERNAL VALUES. @@ -1224,6 +1229,17 @@ _PyTier2_Code_DetectAndEmitBB( opcode = specop = LOAD_FAST_NO_INCREF; } else { + if (TYPELOCALS_GET(oparg) == &PyFloat_Type) { + write_i->op.code = LOAD_FAST; + write_i->op.arg = oparg; + write_i++; + type_propagate(LOAD_FAST, oparg, starting_type_context, consts); + write_i->op.code = UNBOX_FLOAT; + write_i->op.arg = 0; + write_i++; + type_propagate(UNBOX_FLOAT, oparg, starting_type_context, consts); + continue; + } opcode = specop = LOAD_FAST; } DISPATCH(); @@ -1773,7 +1789,7 @@ _PyTier2_GenerateNextBB( // one of those conditional pops. assert(!gen_bb_requires_pop); // Propagate the type guard information. -#if TYPEPROP_DEBUG +#if TYPEPROP_DEBUG && defined(Py_DEBUG) fprintf(stderr, " [-] Previous predicate BB ended with a type guard: %s\n", _PyOpcode_OpName[prev_type_guard->op.code]); diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index e69de29bb2d1d6..11ecd8de10d44f 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -0,0 +1,1107 @@ +// This file is generated by Tools/cases_generator/generate_cases.py @TODO: make this a seperate argument +// from: +// Python/bytecodes.c +// Do not edit! + + TARGET(NOP) { + break; + } + + TARGET(RESUME) { + break; + } + + TARGET(RESUME_QUICK) { + break; + } + + TARGET(LOAD_CLOSURE) { + STACK_GROW(1); + TYPE_OVERWRITE(TYPELOCALS_GET(oparg), TYPESTACK_PEEK(1), false); + break; + } + + TARGET(LOAD_FAST_CHECK) { + STACK_GROW(1); + TYPE_OVERWRITE(TYPELOCALS_GET(oparg), TYPESTACK_PEEK(1), false); + break; + } + + TARGET(LOAD_FAST) { + STACK_GROW(1); + TYPE_OVERWRITE(TYPELOCALS_GET(oparg), TYPESTACK_PEEK(1), false); + break; + } + + TARGET(LOAD_FAST_NO_INCREF) { + STACK_GROW(1); + TYPE_OVERWRITE(TYPELOCALS_GET(oparg), TYPESTACK_PEEK(1), false); + break; + } + + TARGET(LOAD_CONST) { + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)TYPECONST_GET(oparg), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(STORE_FAST) { + _Py_TYPENODE_t *value = TYPESTACK_PEEK(1); + TYPE_OVERWRITE(value, TYPELOCALS_GET(oparg), false); + STACK_SHRINK(1); + break; + } + + TARGET(STORE_FAST_BOXED_UNBOXED) { + _Py_TYPENODE_t *value = TYPESTACK_PEEK(1); + TYPE_OVERWRITE(value, TYPELOCALS_GET(oparg), false); + STACK_SHRINK(1); + break; + } + + TARGET(STORE_FAST_UNBOXED_BOXED) { + _Py_TYPENODE_t *value = TYPESTACK_PEEK(1); + TYPE_OVERWRITE(value, TYPELOCALS_GET(oparg), false); + STACK_SHRINK(1); + break; + } + + TARGET(STORE_FAST_UNBOXED_UNBOXED) { + _Py_TYPENODE_t *value = TYPESTACK_PEEK(1); + TYPE_OVERWRITE(value, TYPELOCALS_GET(oparg), false); + STACK_SHRINK(1); + break; + } + + TARGET(POP_TOP) { + STACK_SHRINK(1); + break; + } + + TARGET(PUSH_NULL) { + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(END_FOR) { + { + STACK_SHRINK(1); + } + { + STACK_SHRINK(1); + } + break; + } + + TARGET(UNARY_NEGATIVE) { + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(UNARY_NOT) { + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(UNARY_INVERT) { + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(BINARY_OP_MULTIPLY_INT) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyLong_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(BINARY_OP_MULTIPLY_FLOAT) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(BINARY_OP_SUBTRACT_INT) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyLong_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(BINARY_OP_SUBTRACT_FLOAT) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(BINARY_OP_ADD_UNICODE) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyUnicode_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(BINARY_OP_INPLACE_ADD_UNICODE) { + STACK_SHRINK(2); + break; + } + + TARGET(BINARY_OP_ADD_FLOAT) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(BINARY_CHECK_FLOAT) { + TYPE_SET((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyRawFloat_Type), TYPESTACK_PEEK(1), true); + TYPE_SET((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(2), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyRawFloat_Type), TYPESTACK_PEEK(2), true); + break; + } + + TARGET(UNARY_CHECK_FLOAT) { + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(1 + oparg), true); + break; + } + + TARGET(BINARY_OP_ADD_FLOAT_UNBOXED) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyRawFloat_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(UNBOX_FLOAT) { + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyRawFloat_Type), TYPESTACK_PEEK(1 + oparg), true); + break; + } + + TARGET(BOX_FLOAT) { + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(1 + oparg), true); + break; + } + + TARGET(BINARY_OP_ADD_INT) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyLong_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(BINARY_CHECK_INT) { + TYPE_SET((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyLong_Type), TYPESTACK_PEEK(1), true); + TYPE_SET((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyLong_Type), TYPESTACK_PEEK(2), true); + break; + } + + TARGET(BINARY_OP_ADD_INT_REST) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyLong_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(BINARY_SUBSCR) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(BINARY_SLICE) { + STACK_SHRINK(2); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(STORE_SLICE) { + STACK_SHRINK(4); + break; + } + + TARGET(BINARY_SUBSCR_LIST_INT) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(BINARY_SUBSCR_TUPLE_INT) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(BINARY_SUBSCR_DICT) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(BINARY_SUBSCR_GETITEM) { + STACK_SHRINK(1); + break; + } + + TARGET(LIST_APPEND) { + STACK_SHRINK(1); + break; + } + + TARGET(SET_ADD) { + STACK_SHRINK(1); + break; + } + + TARGET(STORE_SUBSCR) { + STACK_SHRINK(3); + break; + } + + TARGET(STORE_SUBSCR_LIST_INT) { + STACK_SHRINK(3); + break; + } + + TARGET(STORE_SUBSCR_DICT) { + STACK_SHRINK(3); + break; + } + + TARGET(DELETE_SUBSCR) { + STACK_SHRINK(2); + break; + } + + TARGET(CALL_INTRINSIC_1) { + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(CALL_INTRINSIC_2) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(RAISE_VARARGS) { + fprintf(stderr, "Type propagation across `RAISE_VARARGS` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); + break; + } + + TARGET(INTERPRETER_EXIT) { + STACK_SHRINK(1); + break; + } + + TARGET(RETURN_VALUE) { + STACK_SHRINK(1); + break; + } + + TARGET(RETURN_CONST) { + break; + } + + TARGET(GET_AITER) { + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(GET_ANEXT) { + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(GET_AWAITABLE) { + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(SEND) { + fprintf(stderr, "Type propagation across `SEND` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); + break; + } + + TARGET(SEND_GEN) { + fprintf(stderr, "Type propagation across `SEND_GEN` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); + break; + } + + TARGET(YIELD_VALUE) { + fprintf(stderr, "Type propagation across `YIELD_VALUE` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); + break; + } + + TARGET(POP_EXCEPT) { + fprintf(stderr, "Type propagation across `POP_EXCEPT` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); + break; + } + + TARGET(RERAISE) { + fprintf(stderr, "Type propagation across `RERAISE` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); + break; + } + + TARGET(END_ASYNC_FOR) { + STACK_SHRINK(2); + break; + } + + TARGET(CLEANUP_THROW) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(2), true); + break; + } + + TARGET(LOAD_ASSERTION_ERROR) { + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(LOAD_BUILD_CLASS) { + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(STORE_NAME) { + STACK_SHRINK(1); + break; + } + + TARGET(DELETE_NAME) { + break; + } + + TARGET(UNPACK_SEQUENCE) { + STACK_SHRINK(1); + STACK_GROW(oparg); + break; + } + + TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { + STACK_SHRINK(1); + STACK_GROW(oparg); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(oparg), true); + break; + } + + TARGET(UNPACK_SEQUENCE_TUPLE) { + STACK_SHRINK(1); + STACK_GROW(oparg); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(oparg), true); + break; + } + + TARGET(UNPACK_SEQUENCE_LIST) { + STACK_SHRINK(1); + STACK_GROW(oparg); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(oparg), true); + break; + } + + TARGET(UNPACK_EX) { + STACK_GROW((oparg & 0xFF) + (oparg >> 8)); + break; + } + + TARGET(STORE_ATTR) { + STACK_SHRINK(2); + break; + } + + TARGET(DELETE_ATTR) { + STACK_SHRINK(1); + break; + } + + TARGET(STORE_GLOBAL) { + STACK_SHRINK(1); + break; + } + + TARGET(DELETE_GLOBAL) { + break; + } + + TARGET(LOAD_NAME) { + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(LOAD_GLOBAL) { + STACK_GROW(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + break; + } + + TARGET(LOAD_GLOBAL_MODULE) { + STACK_GROW(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + break; + } + + TARGET(LOAD_GLOBAL_BUILTIN) { + STACK_GROW(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + break; + } + + TARGET(DELETE_FAST) { + fprintf(stderr, "Type propagation across `DELETE_FAST` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); + break; + } + + TARGET(MAKE_CELL) { + fprintf(stderr, "Type propagation across `MAKE_CELL` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); + break; + } + + TARGET(DELETE_DEREF) { + break; + } + + TARGET(LOAD_CLASSDEREF) { + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(LOAD_DEREF) { + fprintf(stderr, "Type propagation across `LOAD_DEREF` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); + break; + } + + TARGET(STORE_DEREF) { + STACK_SHRINK(1); + break; + } + + TARGET(COPY_FREE_VARS) { + break; + } + + TARGET(BUILD_STRING) { + STACK_SHRINK(oparg); + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyUnicode_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(BUILD_TUPLE) { + STACK_SHRINK(oparg); + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyTuple_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(BUILD_LIST) { + STACK_SHRINK(oparg); + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyList_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(LIST_EXTEND) { + STACK_SHRINK(1); + break; + } + + TARGET(SET_UPDATE) { + STACK_SHRINK(1); + break; + } + + TARGET(BUILD_SET) { + STACK_SHRINK(oparg); + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PySet_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(BUILD_MAP) { + STACK_SHRINK(oparg*2); + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyDict_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(SETUP_ANNOTATIONS) { + break; + } + + TARGET(BUILD_CONST_KEY_MAP) { + STACK_SHRINK(oparg); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyDict_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(DICT_UPDATE) { + STACK_SHRINK(1); + break; + } + + TARGET(DICT_MERGE) { + STACK_SHRINK(1); + break; + } + + TARGET(MAP_ADD) { + STACK_SHRINK(2); + break; + } + + TARGET(LOAD_ATTR) { + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + break; + } + + TARGET(LOAD_ATTR_INSTANCE_VALUE) { + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + break; + } + + TARGET(LOAD_ATTR_MODULE) { + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + break; + } + + TARGET(LOAD_ATTR_WITH_HINT) { + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + break; + } + + TARGET(LOAD_ATTR_SLOT) { + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + break; + } + + TARGET(LOAD_ATTR_CLASS) { + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + break; + } + + TARGET(LOAD_ATTR_PROPERTY) { + STACK_GROW(((oparg & 1) ? 1 : 0)); + break; + } + + TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { + STACK_GROW(((oparg & 1) ? 1 : 0)); + break; + } + + TARGET(STORE_ATTR_INSTANCE_VALUE) { + STACK_SHRINK(2); + break; + } + + TARGET(STORE_ATTR_WITH_HINT) { + STACK_SHRINK(2); + break; + } + + TARGET(STORE_ATTR_SLOT) { + STACK_SHRINK(2); + break; + } + + TARGET(COMPARE_OP) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(COMPARE_AND_BRANCH) { + STACK_SHRINK(2); + break; + } + + TARGET(COMPARE_AND_BRANCH_FLOAT) { + STACK_SHRINK(2); + break; + } + + TARGET(COMPARE_AND_BRANCH_INT) { + STACK_SHRINK(2); + break; + } + + TARGET(COMPARE_AND_BRANCH_STR) { + STACK_SHRINK(2); + break; + } + + TARGET(IS_OP) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyBool_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(CONTAINS_OP) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyBool_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(CHECK_EG_MATCH) { + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(2), true); + break; + } + + TARGET(CHECK_EXC_MATCH) { + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyBool_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(IMPORT_NAME) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(IMPORT_FROM) { + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(JUMP_FORWARD) { + break; + } + + TARGET(JUMP_BACKWARD) { + break; + } + + TARGET(JUMP_BACKWARD_QUICK) { + break; + } + + TARGET(POP_JUMP_IF_FALSE) { + STACK_SHRINK(1); + break; + } + + TARGET(BB_TEST_POP_IF_FALSE) { + STACK_SHRINK(1); + break; + } + + TARGET(POP_JUMP_IF_TRUE) { + STACK_SHRINK(1); + break; + } + + TARGET(BB_TEST_POP_IF_TRUE) { + STACK_SHRINK(1); + break; + } + + TARGET(POP_JUMP_IF_NOT_NONE) { + STACK_SHRINK(1); + break; + } + + TARGET(BB_TEST_POP_IF_NOT_NONE) { + STACK_SHRINK(1); + break; + } + + TARGET(POP_JUMP_IF_NONE) { + STACK_SHRINK(1); + break; + } + + TARGET(BB_TEST_POP_IF_NONE) { + STACK_SHRINK(1); + break; + } + + TARGET(JUMP_IF_FALSE_OR_POP) { + fprintf(stderr, "Type propagation across `JUMP_IF_FALSE_OR_POP` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); + break; + } + + TARGET(BB_TEST_IF_FALSE_OR_POP) { + fprintf(stderr, "Type propagation across `BB_TEST_IF_FALSE_OR_POP` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); + break; + } + + TARGET(JUMP_IF_TRUE_OR_POP) { + fprintf(stderr, "Type propagation across `JUMP_IF_TRUE_OR_POP` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); + break; + } + + TARGET(BB_TEST_IF_TRUE_OR_POP) { + fprintf(stderr, "Type propagation across `BB_TEST_IF_TRUE_OR_POP` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); + break; + } + + TARGET(JUMP_BACKWARD_NO_INTERRUPT) { + break; + } + + TARGET(GET_LEN) { + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyLong_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(MATCH_CLASS) { + STACK_SHRINK(2); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(MATCH_MAPPING) { + fprintf(stderr, "Type propagation across `MATCH_MAPPING` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); + break; + } + + TARGET(MATCH_SEQUENCE) { + fprintf(stderr, "Type propagation across `MATCH_SEQUENCE` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); + break; + } + + TARGET(MATCH_KEYS) { + fprintf(stderr, "Type propagation across `MATCH_KEYS` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); + break; + } + + TARGET(GET_ITER) { + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(GET_YIELD_FROM_ITER) { + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(FOR_ITER) { + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(BB_TEST_ITER) { + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(FOR_ITER_LIST) { + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(FOR_ITER_TUPLE) { + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(FOR_ITER_RANGE) { + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(FOR_ITER_GEN) { + STACK_GROW(1); + break; + } + + TARGET(BEFORE_ASYNC_WITH) { + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(2), true); + break; + } + + TARGET(BEFORE_WITH) { + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(2), true); + break; + } + + TARGET(WITH_EXCEPT_START) { + fprintf(stderr, "Type propagation across `WITH_EXCEPT_START` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); + break; + } + + TARGET(PUSH_EXC_INFO) { + fprintf(stderr, "Type propagation across `PUSH_EXC_INFO` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); + break; + } + + TARGET(LOAD_ATTR_METHOD_WITH_VALUES) { + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + break; + } + + TARGET(LOAD_ATTR_METHOD_NO_DICT) { + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + break; + } + + TARGET(LOAD_ATTR_METHOD_LAZY_DICT) { + STACK_GROW(((oparg & 1) ? 1 : 0)); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + if (oparg & 1) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1 + ((oparg & 1) ? 1 : 0)), true); } + break; + } + + TARGET(KW_NAMES) { + break; + } + + TARGET(CALL) { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + break; + } + + TARGET(CALL_PY_EXACT_ARGS) { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + break; + } + + TARGET(CALL_PY_WITH_DEFAULTS) { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + break; + } + + TARGET(CALL_NO_KW_TYPE_1) { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(CALL_NO_KW_STR_1) { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(CALL_NO_KW_TUPLE_1) { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(CALL_BUILTIN_CLASS) { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(CALL_NO_KW_BUILTIN_O) { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(CALL_NO_KW_BUILTIN_FAST) { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(CALL_BUILTIN_FAST_WITH_KEYWORDS) { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(CALL_NO_KW_LEN) { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(CALL_NO_KW_ISINSTANCE) { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(CALL_NO_KW_LIST_APPEND) { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + break; + } + + TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS) { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_FAST) { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(CALL_FUNCTION_EX) { + STACK_SHRINK(((oparg & 1) ? 1 : 0)); + STACK_SHRINK(2); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(MAKE_FUNCTION) { + STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0)); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(RETURN_GENERATOR) { + break; + } + + TARGET(BUILD_SLICE) { + STACK_SHRINK(((oparg == 3) ? 1 : 0)); + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(FORMAT_VALUE) { + STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(COPY) { + _Py_TYPENODE_t *bottom = TYPESTACK_PEEK(1 + (oparg-1)); + STACK_GROW(1); + TYPE_OVERWRITE(bottom, TYPESTACK_PEEK(1), false); + break; + } + + TARGET(BINARY_OP) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(SWAP) { + _Py_TYPENODE_t *top = TYPESTACK_PEEK(1); + _Py_TYPENODE_t *bottom = TYPESTACK_PEEK(2 + (oparg-2)); + TYPE_OVERWRITE(bottom, TYPESTACK_PEEK(1), false); + TYPE_OVERWRITE(top, TYPESTACK_PEEK(2 + (oparg-2)), false); + break; + } + + TARGET(EXTENDED_ARG) { + fprintf(stderr, "Type propagation across `EXTENDED_ARG` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); + break; + } + + TARGET(CACHE) { + break; + } + + TARGET(BB_BRANCH) { + break; + } + + TARGET(BB_BRANCH_IF_FLAG_UNSET) { + break; + } + + TARGET(BB_JUMP_IF_FLAG_UNSET) { + break; + } + + TARGET(BB_BRANCH_IF_FLAG_SET) { + break; + } + + TARGET(BB_JUMP_IF_FLAG_SET) { + break; + } + + TARGET(BB_JUMP_BACKWARD_LAZY) { + break; + } From 0eacc5edebac8c2ca05cde5c23ee503fea5711b5 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 20 Mar 2023 23:25:59 +0800 Subject: [PATCH 080/280] Fix up merge problems --- Python/tier2.c | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index 387d702b45ddee..b601261907d552 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -434,7 +434,7 @@ type_propagate( // Get the type of the const and make into a TYPENODE ROOT #define TYPECONST_GET(idx) _Py_TYPENODE_MAKE_ROOT( \ (_Py_TYPENODE_t)Py_TYPE( \ - _PyTuple_CAST(consts)->ob_item[(idx)])) + PyTuple_GET_ITEM(consts, idx))) #define TYPE_SET(src, dst, flag) __type_propagate_TYPE_SET((src), (dst), (flag)) #define TYPE_OVERWRITE(src, dst, flag) __type_propagate_TYPE_OVERWRITE(type_context, (src), (dst), (flag)) @@ -467,6 +467,7 @@ type_propagate( #undef STACK_ADJUST #undef STACK_GROW #undef STACK_SHRINK +#undef TYPECONST_GET } ////////// Utility functions @@ -754,8 +755,8 @@ rebox_stack(_Py_CODEUNIT *write_curr, _PyTier2TypeContext *type_context, int num_elements) { for (int i = 0; i < num_elements; i++) { - PyTypeObject **curr = type_context->type_stack_ptr - 1 - i; - if (*curr == &PyRawFloat_Type) { + _Py_TYPENODE_t *curr = type_context->type_stack_ptr - 1 - i; + if (typenode_get_type(*curr) == &PyRawFloat_Type) { write_curr->op.code = BOX_FLOAT; write_curr->op.arg = i; write_curr++; @@ -1151,7 +1152,7 @@ _PyTier2_Code_DetectAndEmitBB( type_propagate(opcode, oparg, starting_type_context, consts); \ continue; #define DISPATCH_GOTO() goto dispatch_opcode; - +#define TYPECONST_GET_RAWTYPE(idx) Py_TYPE(PyTuple_GET_ITEM(consts, idx)) assert(co->_tier2_info != NULL); // There are only two cases that a BB ends. @@ -1202,10 +1203,7 @@ _PyTier2_Code_DetectAndEmitBB( t2_start++; DISPATCH(); case LOAD_CONST: { - _Py_TYPENODE_t *type_stack = starting_type_context->type_stack; - _Py_TYPENODE_t *type_locals = starting_type_context->type_locals; - _Py_TYPENODE_t **type_stackptr = &starting_type_context->type_stack_ptr; - if (TYPECONST_GET(oparg) == &PyFloat_Type) { + if (TYPECONST_GET_RAWTYPE(oparg) == &PyFloat_Type) { write_i->op.code = LOAD_CONST; write_i->op.arg = oparg; write_i++; @@ -1221,15 +1219,14 @@ _PyTier2_Code_DetectAndEmitBB( case LOAD_FAST: { // Read-only, only for us to inspect the types. DO NOT MODIFY HERE. // ONLY THE TYPES PROPAGATOR SHOULD MODIFY THEIR INTERNAL VALUES. - PyTypeObject **type_stack = starting_type_context->type_stack; - PyTypeObject **type_locals = starting_type_context->type_locals; - PyTypeObject **type_stackptr = starting_type_context->type_stack_ptr; - // Writing unboxed val to a boxed val. - if (is_unboxed_type(TYPELOCALS_GET(oparg))) { + _Py_TYPENODE_t *type_locals = starting_type_context->type_locals; + // Writing unboxed val to a boxed val. + PyTypeObject *local = typenode_get_type(*TYPELOCALS_GET(oparg)); + if (is_unboxed_type(local)) { opcode = specop = LOAD_FAST_NO_INCREF; } else { - if (TYPELOCALS_GET(oparg) == &PyFloat_Type) { + if (local == &PyFloat_Type) { write_i->op.code = LOAD_FAST; write_i->op.arg = oparg; write_i++; @@ -1247,12 +1244,13 @@ _PyTier2_Code_DetectAndEmitBB( case STORE_FAST: { // Read-only, only for us to inspect the types. DO NOT MODIFY HERE. // ONLY THE TYPES PROPAGATOR SHOULD MODIFY THEIR INTERNAL VALUES. - PyTypeObject **type_stack = starting_type_context->type_stack; - PyTypeObject **type_locals = starting_type_context->type_locals; - PyTypeObject **type_stackptr = starting_type_context->type_stack_ptr; + _Py_TYPENODE_t *type_locals = starting_type_context->type_locals; + _Py_TYPENODE_t **type_stackptr = &starting_type_context->type_stack_ptr; + PyTypeObject *local = typenode_get_type(*TYPESTACK_PEEK(1)); + PyTypeObject *store = typenode_get_type(*TYPELOCALS_GET(oparg)); // Writing unboxed val to a boxed val. - if (is_unboxed_type(TYPESTACK_PEEK(1))) { - if (!is_unboxed_type(TYPELOCALS_GET(oparg))) { + if (is_unboxed_type(local)) { + if (!is_unboxed_type(store)) { opcode = specop = STORE_FAST_UNBOXED_BOXED; } else { @@ -1260,7 +1258,7 @@ _PyTier2_Code_DetectAndEmitBB( } } else { - if (is_unboxed_type(TYPELOCALS_GET(oparg))) { + if (is_unboxed_type(store)) { opcode = specop = STORE_FAST_BOXED_UNBOXED; } else { @@ -1974,6 +1972,5 @@ _PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *tar #undef TYPESTACK_POKE #undef TYPELOCALS_SET #undef TYPELOCALS_GET -#undef TYPECONST_GET #undef TYPE_SET #undef TYPE_OVERWRITE From 438873eccaef8097f7cd9d2b17c6a0822ba7bff1 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 21 Mar 2023 00:15:40 +0800 Subject: [PATCH 081/280] Fix more segfaults, write back on LOAD_FAST unboxed --- Include/internal/pycore_opcode.h | 3 +-- Include/opcode.h | 13 +++++++------ Lib/opcode.py | 1 + Python/bytecodes.c | 3 +++ Python/generated_cases.c.h | 6 ++++++ Python/opcode_metadata.h | 5 +++++ Python/tier2.c | 26 ++++++++++++++++++++++++-- Python/tier2_typepropagator.c.h | 5 +++++ 8 files changed, 52 insertions(+), 10 deletions(-) diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index ab2ff150d4bede..5dd2ed17adee51 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -431,13 +431,13 @@ static const char *const _PyOpcode_OpName[263] = { [UNARY_CHECK_FLOAT] = "UNARY_CHECK_FLOAT", [BINARY_OP_ADD_INT_REST] = "BINARY_OP_ADD_INT_REST", [BINARY_OP_ADD_FLOAT_UNBOXED] = "BINARY_OP_ADD_FLOAT_UNBOXED", + [POP_TOP_NO_DECREF] = "POP_TOP_NO_DECREF", [UNBOX_FLOAT] = "UNBOX_FLOAT", [BOX_FLOAT] = "BOX_FLOAT", [LOAD_FAST_NO_INCREF] = "LOAD_FAST_NO_INCREF", [STORE_FAST_BOXED_UNBOXED] = "STORE_FAST_BOXED_UNBOXED", [STORE_FAST_UNBOXED_BOXED] = "STORE_FAST_UNBOXED_BOXED", [STORE_FAST_UNBOXED_UNBOXED] = "STORE_FAST_UNBOXED_UNBOXED", - [200] = "<200>", [201] = "<201>", [202] = "<202>", [203] = "<203>", @@ -505,7 +505,6 @@ static const char *const _PyOpcode_OpName[263] = { #define EXTRA_CASES \ - case 200: \ case 201: \ case 202: \ case 203: \ diff --git a/Include/opcode.h b/Include/opcode.h index a1570a55260b07..1a883aafd96f1b 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -283,12 +283,13 @@ extern "C" { #define UNARY_CHECK_FLOAT 191 #define BINARY_OP_ADD_INT_REST 192 #define BINARY_OP_ADD_FLOAT_UNBOXED 193 -#define UNBOX_FLOAT 194 -#define BOX_FLOAT 195 -#define LOAD_FAST_NO_INCREF 196 -#define STORE_FAST_BOXED_UNBOXED 197 -#define STORE_FAST_UNBOXED_BOXED 198 -#define STORE_FAST_UNBOXED_UNBOXED 199 +#define POP_TOP_NO_DECREF 194 +#define UNBOX_FLOAT 195 +#define BOX_FLOAT 196 +#define LOAD_FAST_NO_INCREF 197 +#define STORE_FAST_BOXED_UNBOXED 198 +#define STORE_FAST_UNBOXED_BOXED 199 +#define STORE_FAST_UNBOXED_UNBOXED 200 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/opcode.py b/Lib/opcode.py index aa1b33a5187c72..e46327cfe680b7 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -510,6 +510,7 @@ def pseudo_op(name, op, real_ops): 'BINARY_OP_ADD_FLOAT_UNBOXED', # Boxing / unboxing ops + 'POP_TOP_NO_DECREF', 'UNBOX_FLOAT', 'BOX_FLOAT', 'LOAD_FAST_NO_INCREF', diff --git a/Python/bytecodes.c b/Python/bytecodes.c index b065e5c22a0877..aedb50a0c3d6bc 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -158,6 +158,9 @@ dummy_func( DECREF_INPUTS(); } + inst(POP_TOP_NO_DECREF, (value--)) { + } + inst(PUSH_NULL, (-- res: NULL)) { res = NULL; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 509c18a45ec8e3..60d7460c8d4d81 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -223,6 +223,12 @@ DISPATCH(); } + TARGET(POP_TOP_NO_DECREF) { + PyObject *value = stack_pointer[-1]; + STACK_SHRINK(1); + DISPATCH(); + } + TARGET(PUSH_NULL) { PyObject *res; res = NULL; diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 9a14cd4e009cb6..24a861100bca47 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -45,6 +45,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 0+0; case POP_TOP: return 1; + case POP_TOP_NO_DECREF: + return 1; case PUSH_NULL: return 0; case END_FOR: @@ -449,6 +451,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 1+1; case POP_TOP: return 0; + case POP_TOP_NO_DECREF: + return 0; case PUSH_NULL: return 1; case END_FOR: @@ -843,6 +847,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [STORE_FAST__STORE_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, [LOAD_CONST__LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, [POP_TOP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [POP_TOP_NO_DECREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [PUSH_NULL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [END_FOR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [UNARY_NEGATIVE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, diff --git a/Python/tier2.c b/Python/tier2.c index b601261907d552..10628e5720404b 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -1202,6 +1202,17 @@ _PyTier2_Code_DetectAndEmitBB( // So we tell the BB to skip over it. t2_start++; DISPATCH(); + case POP_TOP: { + // Read-only, only for us to inspect the types. DO NOT MODIFY HERE. + // ONLY THE TYPES PROPAGATOR SHOULD MODIFY THEIR INTERNAL VALUES. + _Py_TYPENODE_t **type_stackptr = &starting_type_context->type_stack_ptr; + PyTypeObject *pop = typenode_get_type(*TYPESTACK_PEEK(1)); + // Writing unboxed val to a boxed val. + if (is_unboxed_type(pop)) { + opcode = specop = POP_TOP_NO_DECREF; + } + DISPATCH(); + } case LOAD_CONST: { if (TYPECONST_GET_RAWTYPE(oparg) == &PyFloat_Type) { write_i->op.code = LOAD_CONST; @@ -1230,11 +1241,22 @@ _PyTier2_Code_DetectAndEmitBB( write_i->op.code = LOAD_FAST; write_i->op.arg = oparg; write_i++; - type_propagate(LOAD_FAST, oparg, starting_type_context, consts); + type_propagate(LOAD_FAST, + oparg, starting_type_context, consts); write_i->op.code = UNBOX_FLOAT; write_i->op.arg = 0; write_i++; - type_propagate(UNBOX_FLOAT, oparg, starting_type_context, consts); + type_propagate(UNBOX_FLOAT, 0, starting_type_context, consts); + write_i->op.code = STORE_FAST_UNBOXED_BOXED; + write_i->op.arg = oparg; + write_i++; + type_propagate(STORE_FAST_UNBOXED_BOXED, + oparg, starting_type_context, consts); + write_i->op.code = LOAD_FAST_NO_INCREF; + write_i->op.arg = oparg; + write_i++; + type_propagate(LOAD_FAST_NO_INCREF, + oparg, starting_type_context, consts); continue; } opcode = specop = LOAD_FAST; diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index 11ecd8de10d44f..98ef0f8006d5b9 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -78,6 +78,11 @@ break; } + TARGET(POP_TOP_NO_DECREF) { + STACK_SHRINK(1); + break; + } + TARGET(PUSH_NULL) { STACK_GROW(1); TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); From 07a8d611f7c8c0f1095da8722807a54195a05e68 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 21 Mar 2023 16:15:22 +0800 Subject: [PATCH 082/280] Fix up some type annotations in DSL --- Python/bytecodes.c | 18 +++++++++--------- Python/tier2_typepropagator.c.h | 16 +++++++++------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index aedb50a0c3d6bc..5adac55e7e8399 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -205,7 +205,7 @@ dummy_func( }; - inst(BINARY_OP_MULTIPLY_INT, (unused/1, left, right -- prod: PyLong_Type)) { + inst(BINARY_OP_MULTIPLY_INT, (unused/1, left, right -- prod)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); @@ -216,7 +216,7 @@ dummy_func( ERROR_IF(prod == NULL, error); } - inst(BINARY_OP_MULTIPLY_FLOAT, (unused/1, left, right -- prod: PyFloat_Type)) { + inst(BINARY_OP_MULTIPLY_FLOAT, (unused/1, left, right -- prod)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); @@ -226,7 +226,7 @@ dummy_func( DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dprod, prod); } - inst(BINARY_OP_SUBTRACT_INT, (unused/1, left, right -- sub: PyLong_Type)) { + inst(BINARY_OP_SUBTRACT_INT, (unused/1, left, right -- sub)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); @@ -237,7 +237,7 @@ dummy_func( ERROR_IF(sub == NULL, error); } - inst(BINARY_OP_SUBTRACT_FLOAT, (unused/1, left, right -- sub: PyFloat_Type)) { + inst(BINARY_OP_SUBTRACT_FLOAT, (unused/1, left, right -- sub)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); @@ -246,7 +246,7 @@ dummy_func( DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsub, sub); } - inst(BINARY_OP_ADD_UNICODE, (unused/1, left, right -- res: PyUnicode_Type)) { + inst(BINARY_OP_ADD_UNICODE, (unused/1, left, right -- res)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); @@ -293,7 +293,7 @@ dummy_func( JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1); } - inst(BINARY_OP_ADD_FLOAT, (unused/1, left, right -- sum: PyFloat_Type)) { + inst(BINARY_OP_ADD_FLOAT, (unused/1, left, right -- sum)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); @@ -338,7 +338,7 @@ dummy_func( boxed_float = PyFloat_FromDouble(*(double *)(&(raw_float))); } - macro_inst(BINARY_OP_ADD_INT, (unused/1, left, right -- sum: PyLong_Type)) { + macro_inst(BINARY_OP_ADD_INT, (unused/1, left, right -- sum)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP); @@ -487,7 +487,7 @@ dummy_func( DISPATCH_INLINED(new_frame); } - inst(LIST_APPEND, (list, unused[oparg-1], v -- list, unused[oparg-1])) { + inst(LIST_APPEND, (list, unused[oparg-1], v -- list : PyList_Type, unused[oparg-1])) { ERROR_IF(_PyList_AppendTakeRef((PyListObject *)list, v) < 0, error); PREDICT(JUMP_BACKWARD); } @@ -1357,7 +1357,7 @@ dummy_func( DECREF_INPUTS(); } - inst(SET_UPDATE, (set, unused[oparg-1], iterable -- set, unused[oparg-1])) { + inst(SET_UPDATE, (set, unused[oparg-1], iterable -- set: PySet_Type, unused[oparg-1])) { int err = _PySet_Update(set, iterable); DECREF_INPUTS(); ERROR_IF(err < 0, error); diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index 98ef0f8006d5b9..f3620b6c6a9b4b 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -116,31 +116,31 @@ TARGET(BINARY_OP_MULTIPLY_INT) { STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyLong_Type), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(BINARY_OP_MULTIPLY_FLOAT) { STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(BINARY_OP_SUBTRACT_INT) { STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyLong_Type), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(BINARY_OP_SUBTRACT_FLOAT) { STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } TARGET(BINARY_OP_ADD_UNICODE) { STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyUnicode_Type), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } @@ -151,7 +151,7 @@ TARGET(BINARY_OP_ADD_FLOAT) { STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } @@ -186,7 +186,7 @@ TARGET(BINARY_OP_ADD_INT) { STACK_SHRINK(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyLong_Type), TYPESTACK_PEEK(1), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } @@ -244,6 +244,7 @@ TARGET(LIST_APPEND) { STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyList_Type), TYPESTACK_PEEK(1 + (oparg-1)), true); break; } @@ -528,6 +529,7 @@ TARGET(SET_UPDATE) { STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PySet_Type), TYPESTACK_PEEK(1 + (oparg-1)), true); break; } From 3143a1003202c9786def41638a5a2dee2fef8a20 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 22 Mar 2023 13:07:43 +0800 Subject: [PATCH 083/280] fix refleak in UNBOX_FLOAT --- Python/bytecodes.c | 1 + Python/generated_cases.c.h | 1 + 2 files changed, 2 insertions(+) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 5adac55e7e8399..68a69d62bcc9fe 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -331,6 +331,7 @@ dummy_func( inst(UNBOX_FLOAT, (boxed_float, unused[oparg] -- unboxed_float : PyRawFloat_Type, unused[oparg])) { double temp = ((PyFloatObject *)boxed_float)->ob_fval; + Py_DECREF(boxed_float); unboxed_float = (*(PyObject **)(&temp)); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 60d7460c8d4d81..30549b63597876 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -468,6 +468,7 @@ PyObject *boxed_float = stack_pointer[-(1 + oparg)]; PyObject *unboxed_float; double temp = ((PyFloatObject *)boxed_float)->ob_fval; + Py_DECREF(boxed_float); unboxed_float = (*(PyObject **)(&temp)); stack_pointer[-(1 + oparg)] = unboxed_float; DISPATCH(); From 1359271d0ed6ca4965fb795dd14ea3934481299e Mon Sep 17 00:00:00 2001 From: Jules <57632293+JuliaPoo@users.noreply.github.com> Date: Fri, 24 Mar 2023 00:26:27 +0800 Subject: [PATCH 084/280] Fix: Buggy pointer magic in copying type context (#27) * Fix: Buggy pointer magic in copying type context Added better debugging for type context * Refactor: Rename vars --- Python/tier2.c | 87 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 17 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index 10628e5720404b..fb04660cea3f05 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -113,12 +113,17 @@ _PyTier2TypeContext_Copy(const _PyTier2TypeContext *type_context) _Py_TYPENODE_t *parent = (_Py_TYPENODE_t *)_Py_TYPENODE_CLEAR_TAG(node); // Check if part of locals - if (parent - type_context->type_locals < nlocals) { - type_locals[i] = node - (uintptr_t)orig_type_locals + (uintptr_t)type_locals; + int offset_locals = (int)(parent - type_context->type_locals); + if (0 <= offset_locals && offset_locals < nlocals) { + type_locals[i] = _Py_TYPENODE_MAKE_REF((_Py_TYPENODE_t)(&type_locals[offset_locals])); } // Is part of stack else { - type_locals[i] = node - (uintptr_t)orig_type_stack + (uintptr_t)type_stack; +#if TYPEPROP_DEBUG + int offset_stack = (int)(parent - type_context->type_stack); + assert(0 <= offset_stack && offset_stack < nstack); +#endif + type_locals[i] = _Py_TYPENODE_MAKE_REF((_Py_TYPENODE_t)(&type_stack[offset_stack])); } break; } @@ -139,12 +144,17 @@ _PyTier2TypeContext_Copy(const _PyTier2TypeContext *type_context) _Py_TYPENODE_t *parent = (_Py_TYPENODE_t *)_Py_TYPENODE_CLEAR_TAG(node); // Check if part of locals - if (parent - type_context->type_locals < nlocals) { - type_stack[i] = node - (uintptr_t)orig_type_locals + (uintptr_t)type_locals; + int plocals = (int)(parent - type_context->type_locals); + if (0 <= plocals && plocals < nlocals) { + type_stack[i] = _Py_TYPENODE_MAKE_REF((_Py_TYPENODE_t)(&type_locals[plocals])); } // Is part of stack else { - type_stack[i] = node - (uintptr_t)orig_type_stack + (uintptr_t)type_stack; +#if TYPEPROP_DEBUG + int offset_stack = (int)(parent - type_context->type_stack); + assert(0 <= offset_stack && offset_stack < nstack); +#endif + type_stack[i] = _Py_TYPENODE_MAKE_REF((_Py_TYPENODE_t)(&type_stack[offset_stack])); } break; } @@ -394,23 +404,62 @@ print_typestack(const _PyTier2TypeContext *type_context) int nstack_use = (int)(type_stackptr - type_stack); int nstack = type_context->type_stack_len; + int nlocals = type_context->type_locals_len; + + int plocals = 0; + int pstack = 0; + bool is_local = false; + fprintf(stderr, " Stack: %p: [", type_stack); for (int i = 0; i < nstack; i++) { - PyTypeObject *type = typenode_get_type(type_stack[i]); - _Py_TYPENODE_t tag = _Py_TYPENODE_GET_TAG(type_stack[i]); - fprintf(stderr, "%s%s%s", + _Py_TYPENODE_t node = type_stack[i]; + PyTypeObject *type = typenode_get_type(node); + _Py_TYPENODE_t tag = _Py_TYPENODE_GET_TAG(node); + + if (tag == TYPE_REF) { + _Py_TYPENODE_t *parent = (_Py_TYPENODE_t *)(_Py_TYPENODE_CLEAR_TAG(node)); + plocals = (int)(parent - type_context->type_locals); + pstack = (int)(parent - type_context->type_stack); + is_local = (0 <= plocals) && (plocals < nlocals); + if (!is_local) { + assert((0 <= pstack) && (pstack < nstack)); + } + } + + fprintf(stderr, "%s%s", i == nstack_use ? "." : " ", - type == NULL ? "?" : type->tp_name, - tag == TYPE_REF ? "*" : ""); + type == NULL ? "?" : type->tp_name); + if (tag == TYPE_REF) { + fprintf(stderr, "%s%d]", + is_local ? "->locals[" : "->stack[", + is_local ? plocals : pstack); + } } fprintf(stderr, "]\n"); + fprintf(stderr, " Locals %p: [", type_locals); - for (int i = 0; i < type_context->type_locals_len; i++) { - PyTypeObject *type = typenode_get_type(type_locals[i]); - _Py_TYPENODE_t tag = _Py_TYPENODE_GET_TAG(type_locals[i]); - fprintf(stderr, "%s%s ", - type == NULL ? "?" : type->tp_name, - tag == TYPE_REF ? "*" : ""); + for (int i = 0; i < nlocals; i++) { + _Py_TYPENODE_t node = type_locals[i]; + PyTypeObject *type = typenode_get_type(node); + _Py_TYPENODE_t tag = _Py_TYPENODE_GET_TAG(node); + + if (tag == TYPE_REF) { + _Py_TYPENODE_t *parent = (_Py_TYPENODE_t *)(_Py_TYPENODE_CLEAR_TAG(node)); + plocals = (int)(parent - type_context->type_locals); + pstack = (int)(parent - type_context->type_stack); + is_local = (0 <= plocals) && (plocals < nlocals); + if (!is_local) { + assert((0 <= pstack) && (pstack < nstack)); + } + } + + fprintf(stderr, " %s", + type == NULL ? "?" : type->tp_name); + if (tag == TYPE_REF) { + fprintf(stderr, "%s%d]", + is_local ? "->locals[" : "->stack[", + is_local ? plocals : pstack); + } } fprintf(stderr, "]\n"); } @@ -1669,7 +1718,11 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) int deopt = _PyOpcode_Deopt[_Py_OPCODE(*curr_instr)]; if (IS_FORBIDDEN_OPCODE(deopt)) { #if BB_DEBUG +#ifdef Py_DEBUG + fprintf(stderr, "FORBIDDEN OPCODE %s\n", _PyOpcode_OpName[_Py_OPCODE(*curr_instr)]); +#else fprintf(stderr, "FORBIDDEN OPCODE %d\n", _Py_OPCODE(*curr_instr)); +#endif #endif return NULL; } From 80fa4ed0e408e9fda9d4aa04e4b47fdc1db5db0f Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Mon, 13 Mar 2023 15:56:24 +0000 Subject: [PATCH 085/280] gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives (#102631) --- Python/ceval.c | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 017f5e9aeb977e..e4b03e37c37805 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -13,7 +13,7 @@ #include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_moduleobject.h" // PyModuleObject #include "pycore_opcode.h" // EXTRA_CASES -#include "pycore_pyerrors.h" // _PyErr_Fetch(), _PyErr_GetRaisedException() +#include "pycore_pyerrors.h" // _PyErr_GetRaisedException() #include "pycore_pymem.h" // _PyMem_IsPtrFreed() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_range.h" // _PyRangeIterObject @@ -1791,18 +1791,15 @@ do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause) if (exc == NULL) { /* Reraise */ _PyErr_StackItem *exc_info = _PyErr_GetTopmostException(tstate); - value = exc_info->exc_value; - if (Py_IsNone(value) || value == NULL) { + exc = exc_info->exc_value; + if (Py_IsNone(exc) || exc == NULL) { _PyErr_SetString(tstate, PyExc_RuntimeError, "No active exception to reraise"); return 0; } - assert(PyExceptionInstance_Check(value)); - type = PyExceptionInstance_Class(value); - Py_XINCREF(type); - Py_XINCREF(value); - PyObject *tb = PyException_GetTraceback(value); /* new ref */ - _PyErr_Restore(tstate, type, value, tb); + Py_INCREF(exc); + assert(PyExceptionInstance_Check(exc)); + _PyErr_SetRaisedException(tstate, exc); return 1; } @@ -2043,28 +2040,27 @@ call_exc_trace(Py_tracefunc func, PyObject *self, PyThreadState *tstate, _PyInterpreterFrame *f) { - PyObject *type, *value, *traceback, *orig_traceback, *arg; - int err; - _PyErr_Fetch(tstate, &type, &value, &orig_traceback); - if (value == NULL) { - value = Py_NewRef(Py_None); + PyObject *exc = _PyErr_GetRaisedException(tstate); + assert(exc && PyExceptionInstance_Check(exc)); + PyObject *type = PyExceptionInstance_Class(exc); + PyObject *traceback = PyException_GetTraceback(exc); + if (traceback == NULL) { + traceback = Py_NewRef(Py_None); } - _PyErr_NormalizeException(tstate, &type, &value, &orig_traceback); - traceback = (orig_traceback != NULL) ? orig_traceback : Py_None; - arg = PyTuple_Pack(3, type, value, traceback); + PyObject *arg = PyTuple_Pack(3, type, exc, traceback); + Py_XDECREF(traceback); + if (arg == NULL) { - _PyErr_Restore(tstate, type, value, orig_traceback); + _PyErr_SetRaisedException(tstate, exc); return; } - err = call_trace(func, self, tstate, f, PyTrace_EXCEPTION, arg); + int err = call_trace(func, self, tstate, f, PyTrace_EXCEPTION, arg); Py_DECREF(arg); if (err == 0) { - _PyErr_Restore(tstate, type, value, orig_traceback); + _PyErr_SetRaisedException(tstate, exc); } else { - Py_XDECREF(type); - Py_XDECREF(value); - Py_XDECREF(orig_traceback); + Py_XDECREF(exc); } } From aaca52a4fc4ad2954d886735f46ec8091e8971b1 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Mon, 13 Mar 2023 15:59:20 +0000 Subject: [PATCH 086/280] gh-87092: refactor assemble() to a number of separate functions, which do not need the compiler struct (#102562) --- Lib/test/support/bytecode_helper.py | 2 +- Lib/test/test_peepholer.py | 43 ++- Python/compile.c | 534 +++++++++++++++------------- 3 files changed, 318 insertions(+), 261 deletions(-) diff --git a/Lib/test/support/bytecode_helper.py b/Lib/test/support/bytecode_helper.py index 190fe8723b1fb5..1d9b889c920986 100644 --- a/Lib/test/support/bytecode_helper.py +++ b/Lib/test/support/bytecode_helper.py @@ -125,7 +125,7 @@ def complete_insts_info(self, insts): assert isinstance(item, tuple) inst = list(reversed(item)) opcode = dis.opmap[inst.pop()] - oparg = inst.pop() if opcode in self.HAS_ARG_OR_TARGET else 0 + oparg = inst.pop() loc = inst + [-1] * (4 - len(inst)) res.append((opcode, oparg, *loc)) return res diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index aea234e38705a8..9ff017da53c2b1 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -995,15 +995,19 @@ def test_conditional_jump_forward_non_const_condition(self): ('LOAD_CONST', 2, 13), lbl, ('LOAD_CONST', 3, 14), + ('RETURN_VALUE', 14), ] - expected = [ + expected_insts = [ ('LOAD_NAME', 1, 11), ('POP_JUMP_IF_TRUE', lbl := self.Label(), 12), - ('LOAD_CONST', 2, 13), + ('LOAD_CONST', 1, 13), lbl, - ('LOAD_CONST', 3, 14) + ('RETURN_CONST', 2, 14), ] - self.cfg_optimization_test(insts, expected, consts=list(range(5))) + self.cfg_optimization_test(insts, + expected_insts, + consts=[0, 1, 2, 3, 4], + expected_consts=[0, 2, 3]) def test_conditional_jump_forward_const_condition(self): # The unreachable branch of the jump is removed, the jump @@ -1015,26 +1019,32 @@ def test_conditional_jump_forward_const_condition(self): ('LOAD_CONST', 2, 13), lbl, ('LOAD_CONST', 3, 14), + ('RETURN_VALUE', 14), ] - expected = [ - ('NOP', None, 11), - ('NOP', None, 12), - ('LOAD_CONST', 3, 14) + expected_insts = [ + ('NOP', 11), + ('NOP', 12), + ('RETURN_CONST', 1, 14), ] - self.cfg_optimization_test(insts, expected, consts=list(range(5))) + self.cfg_optimization_test(insts, + expected_insts, + consts=[0, 1, 2, 3, 4], + expected_consts=[0, 3]) def test_conditional_jump_backward_non_const_condition(self): insts = [ lbl1 := self.Label(), ('LOAD_NAME', 1, 11), ('POP_JUMP_IF_TRUE', lbl1, 12), - ('LOAD_CONST', 2, 13), + ('LOAD_NAME', 2, 13), + ('RETURN_VALUE', 13), ] expected = [ lbl := self.Label(), ('LOAD_NAME', 1, 11), ('POP_JUMP_IF_TRUE', lbl, 12), - ('LOAD_CONST', 2, 13) + ('LOAD_NAME', 2, 13), + ('RETURN_VALUE', 13), ] self.cfg_optimization_test(insts, expected, consts=list(range(5))) @@ -1042,16 +1052,17 @@ def test_conditional_jump_backward_const_condition(self): # The unreachable branch of the jump is removed insts = [ lbl1 := self.Label(), - ('LOAD_CONST', 1, 11), + ('LOAD_CONST', 3, 11), ('POP_JUMP_IF_TRUE', lbl1, 12), ('LOAD_CONST', 2, 13), + ('RETURN_VALUE', 13), ] - expected = [ + expected_insts = [ lbl := self.Label(), - ('NOP', None, 11), - ('JUMP', lbl, 12) + ('NOP', 11), + ('JUMP', lbl, 12), ] - self.cfg_optimization_test(insts, expected, consts=list(range(5))) + self.cfg_optimization_test(insts, expected_insts, consts=list(range(5))) if __name__ == "__main__": diff --git a/Python/compile.c b/Python/compile.c index 45c97b4f8ef0e6..29e55b8b30c56b 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -308,7 +308,7 @@ typedef struct basicblock_ { block, not to be confused with b_next, which is next by control flow. */ struct basicblock_ *b_list; /* The label of this block if it is a jump target, -1 otherwise */ - int b_label; + jump_target_label b_label; /* Exception stack at start of block, used by assembler to create the exception handling table */ ExceptStack *b_exceptstack; /* pointer to an array of instructions, initially NULL */ @@ -501,7 +501,7 @@ instr_sequence_next_inst(instr_sequence *seq) { static jump_target_label instr_sequence_new_label(instr_sequence *seq) { - jump_target_label lbl = {seq->s_next_free_label++}; + jump_target_label lbl = {++seq->s_next_free_label}; return lbl; } @@ -606,6 +606,14 @@ instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { instruction *instr = &seq->s_instrs[i]; RETURN_IF_ERROR(cfg_builder_addop(g, instr->i_opcode, instr->i_oparg, instr->i_loc)); } + int nblocks = 0; + for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) { + nblocks++; + } + if ((size_t)nblocks > SIZE_MAX / sizeof(basicblock *)) { + PyErr_NoMemory(); + return ERROR; + } return SUCCESS; } @@ -937,6 +945,7 @@ dictbytype(PyObject *src, int scope_type, int flag, Py_ssize_t offset) static bool cfg_builder_check(cfg_builder *g) { + assert(g->g_entryblock->b_iused > 0); for (basicblock *block = g->g_block_list; block != NULL; block = block->b_list) { assert(!_PyMem_IsPtrFreed(block)); if (block->b_instr != NULL) { @@ -1086,7 +1095,7 @@ cfg_builder_new_block(cfg_builder *g) /* Extend the singly linked list of blocks with new block. */ b->b_list = g->g_block_list; g->g_block_list = b; - b->b_label = -1; + b->b_label = NO_LABEL; return b; } @@ -1267,11 +1276,21 @@ basicblock_addop(basicblock *b, int opcode, int oparg, location loc) static bool cfg_builder_current_block_is_terminated(cfg_builder *g) { - if (IS_LABEL(g->g_current_label)) { + struct cfg_instr *last = basicblock_last_instr(g->g_curblock); + if (last && IS_TERMINATOR_OPCODE(last->i_opcode)) { return true; } - struct cfg_instr *last = basicblock_last_instr(g->g_curblock); - return last && IS_TERMINATOR_OPCODE(last->i_opcode); + if (IS_LABEL(g->g_current_label)) { + if (last || IS_LABEL(g->g_curblock->b_label)) { + return true; + } + else { + /* current block is empty, label it */ + g->g_curblock->b_label = g->g_current_label; + g->g_current_label = NO_LABEL; + } + } + return false; } static int @@ -1282,7 +1301,7 @@ cfg_builder_maybe_start_new_block(cfg_builder *g) if (b == NULL) { return ERROR; } - b->b_label = g->g_current_label.id; + b->b_label = g->g_current_label; g->g_current_label = NO_LABEL; cfg_builder_use_next_block(g, b); } @@ -1432,50 +1451,49 @@ merge_consts_recursive(PyObject *const_cache, PyObject *o) } static Py_ssize_t -compiler_add_const(struct compiler *c, PyObject *o) +compiler_add_const(PyObject *const_cache, struct compiler_unit *u, PyObject *o) { - PyObject *key = merge_consts_recursive(c->c_const_cache, o); + assert(PyDict_CheckExact(const_cache)); + PyObject *key = merge_consts_recursive(const_cache, o); if (key == NULL) { return ERROR; } - Py_ssize_t arg = dict_add_o(c->u->u_consts, key); + Py_ssize_t arg = dict_add_o(u->u_consts, key); Py_DECREF(key); return arg; } static int -compiler_addop_load_const(struct compiler *c, location loc, PyObject *o) +compiler_addop_load_const(PyObject *const_cache, struct compiler_unit *u, location loc, PyObject *o) { - Py_ssize_t arg = compiler_add_const(c, o); + Py_ssize_t arg = compiler_add_const(const_cache, u, o); if (arg < 0) { return ERROR; } - return codegen_addop_i(INSTR_SEQUENCE(c), LOAD_CONST, arg, loc); + return codegen_addop_i(&u->u_instr_sequence, LOAD_CONST, arg, loc); } static int -compiler_addop_o(struct compiler *c, location loc, +compiler_addop_o(struct compiler_unit *u, location loc, int opcode, PyObject *dict, PyObject *o) { Py_ssize_t arg = dict_add_o(dict, o); if (arg < 0) { return ERROR; } - return codegen_addop_i(INSTR_SEQUENCE(c), opcode, arg, loc); + return codegen_addop_i(&u->u_instr_sequence, opcode, arg, loc); } static int -compiler_addop_name(struct compiler *c, location loc, +compiler_addop_name(struct compiler_unit *u, location loc, int opcode, PyObject *dict, PyObject *o) { - Py_ssize_t arg; - - PyObject *mangled = _Py_Mangle(c->u->u_private, o); + PyObject *mangled = _Py_Mangle(u->u_private, o); if (!mangled) { return ERROR; } - arg = dict_add_o(dict, mangled); + Py_ssize_t arg = dict_add_o(dict, mangled); Py_DECREF(mangled); if (arg < 0) { return ERROR; @@ -1488,7 +1506,7 @@ compiler_addop_name(struct compiler *c, location loc, arg <<= 1; arg |= 1; } - return codegen_addop_i(INSTR_SEQUENCE(c), opcode, arg, loc); + return codegen_addop_i(&u->u_instr_sequence, opcode, arg, loc); } /* Add an opcode with an integer argument */ @@ -1509,7 +1527,7 @@ codegen_addop_i(instr_sequence *seq, int opcode, Py_ssize_t oparg, location loc) static int codegen_addop_j(instr_sequence *seq, location loc, - int opcode, jump_target_label target) + int opcode, jump_target_label target) { assert(IS_LABEL(target)); assert(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode)); @@ -1527,7 +1545,7 @@ codegen_addop_j(instr_sequence *seq, location loc, } #define ADDOP_LOAD_CONST(C, LOC, O) \ - RETURN_IF_ERROR(compiler_addop_load_const((C), (LOC), (O))) + RETURN_IF_ERROR(compiler_addop_load_const((C)->c_const_cache, (C)->u, (LOC), (O))) /* Same as ADDOP_LOAD_CONST, but steals a reference. */ #define ADDOP_LOAD_CONST_NEW(C, LOC, O) { \ @@ -1535,7 +1553,7 @@ codegen_addop_j(instr_sequence *seq, location loc, if (__new_const == NULL) { \ return ERROR; \ } \ - if (compiler_addop_load_const((C), (LOC), __new_const) < 0) { \ + if (compiler_addop_load_const((C)->c_const_cache, (C)->u, (LOC), __new_const) < 0) { \ Py_DECREF(__new_const); \ return ERROR; \ } \ @@ -1544,7 +1562,7 @@ codegen_addop_j(instr_sequence *seq, location loc, #define ADDOP_N(C, LOC, OP, O, TYPE) { \ assert(!HAS_CONST(OP)); /* use ADDOP_LOAD_CONST_NEW */ \ - if (compiler_addop_o((C), (LOC), (OP), (C)->u->u_ ## TYPE, (O)) < 0) { \ + if (compiler_addop_o((C)->u, (LOC), (OP), (C)->u->u_ ## TYPE, (O)) < 0) { \ Py_DECREF((O)); \ return ERROR; \ } \ @@ -1552,7 +1570,7 @@ codegen_addop_j(instr_sequence *seq, location loc, } #define ADDOP_NAME(C, LOC, OP, O, TYPE) \ - RETURN_IF_ERROR(compiler_addop_name((C), (LOC), (OP), (C)->u->u_ ## TYPE, (O))) + RETURN_IF_ERROR(compiler_addop_name((C)->u, (LOC), (OP), (C)->u->u_ ## TYPE, (O))) #define ADDOP_I(C, LOC, OP, O) \ RETURN_IF_ERROR(codegen_addop_i(INSTR_SEQUENCE(C), (OP), (O), (LOC))) @@ -2556,7 +2574,7 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) if (c->c_optimize < 2) { docstring = _PyAST_GetDocString(body); } - if (compiler_add_const(c, docstring ? docstring : Py_None) < 0) { + if (compiler_add_const(c->c_const_cache, c->u, docstring ? docstring : Py_None) < 0) { compiler_exit_scope(c); return ERROR; } @@ -2924,7 +2942,7 @@ compiler_lambda(struct compiler *c, expr_ty e) /* Make None the first constant, so the lambda can't have a docstring. */ - RETURN_IF_ERROR(compiler_add_const(c, Py_None)); + RETURN_IF_ERROR(compiler_add_const(c->c_const_cache, c->u, Py_None)); c->u->u_argcount = asdl_seq_LEN(args->args); c->u->u_posonlyargcount = asdl_seq_LEN(args->posonlyargs); @@ -4915,7 +4933,7 @@ compiler_call_simple_kw_helper(struct compiler *c, location loc, keyword_ty kw = asdl_seq_GET(keywords, i); PyTuple_SET_ITEM(names, i, Py_NewRef(kw->arg)); } - Py_ssize_t arg = compiler_add_const(c, names); + Py_ssize_t arg = compiler_add_const(c->c_const_cache, c->u, names); if (arg < 0) { return ERROR; } @@ -7372,7 +7390,7 @@ push_cold_blocks_to_end(cfg_builder *g, int code_flags) { if (explicit_jump == NULL) { return ERROR; } - basicblock_addop(explicit_jump, JUMP, b->b_next->b_label, NO_LOCATION); + basicblock_addop(explicit_jump, JUMP, b->b_next->b_label.id, NO_LOCATION); explicit_jump->b_cold = 1; explicit_jump->b_next = b->b_next; b->b_next = explicit_jump; @@ -7676,13 +7694,33 @@ assemble_emit_location(struct assembler* a, location loc, int isize) return write_location_info_entry(a, loc, isize); } -/* assemble_emit() +static int +assemble_location_info(struct assembler *a, basicblock *entryblock, int firstlineno) +{ + a->a_lineno = firstlineno; + location loc = NO_LOCATION; + int size = 0; + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + for (int j = 0; j < b->b_iused; j++) { + if (!same_location(loc, b->b_instr[j].i_loc)) { + RETURN_IF_ERROR(assemble_emit_location(a, loc, size)); + loc = b->b_instr[j].i_loc; + size = 0; + } + size += instr_size(&b->b_instr[j]); + } + } + RETURN_IF_ERROR(assemble_emit_location(a, loc, size)); + return SUCCESS; +} + +/* assemble_emit_instr() Extend the bytecode with a new instruction. Update lnotab if necessary. */ static int -assemble_emit(struct assembler *a, struct cfg_instr *i) +assemble_emit_instr(struct assembler *a, struct cfg_instr *i) { Py_ssize_t len = PyBytes_GET_SIZE(a->a_bytecode); _Py_CODEUNIT *code; @@ -7700,6 +7738,35 @@ assemble_emit(struct assembler *a, struct cfg_instr *i) return SUCCESS; } +static int merge_const_one(PyObject *const_cache, PyObject **obj); + +static int +assemble_emit(struct assembler *a, basicblock *entryblock, int first_lineno, + PyObject *const_cache) +{ + RETURN_IF_ERROR(assemble_init(a, first_lineno)); + + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + for (int j = 0; j < b->b_iused; j++) { + RETURN_IF_ERROR(assemble_emit_instr(a, &b->b_instr[j])); + } + } + + RETURN_IF_ERROR(assemble_location_info(a, entryblock, a->a_lineno)); + + RETURN_IF_ERROR(assemble_exception_table(a, entryblock)); + + RETURN_IF_ERROR(_PyBytes_Resize(&a->a_except_table, a->a_except_table_off)); + RETURN_IF_ERROR(merge_const_one(const_cache, &a->a_except_table)); + + RETURN_IF_ERROR(_PyBytes_Resize(&a->a_linetable, a->a_location_off)); + RETURN_IF_ERROR(merge_const_one(const_cache, &a->a_linetable)); + + RETURN_IF_ERROR(_PyBytes_Resize(&a->a_bytecode, a->a_offset * sizeof(_Py_CODEUNIT))); + RETURN_IF_ERROR(merge_const_one(const_cache, &a->a_bytecode)); + return SUCCESS; +} + static int normalize_jumps_in_block(cfg_builder *g, basicblock *b) { struct cfg_instr *last = basicblock_last_instr(b); @@ -7760,7 +7827,7 @@ normalize_jumps_in_block(cfg_builder *g, basicblock *b) { if (backwards_jump == NULL) { return ERROR; } - basicblock_addop(backwards_jump, JUMP, target->b_label, NO_LOCATION); + basicblock_addop(backwards_jump, JUMP, target->b_label.id, NO_LOCATION); backwards_jump->b_instr[0].i_target = target; last->i_opcode = reversed_opcode; last->i_target = b->b_next; @@ -7963,9 +8030,9 @@ fast_scan_many_locals(basicblock *entryblock, int nlocals) static int add_checks_for_loads_of_uninitialized_variables(basicblock *entryblock, - struct compiler *c) + int nlocals, + int nparams) { - int nlocals = (int)PyDict_GET_SIZE(c->u->u_varnames); if (nlocals == 0) { return SUCCESS; } @@ -7986,7 +8053,6 @@ add_checks_for_loads_of_uninitialized_variables(basicblock *entryblock, // First origin of being uninitialized: // The non-parameter locals in the entry block. - int nparams = (int)PyList_GET_SIZE(c->u->u_ste->ste_varnames); uint64_t start_mask = 0; for (int i = nparams; i < nlocals; i++) { start_mask |= (uint64_t)1 << i; @@ -8092,7 +8158,7 @@ compute_code_flags(struct compiler *c) static int merge_const_one(PyObject *const_cache, PyObject **obj) { - PyDict_CheckExact(const_cache); + assert(PyDict_CheckExact(const_cache)); PyObject *key = _PyCode_ConstantKey(*obj); if (key == NULL) { return ERROR; @@ -8122,29 +8188,29 @@ extern void _Py_set_localsplus_info(int, PyObject *, unsigned char, PyObject *, PyObject *); static void -compute_localsplus_info(struct compiler *c, int nlocalsplus, +compute_localsplus_info(struct compiler_unit *u, int nlocalsplus, PyObject *names, PyObject *kinds) { PyObject *k, *v; Py_ssize_t pos = 0; - while (PyDict_Next(c->u->u_varnames, &pos, &k, &v)) { + while (PyDict_Next(u->u_varnames, &pos, &k, &v)) { int offset = (int)PyLong_AS_LONG(v); assert(offset >= 0); assert(offset < nlocalsplus); // For now we do not distinguish arg kinds. _PyLocals_Kind kind = CO_FAST_LOCAL; - if (PyDict_GetItem(c->u->u_cellvars, k) != NULL) { + if (PyDict_GetItem(u->u_cellvars, k) != NULL) { kind |= CO_FAST_CELL; } _Py_set_localsplus_info(offset, k, kind, names, kinds); } - int nlocals = (int)PyDict_GET_SIZE(c->u->u_varnames); + int nlocals = (int)PyDict_GET_SIZE(u->u_varnames); // This counter mirrors the fix done in fix_cell_offsets(). int numdropped = 0; pos = 0; - while (PyDict_Next(c->u->u_cellvars, &pos, &k, &v)) { - if (PyDict_GetItem(c->u->u_varnames, k) != NULL) { + while (PyDict_Next(u->u_cellvars, &pos, &k, &v)) { + if (PyDict_GetItem(u->u_varnames, k) != NULL) { // Skip cells that are already covered by locals. numdropped += 1; continue; @@ -8157,7 +8223,7 @@ compute_localsplus_info(struct compiler *c, int nlocalsplus, } pos = 0; - while (PyDict_Next(c->u->u_freevars, &pos, &k, &v)) { + while (PyDict_Next(u->u_freevars, &pos, &k, &v)) { int offset = (int)PyLong_AS_LONG(v); assert(offset >= 0); offset += nlocals - numdropped; @@ -8167,19 +8233,20 @@ compute_localsplus_info(struct compiler *c, int nlocalsplus, } static PyCodeObject * -makecode(struct compiler *c, struct assembler *a, PyObject *constslist, - int maxdepth, int nlocalsplus, int code_flags) +makecode(struct compiler_unit *u, struct assembler *a, PyObject *const_cache, + PyObject *constslist, int maxdepth, int nlocalsplus, int code_flags, + PyObject *filename) { PyCodeObject *co = NULL; PyObject *names = NULL; PyObject *consts = NULL; PyObject *localsplusnames = NULL; PyObject *localspluskinds = NULL; - names = dict_keys_inorder(c->u->u_names, 0); + names = dict_keys_inorder(u->u_names, 0); if (!names) { goto error; } - if (merge_const_one(c->c_const_cache, &names) < 0) { + if (merge_const_one(const_cache, &names) < 0) { goto error; } @@ -8187,17 +8254,17 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist, if (consts == NULL) { goto error; } - if (merge_const_one(c->c_const_cache, &consts) < 0) { + if (merge_const_one(const_cache, &consts) < 0) { goto error; } - assert(c->u->u_posonlyargcount < INT_MAX); - assert(c->u->u_argcount < INT_MAX); - assert(c->u->u_kwonlyargcount < INT_MAX); - int posonlyargcount = (int)c->u->u_posonlyargcount; - int posorkwargcount = (int)c->u->u_argcount; + assert(u->u_posonlyargcount < INT_MAX); + assert(u->u_argcount < INT_MAX); + assert(u->u_kwonlyargcount < INT_MAX); + int posonlyargcount = (int)u->u_posonlyargcount; + int posorkwargcount = (int)u->u_argcount; assert(INT_MAX - posonlyargcount - posorkwargcount > 0); - int kwonlyargcount = (int)c->u->u_kwonlyargcount; + int kwonlyargcount = (int)u->u_kwonlyargcount; localsplusnames = PyTuple_New(nlocalsplus); if (localsplusnames == NULL) { @@ -8207,16 +8274,16 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist, if (localspluskinds == NULL) { goto error; } - compute_localsplus_info(c, nlocalsplus, localsplusnames, localspluskinds); + compute_localsplus_info(u, nlocalsplus, localsplusnames, localspluskinds); struct _PyCodeConstructor con = { - .filename = c->c_filename, - .name = c->u->u_name, - .qualname = c->u->u_qualname ? c->u->u_qualname : c->u->u_name, + .filename = filename, + .name = u->u_name, + .qualname = u->u_qualname ? u->u_qualname : u->u_name, .flags = code_flags, .code = a->a_bytecode, - .firstlineno = c->u->u_firstlineno, + .firstlineno = u->u_firstlineno, .linetable = a->a_linetable, .consts = consts, @@ -8238,7 +8305,7 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist, goto error; } - if (merge_const_one(c->c_const_cache, &localsplusnames) < 0) { + if (merge_const_one(const_cache, &localsplusnames) < 0) { goto error; } con.localsplusnames = localsplusnames; @@ -8289,7 +8356,7 @@ dump_basicblock(const basicblock *b) { const char *b_return = basicblock_returns(b) ? "return " : ""; fprintf(stderr, "%d: [EH=%d CLD=%d WRM=%d NO_FT=%d %p] used: %d, depth: %d, offset: %d %s\n", - b->b_label, b->b_except_handler, b->b_cold, b->b_warm, BB_NO_FALLTHROUGH(b), b, b->b_iused, + b->b_label.id, b->b_except_handler, b->b_cold, b->b_warm, BB_NO_FALLTHROUGH(b), b, b->b_iused, b->b_startdepth, b->b_offset, b_return); if (b->b_instr) { int i; @@ -8316,11 +8383,11 @@ static int duplicate_exits_without_lineno(cfg_builder *g); static int * -build_cellfixedoffsets(struct compiler *c) +build_cellfixedoffsets(struct compiler_unit *u) { - int nlocals = (int)PyDict_GET_SIZE(c->u->u_varnames); - int ncellvars = (int)PyDict_GET_SIZE(c->u->u_cellvars); - int nfreevars = (int)PyDict_GET_SIZE(c->u->u_freevars); + int nlocals = (int)PyDict_GET_SIZE(u->u_varnames); + int ncellvars = (int)PyDict_GET_SIZE(u->u_cellvars); + int nfreevars = (int)PyDict_GET_SIZE(u->u_freevars); int noffsets = ncellvars + nfreevars; int *fixed = PyMem_New(int, noffsets); @@ -8334,8 +8401,8 @@ build_cellfixedoffsets(struct compiler *c) PyObject *varname, *cellindex; Py_ssize_t pos = 0; - while (PyDict_Next(c->u->u_cellvars, &pos, &varname, &cellindex)) { - PyObject *varindex = PyDict_GetItem(c->u->u_varnames, varname); + while (PyDict_Next(u->u_cellvars, &pos, &varname, &cellindex)) { + PyObject *varindex = PyDict_GetItem(u->u_varnames, varname); if (varindex != NULL) { assert(PyLong_AS_LONG(cellindex) < INT_MAX); assert(PyLong_AS_LONG(varindex) < INT_MAX); @@ -8349,17 +8416,17 @@ build_cellfixedoffsets(struct compiler *c) } static int -insert_prefix_instructions(struct compiler *c, basicblock *entryblock, +insert_prefix_instructions(struct compiler_unit *u, basicblock *entryblock, int *fixed, int nfreevars, int code_flags) { - assert(c->u->u_firstlineno > 0); + assert(u->u_firstlineno > 0); /* Add the generator prefix instructions. */ if (code_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) { struct cfg_instr make_gen = { .i_opcode = RETURN_GENERATOR, .i_oparg = 0, - .i_loc = LOCATION(c->u->u_firstlineno, c->u->u_firstlineno, -1, -1), + .i_loc = LOCATION(u->u_firstlineno, u->u_firstlineno, -1, -1), .i_target = NULL, }; RETURN_IF_ERROR(insert_instruction(entryblock, 0, &make_gen)); @@ -8373,12 +8440,12 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock, } /* Set up cells for any variable that escapes, to be put in a closure. */ - const int ncellvars = (int)PyDict_GET_SIZE(c->u->u_cellvars); + const int ncellvars = (int)PyDict_GET_SIZE(u->u_cellvars); if (ncellvars) { - // c->u->u_cellvars has the cells out of order so we sort them + // u->u_cellvars has the cells out of order so we sort them // before adding the MAKE_CELL instructions. Note that we // adjust for arg cells, which come first. - const int nvars = ncellvars + (int)PyDict_GET_SIZE(c->u->u_varnames); + const int nvars = ncellvars + (int)PyDict_GET_SIZE(u->u_varnames); int *sorted = PyMem_RawCalloc(nvars, sizeof(int)); if (sorted == NULL) { PyErr_NoMemory(); @@ -8447,11 +8514,11 @@ guarantee_lineno_for_exits(basicblock *entryblock, int firstlineno) { } static int -fix_cell_offsets(struct compiler *c, basicblock *entryblock, int *fixedmap) +fix_cell_offsets(struct compiler_unit *u, basicblock *entryblock, int *fixedmap) { - int nlocals = (int)PyDict_GET_SIZE(c->u->u_varnames); - int ncellvars = (int)PyDict_GET_SIZE(c->u->u_cellvars); - int nfreevars = (int)PyDict_GET_SIZE(c->u->u_freevars); + int nlocals = (int)PyDict_GET_SIZE(u->u_varnames); + int ncellvars = (int)PyDict_GET_SIZE(u->u_cellvars); + int nfreevars = (int)PyDict_GET_SIZE(u->u_freevars); int noffsets = ncellvars + nfreevars; // First deal with duplicates (arg cells). @@ -8491,8 +8558,6 @@ fix_cell_offsets(struct compiler *c, basicblock *entryblock, int *fixedmap) return numdropped; } -static void -propagate_line_numbers(basicblock *entryblock); #ifndef NDEBUG @@ -8589,30 +8654,30 @@ remove_redundant_jumps(cfg_builder *g) { } static int -prepare_localsplus(struct compiler* c, cfg_builder *g, int code_flags) +prepare_localsplus(struct compiler_unit* u, cfg_builder *g, int code_flags) { - assert(PyDict_GET_SIZE(c->u->u_varnames) < INT_MAX); - assert(PyDict_GET_SIZE(c->u->u_cellvars) < INT_MAX); - assert(PyDict_GET_SIZE(c->u->u_freevars) < INT_MAX); - int nlocals = (int)PyDict_GET_SIZE(c->u->u_varnames); - int ncellvars = (int)PyDict_GET_SIZE(c->u->u_cellvars); - int nfreevars = (int)PyDict_GET_SIZE(c->u->u_freevars); + assert(PyDict_GET_SIZE(u->u_varnames) < INT_MAX); + assert(PyDict_GET_SIZE(u->u_cellvars) < INT_MAX); + assert(PyDict_GET_SIZE(u->u_freevars) < INT_MAX); + int nlocals = (int)PyDict_GET_SIZE(u->u_varnames); + int ncellvars = (int)PyDict_GET_SIZE(u->u_cellvars); + int nfreevars = (int)PyDict_GET_SIZE(u->u_freevars); assert(INT_MAX - nlocals - ncellvars > 0); assert(INT_MAX - nlocals - ncellvars - nfreevars > 0); int nlocalsplus = nlocals + ncellvars + nfreevars; - int* cellfixedoffsets = build_cellfixedoffsets(c); + int* cellfixedoffsets = build_cellfixedoffsets(u); if (cellfixedoffsets == NULL) { return ERROR; } // This must be called before fix_cell_offsets(). - if (insert_prefix_instructions(c, g->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) { + if (insert_prefix_instructions(u, g->g_entryblock, cellfixedoffsets, nfreevars, code_flags)) { PyMem_Free(cellfixedoffsets); return ERROR; } - int numdropped = fix_cell_offsets(c, g->g_entryblock, cellfixedoffsets); + int numdropped = fix_cell_offsets(u, g->g_entryblock, cellfixedoffsets); PyMem_Free(cellfixedoffsets); // At this point we're done with it. cellfixedoffsets = NULL; if (numdropped < 0) { @@ -8636,176 +8701,127 @@ add_return_at_end(struct compiler *c, int addNone) return SUCCESS; } -static PyCodeObject * -assemble(struct compiler *c, int addNone) -{ - PyCodeObject *co = NULL; - PyObject *consts = NULL; - cfg_builder g_; - cfg_builder *g = &g_; - struct assembler a; - memset(&a, 0, sizeof(struct assembler)); - - int code_flags = compute_code_flags(c); - if (code_flags < 0) { - return NULL; - } - - if (add_return_at_end(c, addNone) < 0) { - return NULL; - } - - /** Preprocessing **/ - if (instr_sequence_to_cfg(INSTR_SEQUENCE(c), g) < 0) { - goto error; - } - assert(cfg_builder_check(g)); - - int nblocks = 0; - for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) { - nblocks++; - } - if ((size_t)nblocks > SIZE_MAX / sizeof(basicblock *)) { - PyErr_NoMemory(); - goto error; - } +static void propagate_line_numbers(basicblock *entryblock); +static int +resolve_line_numbers(struct compiler_unit *u, cfg_builder *g) +{ /* Set firstlineno if it wasn't explicitly set. */ - if (!c->u->u_firstlineno) { + if (!u->u_firstlineno) { if (g->g_entryblock->b_instr && g->g_entryblock->b_instr->i_loc.lineno) { - c->u->u_firstlineno = g->g_entryblock->b_instr->i_loc.lineno; + u->u_firstlineno = g->g_entryblock->b_instr->i_loc.lineno; } else { - c->u->u_firstlineno = 1; + u->u_firstlineno = 1; } } + RETURN_IF_ERROR(duplicate_exits_without_lineno(g)); + propagate_line_numbers(g->g_entryblock); + guarantee_lineno_for_exits(g->g_entryblock, u->u_firstlineno); + return SUCCESS; +} +static int +optimize_code_unit(cfg_builder *g, PyObject *consts, PyObject *const_cache, + int code_flags, int nlocals, int nparams) +{ + assert(cfg_builder_check(g)); + /** Preprocessing **/ /* Map labels to targets and mark exception handlers */ - if (translate_jump_labels_to_targets(g->g_entryblock) < 0) { - goto error; - } - if (mark_except_handlers(g->g_entryblock) < 0) { - goto error; - } - if (label_exception_targets(g->g_entryblock)) { - goto error; - } + RETURN_IF_ERROR(translate_jump_labels_to_targets(g->g_entryblock)); + RETURN_IF_ERROR(mark_except_handlers(g->g_entryblock)); + RETURN_IF_ERROR(label_exception_targets(g->g_entryblock)); /** Optimization **/ - consts = consts_dict_keys_inorder(c->u->u_consts); + RETURN_IF_ERROR(optimize_cfg(g, consts, const_cache)); + RETURN_IF_ERROR(remove_unused_consts(g->g_entryblock, consts)); + RETURN_IF_ERROR( + add_checks_for_loads_of_uninitialized_variables( + g->g_entryblock, nlocals, nparams)); + + RETURN_IF_ERROR(push_cold_blocks_to_end(g, code_flags)); + return SUCCESS; +} + +static PyCodeObject * +assemble_code_unit(struct compiler_unit *u, PyObject *const_cache, + int code_flags, PyObject *filename) +{ + PyCodeObject *co = NULL; + PyObject *consts = consts_dict_keys_inorder(u->u_consts); if (consts == NULL) { goto error; } - if (optimize_cfg(g, consts, c->c_const_cache)) { - goto error; - } - if (remove_unused_consts(g->g_entryblock, consts) < 0) { + cfg_builder g; + if (instr_sequence_to_cfg(&u->u_instr_sequence, &g) < 0) { goto error; } - if (add_checks_for_loads_of_uninitialized_variables(g->g_entryblock, c) < 0) { + int nparams = (int)PyList_GET_SIZE(u->u_ste->ste_varnames); + int nlocals = (int)PyDict_GET_SIZE(u->u_varnames); + if (optimize_code_unit(&g, consts, const_cache, code_flags, nlocals, nparams) < 0) { goto error; } - /** line numbers (TODO: move this before optimization stage) */ - if (duplicate_exits_without_lineno(g) < 0) { - goto error; - } - propagate_line_numbers(g->g_entryblock); - guarantee_lineno_for_exits(g->g_entryblock, c->u->u_firstlineno); + /** Assembly **/ - if (push_cold_blocks_to_end(g, code_flags) < 0) { + if (resolve_line_numbers(u, &g) < 0) { goto error; } - /** Assembly **/ - - int nlocalsplus = prepare_localsplus(c, g, code_flags); + int nlocalsplus = prepare_localsplus(u, &g, code_flags); if (nlocalsplus < 0) { goto error; } - int maxdepth = stackdepth(g->g_entryblock, code_flags); + int maxdepth = stackdepth(g.g_entryblock, code_flags); if (maxdepth < 0) { goto error; } /* TO DO -- For 3.12, make sure that `maxdepth <= MAX_ALLOWED_STACK_USE` */ - convert_exception_handlers_to_nops(g->g_entryblock); + convert_exception_handlers_to_nops(g.g_entryblock); /* Order of basic blocks must have been determined by now */ - if (normalize_jumps(g) < 0) { + if (normalize_jumps(&g) < 0) { goto error; } - assert(no_redundant_jumps(g)); - assert(opcode_metadata_is_sane(g)); + assert(no_redundant_jumps(&g)); + assert(opcode_metadata_is_sane(&g)); /* Can't modify the bytecode after computing jump offsets. */ - assemble_jump_offsets(g->g_entryblock); + assemble_jump_offsets(g.g_entryblock); - /* Create assembler */ - if (assemble_init(&a, c->u->u_firstlineno) < 0) { - goto error; - } - - /* Emit code. */ - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - for (int j = 0; j < b->b_iused; j++) { - if (assemble_emit(&a, &b->b_instr[j]) < 0) { - goto error; - } - } + struct assembler a; + int res = assemble_emit(&a, g.g_entryblock, u->u_firstlineno, const_cache); + if (res == SUCCESS) { + co = makecode(u, &a, const_cache, consts, maxdepth, nlocalsplus, + code_flags, filename); } + assemble_free(&a); - /* Emit location info */ - a.a_lineno = c->u->u_firstlineno; - location loc = NO_LOCATION; - int size = 0; - for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - for (int j = 0; j < b->b_iused; j++) { - if (!same_location(loc, b->b_instr[j].i_loc)) { - if (assemble_emit_location(&a, loc, size)) { - goto error; - } - loc = b->b_instr[j].i_loc; - size = 0; - } - size += instr_size(&b->b_instr[j]); - } - } - if (assemble_emit_location(&a, loc, size)) { - goto error; - } + error: + Py_XDECREF(consts); + cfg_builder_fini(&g); + return co; +} - if (assemble_exception_table(&a, g->g_entryblock) < 0) { - goto error; - } - if (_PyBytes_Resize(&a.a_except_table, a.a_except_table_off) < 0) { - goto error; - } - if (merge_const_one(c->c_const_cache, &a.a_except_table) < 0) { - goto error; - } +static PyCodeObject * +assemble(struct compiler *c, int addNone) +{ + struct compiler_unit *u = c->u; + PyObject *const_cache = c->c_const_cache; + PyObject *filename = c->c_filename; - if (_PyBytes_Resize(&a.a_linetable, a.a_location_off) < 0) { - goto error; - } - if (merge_const_one(c->c_const_cache, &a.a_linetable) < 0) { - goto error; + int code_flags = compute_code_flags(c); + if (code_flags < 0) { + return NULL; } - if (_PyBytes_Resize(&a.a_bytecode, a.a_offset * sizeof(_Py_CODEUNIT)) < 0) { - goto error; - } - if (merge_const_one(c->c_const_cache, &a.a_bytecode) < 0) { - goto error; + if (add_return_at_end(c, addNone) < 0) { + return NULL; } - co = makecode(c, &a, consts, maxdepth, nlocalsplus, code_flags); - error: - Py_XDECREF(consts); - cfg_builder_fini(g); - assemble_free(&a); - return co; + return assemble_code_unit(u, const_cache, code_flags, filename); } static PyObject* @@ -9529,8 +9545,8 @@ translate_jump_labels_to_targets(basicblock *entryblock) { int max_label = -1; for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - if (b->b_label > max_label) { - max_label = b->b_label; + if (b->b_label.id > max_label) { + max_label = b->b_label.id; } } size_t mapsize = sizeof(basicblock *) * (max_label + 1); @@ -9541,8 +9557,8 @@ translate_jump_labels_to_targets(basicblock *entryblock) } memset(label2block, 0, mapsize); for (basicblock *b = entryblock; b != NULL; b = b->b_next) { - if (b->b_label >= 0) { - label2block[b->b_label] = b; + if (b->b_label.id >= 0) { + label2block[b->b_label.id] = b; } } for (basicblock *b = entryblock; b != NULL; b = b->b_next) { @@ -9554,7 +9570,7 @@ translate_jump_labels_to_targets(basicblock *entryblock) assert(lbl >= 0 && lbl <= max_label); instr->i_target = label2block[lbl]; assert(instr->i_target != NULL); - assert(instr->i_target->b_label == lbl); + assert(instr->i_target->b_label.id == lbl); } } } @@ -9828,9 +9844,15 @@ instructions_to_cfg(PyObject *instructions, cfg_builder *g) if (PyErr_Occurred()) { goto error; } - int oparg = PyLong_AsLong(PyTuple_GET_ITEM(item, 1)); - if (PyErr_Occurred()) { - goto error; + int oparg; + if (HAS_ARG(opcode)) { + oparg = PyLong_AsLong(PyTuple_GET_ITEM(item, 1)); + if (PyErr_Occurred()) { + goto error; + } + } + else { + oparg = 0; } location loc; loc.lineno = PyLong_AsLong(PyTuple_GET_ITEM(item, 2)); @@ -9851,7 +9873,10 @@ instructions_to_cfg(PyObject *instructions, cfg_builder *g) } RETURN_IF_ERROR(cfg_builder_addop(g, opcode, oparg, loc)); } - + struct cfg_instr *last = basicblock_last_instr(g->g_curblock); + if (last && !IS_TERMINATOR_OPCODE(last->i_opcode)) { + RETURN_IF_ERROR(cfg_builder_addop(g, RETURN_VALUE, 0, NO_LOCATION)); + } PyMem_Free(is_target); return SUCCESS; error: @@ -9859,6 +9884,38 @@ instructions_to_cfg(PyObject *instructions, cfg_builder *g) return ERROR; } +static PyObject * +instr_sequence_to_instructions(instr_sequence *seq) { + PyObject *instructions = PyList_New(0); + if (instructions == NULL) { + return NULL; + } + for (int i = 0; i < seq->s_used; i++) { + instruction *instr = &seq->s_instrs[i]; + location loc = instr->i_loc; + int arg = HAS_TARGET(instr->i_opcode) ? + seq->s_labelmap[instr->i_oparg] : instr->i_oparg; + + PyObject *inst_tuple = Py_BuildValue( + "(iiiiii)", instr->i_opcode, arg, + loc.lineno, loc.end_lineno, + loc.col_offset, loc.end_col_offset); + if (inst_tuple == NULL) { + goto error; + } + + int res = PyList_Append(instructions, inst_tuple); + Py_DECREF(inst_tuple); + if (res != 0) { + goto error; + } + } + return instructions; +error: + Py_XDECREF(instructions); + return NULL; +} + static PyObject * cfg_to_instructions(cfg_builder *g) { @@ -9868,7 +9925,7 @@ cfg_to_instructions(cfg_builder *g) } int lbl = 0; for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { - b->b_label = lbl; + b->b_label = (jump_target_label){lbl}; lbl += b->b_iused; } for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { @@ -9876,7 +9933,7 @@ cfg_to_instructions(cfg_builder *g) struct cfg_instr *instr = &b->b_instr[i]; location loc = instr->i_loc; int arg = HAS_TARGET(instr->i_opcode) ? - instr->i_target->b_label : instr->i_oparg; + instr->i_target->b_label.id : instr->i_oparg; PyObject *inst_tuple = Py_BuildValue( "(iiiiii)", instr->i_opcode, arg, @@ -9932,19 +9989,10 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags, goto finally; } - cfg_builder g; - if (instr_sequence_to_cfg(INSTR_SEQUENCE(c), &g) < 0) { - goto finally; - } - if (translate_jump_labels_to_targets(g.g_entryblock) < 0) { - goto finally; - } - - res = cfg_to_instructions(&g); + res = instr_sequence_to_instructions(INSTR_SEQUENCE(c)); finally: compiler_exit_scope(c); - cfg_builder_fini(&g); compiler_free(c); _PyArena_Free(arena); return res; @@ -9954,7 +10002,11 @@ PyObject * _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts) { PyObject *res = NULL; - PyObject *const_cache = NULL; + PyObject *const_cache = PyDict_New(); + if (const_cache == NULL) { + return NULL; + } + cfg_builder g; memset(&g, 0, sizeof(cfg_builder)); if (cfg_builder_init(&g) < 0) { @@ -9963,19 +10015,13 @@ _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts) if (instructions_to_cfg(instructions, &g) < 0) { goto error; } - const_cache = PyDict_New(); - if (const_cache == NULL) { - goto error; - } - if (translate_jump_labels_to_targets(g.g_entryblock) < 0) { - goto error; - } - if (optimize_cfg(&g, consts, const_cache) < 0) { + int code_flags = 0, nlocals = 0, nparams = 0; + if (optimize_code_unit(&g, consts, const_cache, code_flags, nlocals, nparams) < 0) { goto error; } res = cfg_to_instructions(&g); error: - Py_XDECREF(const_cache); + Py_DECREF(const_cache); cfg_builder_fini(&g); return res; } From 3985abda530a9f1527cf4a3910f5ce7001ada141 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 13 Mar 2023 18:35:37 +0000 Subject: [PATCH 087/280] GH-100987: Don't cache references to the names and consts array in `_PyEval_EvalFrameDefault`. (#102640) * Rename local variables, names and consts, from the interpeter loop. Will allow non-code objects in frames for better introspection of C builtins and extensions. * Remove unused dummy variables. --- Python/bytecodes.c | 42 +++++++++++++++++----------------- Python/ceval.c | 7 ------ Python/generated_cases.c.h | 46 +++++++++++++++++++------------------- 3 files changed, 43 insertions(+), 52 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 68a69d62bcc9fe..204f702588fa5c 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -70,8 +70,6 @@ dummy_func( unsigned int oparg, _Py_atomic_int * const eval_breaker, _PyCFrame cframe, - PyObject *names, - PyObject *consts, _Py_CODEUNIT *next_instr, PyObject **stack_pointer, PyObject *kwnames, @@ -627,7 +625,7 @@ dummy_func( } inst(RETURN_CONST, (--)) { - PyObject *retval = GETITEM(consts, oparg); + PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -917,7 +915,7 @@ dummy_func( } inst(STORE_NAME, (v -- )) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { @@ -935,7 +933,7 @@ dummy_func( } inst(DELETE_NAME, (--)) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { @@ -1029,7 +1027,7 @@ dummy_func( #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { assert(cframe.use_tracing == 0); - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); next_instr--; _Py_Specialize_StoreAttr(owner, next_instr, name); DISPATCH_SAME_OPARG(); @@ -1040,7 +1038,7 @@ dummy_func( #else (void)counter; // Unused. #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, v); Py_DECREF(v); Py_DECREF(owner); @@ -1048,21 +1046,21 @@ dummy_func( } inst(DELETE_ATTR, (owner --)) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); Py_DECREF(owner); ERROR_IF(err, error); } inst(STORE_GLOBAL, (v --)) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); Py_DECREF(v); ERROR_IF(err, error); } inst(DELETE_GLOBAL, (--)) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); // Can't use ERROR_IF here. @@ -1076,7 +1074,7 @@ dummy_func( } inst(LOAD_NAME, ( -- v)) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *locals = LOCALS(); if (locals == NULL) { _PyErr_Format(tstate, PyExc_SystemError, @@ -1147,7 +1145,7 @@ dummy_func( _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); - PyObject *name = GETITEM(names, oparg>>1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); next_instr--; _Py_Specialize_LoadGlobal(GLOBALS(), BUILTINS(), next_instr, name); DISPATCH_SAME_OPARG(); @@ -1155,7 +1153,7 @@ dummy_func( STAT_INC(LOAD_GLOBAL, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(names, oparg>>1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); if (PyDict_CheckExact(GLOBALS()) && PyDict_CheckExact(BUILTINS())) { @@ -1509,7 +1507,7 @@ dummy_func( _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); - PyObject *name = GETITEM(names, oparg>>1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); next_instr--; _Py_Specialize_LoadAttr(owner, next_instr, name); DISPATCH_SAME_OPARG(); @@ -1517,7 +1515,7 @@ dummy_func( STAT_INC(LOAD_ATTR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(names, oparg >> 1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 1); if (oparg & 1) { /* Designed to work in tandem with CALL, pushes two values. */ PyObject* meth = NULL; @@ -1598,7 +1596,7 @@ dummy_func( PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); DEOPT_IF(dict == NULL, LOAD_ATTR); assert(PyDict_CheckExact((PyObject *)dict)); - PyObject *name = GETITEM(names, oparg>>1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); uint16_t hint = index; DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, LOAD_ATTR); if (DK_IS_UNICODE(dict->ma_keys)) { @@ -1689,7 +1687,7 @@ dummy_func( DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); - PyObject *name = GETITEM(names, oparg >> 1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 1); Py_INCREF(f); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2); // Manipulate stack directly because we exit with DISPATCH_INLINED(). @@ -1734,7 +1732,7 @@ dummy_func( PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); DEOPT_IF(dict == NULL, STORE_ATTR); assert(PyDict_CheckExact((PyObject *)dict)); - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, STORE_ATTR); PyObject *old_value; uint64_t new_version; @@ -1928,14 +1926,14 @@ dummy_func( } inst(IMPORT_NAME, (level, fromlist -- res)) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); DECREF_INPUTS(); ERROR_IF(res == NULL, error); } inst(IMPORT_FROM, (from -- from, res)) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); ERROR_IF(res == NULL, error); } @@ -2588,8 +2586,8 @@ dummy_func( inst(KW_NAMES, (--)) { assert(kwnames == NULL); - assert(oparg < PyTuple_GET_SIZE(consts)); - kwnames = GETITEM(consts, oparg); + assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); + kwnames = GETITEM(frame->f_code->co_consts, oparg); } // Cache layout: counter/1, func_version/2, min_args/1 diff --git a/Python/ceval.c b/Python/ceval.c index e4b03e37c37805..9d7c6e058cf8e5 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -781,18 +781,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int /* Local "register" variables. * These are cached values from the frame and code object. */ - PyObject *names; - PyObject *consts; _Py_CODEUNIT *next_instr; PyObject **stack_pointer; /* Sets the above local variables from the frame */ #define SET_LOCALS_FROM_FRAME() \ - { \ - PyCodeObject *co = frame->f_code; \ - names = co->co_names; \ - consts = co->co_consts; \ - } \ assert(_PyInterpreterFrame_LASTI(frame) >= -1); \ /* Jump back to the last instruction executed... */ \ next_instr = frame->prev_instr + 1; \ diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 30549b63597876..e9af7acafd9a47 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -75,7 +75,7 @@ TARGET(LOAD_CONST) { PREDICTED(LOAD_CONST); PyObject *value; - value = GETITEM(consts, oparg); + value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); STACK_GROW(1); stack_pointer[-1] = value; @@ -149,7 +149,7 @@ oparg = (next_instr++)->op.arg; { PyObject *value; - value = GETITEM(consts, oparg); + value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); _tmp_1 = value; } @@ -198,7 +198,7 @@ PyObject *_tmp_2; { PyObject *value; - value = GETITEM(consts, oparg); + value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); _tmp_2 = value; } @@ -871,7 +871,7 @@ } TARGET(RETURN_CONST) { - PyObject *retval = GETITEM(consts, oparg); + PyObject *retval = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(retval); assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -1210,7 +1210,7 @@ TARGET(STORE_NAME) { PyObject *v = stack_pointer[-1]; - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { @@ -1230,7 +1230,7 @@ } TARGET(DELETE_NAME) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *ns = LOCALS(); int err; if (ns == NULL) { @@ -1344,7 +1344,7 @@ #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { assert(cframe.use_tracing == 0); - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); next_instr--; _Py_Specialize_StoreAttr(owner, next_instr, name); DISPATCH_SAME_OPARG(); @@ -1355,7 +1355,7 @@ #else (void)counter; // Unused. #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, v); Py_DECREF(v); Py_DECREF(owner); @@ -1367,7 +1367,7 @@ TARGET(DELETE_ATTR) { PyObject *owner = stack_pointer[-1]; - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); Py_DECREF(owner); if (err) goto pop_1_error; @@ -1377,7 +1377,7 @@ TARGET(STORE_GLOBAL) { PyObject *v = stack_pointer[-1]; - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); Py_DECREF(v); if (err) goto pop_1_error; @@ -1386,7 +1386,7 @@ } TARGET(DELETE_GLOBAL) { - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err; err = PyDict_DelItem(GLOBALS(), name); // Can't use ERROR_IF here. @@ -1402,7 +1402,7 @@ TARGET(LOAD_NAME) { PyObject *v; - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); PyObject *locals = LOCALS(); if (locals == NULL) { _PyErr_Format(tstate, PyExc_SystemError, @@ -1474,7 +1474,7 @@ _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); - PyObject *name = GETITEM(names, oparg>>1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); next_instr--; _Py_Specialize_LoadGlobal(GLOBALS(), BUILTINS(), next_instr, name); DISPATCH_SAME_OPARG(); @@ -1482,7 +1482,7 @@ STAT_INC(LOAD_GLOBAL, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(names, oparg>>1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); if (PyDict_CheckExact(GLOBALS()) && PyDict_CheckExact(BUILTINS())) { @@ -1924,7 +1924,7 @@ _PyAttrCache *cache = (_PyAttrCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); - PyObject *name = GETITEM(names, oparg>>1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); next_instr--; _Py_Specialize_LoadAttr(owner, next_instr, name); DISPATCH_SAME_OPARG(); @@ -1932,7 +1932,7 @@ STAT_INC(LOAD_ATTR, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - PyObject *name = GETITEM(names, oparg >> 1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 1); if (oparg & 1) { /* Designed to work in tandem with CALL, pushes two values. */ PyObject* meth = NULL; @@ -2043,7 +2043,7 @@ PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); DEOPT_IF(dict == NULL, LOAD_ATTR); assert(PyDict_CheckExact((PyObject *)dict)); - PyObject *name = GETITEM(names, oparg>>1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1); uint16_t hint = index; DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, LOAD_ATTR); if (DK_IS_UNICODE(dict->ma_keys)) { @@ -2167,7 +2167,7 @@ DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize), LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); - PyObject *name = GETITEM(names, oparg >> 1); + PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 1); Py_INCREF(f); _PyInterpreterFrame *new_frame = _PyFrame_PushUnchecked(tstate, f, 2); // Manipulate stack directly because we exit with DISPATCH_INLINED(). @@ -2223,7 +2223,7 @@ PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); DEOPT_IF(dict == NULL, STORE_ATTR); assert(PyDict_CheckExact((PyObject *)dict)); - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, STORE_ATTR); PyObject *old_value; uint64_t new_version; @@ -2476,7 +2476,7 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_name(tstate, frame, name, fromlist, level); Py_DECREF(level); Py_DECREF(fromlist); @@ -2489,7 +2489,7 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - PyObject *name = GETITEM(names, oparg); + PyObject *name = GETITEM(frame->f_code->co_names, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; STACK_GROW(1); @@ -3304,8 +3304,8 @@ TARGET(KW_NAMES) { assert(kwnames == NULL); - assert(oparg < PyTuple_GET_SIZE(consts)); - kwnames = GETITEM(consts, oparg); + assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts)); + kwnames = GETITEM(frame->f_code->co_consts, oparg); DISPATCH(); } From 58140884b0e9c627196b199ae1c81e4316b1890e Mon Sep 17 00:00:00 2001 From: chgnrdv <52372310+chgnrdv@users.noreply.github.com> Date: Mon, 13 Mar 2023 22:25:17 +0300 Subject: [PATCH 088/280] gh-102650: Remove duplicate include directives from multiple source files (#102651) Remove duplicate include directives from multiple source files --- Mac/Tools/pythonw.c | 1 - Modules/_hashopenssl.c | 3 +-- Modules/arraymodule.c | 1 - Modules/signalmodule.c | 4 +--- Programs/_testembed.c | 1 - 5 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Mac/Tools/pythonw.c b/Mac/Tools/pythonw.c index 78813e818e7dac..9dfb77f6ff41c3 100644 --- a/Mac/Tools/pythonw.c +++ b/Mac/Tools/pythonw.c @@ -27,7 +27,6 @@ #include #include #include -#include #include diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c index 82398547f9b372..ee8c588020118c 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -32,12 +32,11 @@ /* EVP is the preferred interface to hashing in OpenSSL */ #include #include -#include +#include // FIPS_mode() /* We use the object interface to discover what hashes OpenSSL supports. */ #include #include -#include // FIPS_mode() #ifndef OPENSSL_THREADS # error "OPENSSL_THREADS is not defined, Python requires thread-safe OpenSSL" diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 114c69a033593c..798a7629257966 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -13,7 +13,6 @@ #include "pycore_bytesobject.h" // _PyBytes_Repeat #include "structmember.h" // PyMemberDef #include // offsetof() -#include /*[clinic input] module array diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c index 0e472e1ee4f9dd..fdd1450050fa1b 100644 --- a/Modules/signalmodule.c +++ b/Modules/signalmodule.c @@ -13,7 +13,7 @@ #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_pyerrors.h" // _PyErr_SetString() #include "pycore_pystate.h" // _PyThreadState_GET() -#include "pycore_signal.h" +#include "pycore_signal.h" // Py_NSIG #ifndef MS_WINDOWS # include "posixmodule.h" @@ -28,8 +28,6 @@ # endif #endif -#include "pycore_signal.h" // Py_NSIG - #ifdef HAVE_SIGNAL_H # include #endif diff --git a/Programs/_testembed.c b/Programs/_testembed.c index a6ce3f7b200550..00717114b40286 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -9,7 +9,6 @@ #include "pycore_initconfig.h" // _PyConfig_InitCompatConfig() #include "pycore_runtime.h" // _PyRuntime #include "pycore_import.h" // _PyImport_FrozenBootstrap -#include #include #include #include // putenv() From c54eeaf03633e168dcfbdb7a9e8f2424603e6e43 Mon Sep 17 00:00:00 2001 From: T Date: Tue, 14 Mar 2023 04:46:35 +0800 Subject: [PATCH 089/280] gh-98169 dataclasses.astuple support DefaultDict (#98170) Co-authored-by: Pieter Eendebak --- Lib/dataclasses.py | 25 ++++++++++++------- Lib/test/test_dataclasses.py | 21 +++++++++++++--- ...2-10-10-19-14-51.gh-issue-98169.DBWIxL.rst | 2 ++ 3 files changed, 35 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-10-10-19-14-51.gh-issue-98169.DBWIxL.rst diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index f4617b1dbdac66..7c3285cf440a39 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1321,15 +1321,14 @@ def _asdict_inner(obj, dict_factory): # generator (which is not true for namedtuples, handled # above). return type(obj)(_asdict_inner(v, dict_factory) for v in obj) - elif isinstance(obj, dict) and hasattr(type(obj), 'default_factory'): - # obj is a defaultdict, which has a different constructor from - # dict as it requires the default_factory as its first arg. - # https://bugs.python.org/issue35540 - result = type(obj)(getattr(obj, 'default_factory')) - for k, v in obj.items(): - result[_asdict_inner(k, dict_factory)] = _asdict_inner(v, dict_factory) - return result elif isinstance(obj, dict): + if hasattr(type(obj), 'default_factory'): + # obj is a defaultdict, which has a different constructor from + # dict as it requires the default_factory as its first arg. + result = type(obj)(getattr(obj, 'default_factory')) + for k, v in obj.items(): + result[_asdict_inner(k, dict_factory)] = _asdict_inner(v, dict_factory) + return result return type(obj)((_asdict_inner(k, dict_factory), _asdict_inner(v, dict_factory)) for k, v in obj.items()) @@ -1382,7 +1381,15 @@ def _astuple_inner(obj, tuple_factory): # above). return type(obj)(_astuple_inner(v, tuple_factory) for v in obj) elif isinstance(obj, dict): - return type(obj)((_astuple_inner(k, tuple_factory), _astuple_inner(v, tuple_factory)) + obj_type = type(obj) + if hasattr(obj_type, 'default_factory'): + # obj is a defaultdict, which has a different constructor from + # dict as it requires the default_factory as its first arg. + result = obj_type(getattr(obj, 'default_factory')) + for k, v in obj.items(): + result[_astuple_inner(k, tuple_factory)] = _astuple_inner(v, tuple_factory) + return result + return obj_type((_astuple_inner(k, tuple_factory), _astuple_inner(v, tuple_factory)) for k, v in obj.items()) else: return copy.deepcopy(obj) diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 76bed0c3314673..46d4e0fedad2f2 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -1706,19 +1706,17 @@ class C: def test_helper_asdict_defaultdict(self): # Ensure asdict() does not throw exceptions when a # defaultdict is a member of a dataclass - @dataclass class C: mp: DefaultDict[str, List] - dd = defaultdict(list) dd["x"].append(12) c = C(mp=dd) d = asdict(c) - assert d == {"mp": {"x": [12]}} - assert d["mp"] is not c.mp # make sure defaultdict is copied + self.assertEqual(d, {"mp": {"x": [12]}}) + self.assertTrue(d["mp"] is not c.mp) # make sure defaultdict is copied def test_helper_astuple(self): # Basic tests for astuple(), it should return a new tuple. @@ -1847,6 +1845,21 @@ class C: t = astuple(c, tuple_factory=list) self.assertEqual(t, ['outer', T(1, ['inner', T(11, 12, 13)], 2)]) + def test_helper_astuple_defaultdict(self): + # Ensure astuple() does not throw exceptions when a + # defaultdict is a member of a dataclass + @dataclass + class C: + mp: DefaultDict[str, List] + + dd = defaultdict(list) + dd["x"].append(12) + c = C(mp=dd) + t = astuple(c) + + self.assertEqual(t, ({"x": [12]},)) + self.assertTrue(t[0] is not dd) # make sure defaultdict is copied + def test_dynamic_class_creation(self): cls_dict = {'__annotations__': {'x': int, 'y': int}, } diff --git a/Misc/NEWS.d/next/Library/2022-10-10-19-14-51.gh-issue-98169.DBWIxL.rst b/Misc/NEWS.d/next/Library/2022-10-10-19-14-51.gh-issue-98169.DBWIxL.rst new file mode 100644 index 00000000000000..24c3aeecc83f18 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-10-19-14-51.gh-issue-98169.DBWIxL.rst @@ -0,0 +1,2 @@ +Fix :func:`dataclasses.astuple` crash when :class:`collections.defaultdict` +is present in the attributes. From 98b34ba69d383857943aa6fc57cd5cef05aa2590 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Tue, 14 Mar 2023 00:42:05 +0300 Subject: [PATCH 090/280] gh-102069: Fix `__weakref__` descriptor generation for custom dataclasses (#102075) --- Lib/dataclasses.py | 3 +++ Lib/test/test_dataclasses.py | 15 +++++++++++---- ...2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst | 1 + 3 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 7c3285cf440a39..82b08fc017884f 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1189,6 +1189,9 @@ def _add_slots(cls, is_frozen, weakref_slot): # Remove __dict__ itself. cls_dict.pop('__dict__', None) + # Clear existing `__weakref__` descriptor, it belongs to a previous type: + cls_dict.pop('__weakref__', None) # gh-102069 + # And finally create the class. qualname = getattr(cls, '__qualname__', None) cls = type(cls)(cls.__name__, cls.__bases__, cls_dict) diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 46d4e0fedad2f2..46f33043c27071 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -3175,6 +3175,8 @@ class A: with self.assertRaisesRegex(TypeError, "cannot create weak reference"): weakref.ref(a) + with self.assertRaises(AttributeError): + a.__weakref__ def test_slots_weakref(self): @dataclass(slots=True, weakref_slot=True) @@ -3183,7 +3185,9 @@ class A: self.assertIn("__weakref__", A.__slots__) a = A(1) - weakref.ref(a) + a_ref = weakref.ref(a) + + self.assertIs(a.__weakref__, a_ref) def test_slots_weakref_base_str(self): class Base: @@ -3249,7 +3253,8 @@ class A(Base): self.assertIn("__weakref__", Base.__slots__) self.assertNotIn("__weakref__", A.__slots__) a = A(1) - weakref.ref(a) + a_ref = weakref.ref(a) + self.assertIs(a.__weakref__, a_ref) def test_weakref_slot_subclass_no_weakref_slot(self): @dataclass(slots=True, weakref_slot=True) @@ -3265,7 +3270,8 @@ class A(Base): self.assertIn("__weakref__", Base.__slots__) self.assertNotIn("__weakref__", A.__slots__) a = A(1) - weakref.ref(a) + a_ref = weakref.ref(a) + self.assertIs(a.__weakref__, a_ref) def test_weakref_slot_normal_base_weakref_slot(self): class Base: @@ -3280,7 +3286,8 @@ class A(Base): self.assertIn("__weakref__", Base.__slots__) self.assertNotIn("__weakref__", A.__slots__) a = A(1) - weakref.ref(a) + a_ref = weakref.ref(a) + self.assertIs(a.__weakref__, a_ref) class TestDescriptors(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst b/Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst new file mode 100644 index 00000000000000..04c87e515cca93 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-20-16-47-56.gh-issue-102069.FS7f1j.rst @@ -0,0 +1 @@ +Fix ``__weakref__`` descriptor generation for custom dataclasses. From 762e0245162157452d5095451fad56a23d763163 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 13 Mar 2023 15:50:16 -0600 Subject: [PATCH 091/280] gh-101524: Fix the ChannelID tp_name (gh-102655) https://github.com/python/cpython/issues/101524 --- Modules/_xxinterpchannelsmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_xxinterpchannelsmodule.c b/Modules/_xxinterpchannelsmodule.c index a0cd4a2363fb53..fead12c963da26 100644 --- a/Modules/_xxinterpchannelsmodule.c +++ b/Modules/_xxinterpchannelsmodule.c @@ -1806,7 +1806,7 @@ static PyType_Slot ChannelIDType_slots[] = { }; static PyType_Spec ChannelIDType_spec = { - .name = "_xxsubinterpreters.ChannelID", + .name = MODULE_NAME ".ChannelID", .basicsize = sizeof(channelid), .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE), From 75153c13d0cabbfa75e70ab594e66146ccad9b6e Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 13 Mar 2023 16:01:44 -0600 Subject: [PATCH 092/280] gh-101659: Avoid Allocation for Shared Exceptions in the _xxsubinterpreters Module (gh-102659) https://github.com/python/cpython/issues/101659 --- Modules/_xxsubinterpretersmodule.c | 123 ++++++++++++----------------- 1 file changed, 49 insertions(+), 74 deletions(-) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 79dbe3474ba9e8..76fb87fa3a34e1 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -15,14 +15,14 @@ #define MODULE_NAME "_xxsubinterpreters" -static char * +static const char * _copy_raw_string(PyObject *strobj) { const char *str = PyUnicode_AsUTF8(strobj); if (str == NULL) { return NULL; } - char *copied = PyMem_Malloc(strlen(str)+1); + char *copied = PyMem_RawMalloc(strlen(str)+1); if (copied == NULL) { PyErr_NoMemory(); return NULL; @@ -128,7 +128,7 @@ clear_module_state(module_state *state) /* data-sharing-specific code ***********************************************/ struct _sharednsitem { - char *name; + const char *name; _PyCrossInterpreterData data; }; @@ -152,7 +152,7 @@ static void _sharednsitem_clear(struct _sharednsitem *item) { if (item->name != NULL) { - PyMem_Free(item->name); + PyMem_RawFree((void *)item->name); item->name = NULL; } (void)_release_xid_data(&item->data, 1); @@ -258,96 +258,74 @@ _sharedns_apply(_sharedns *shared, PyObject *ns) // of the exception in the calling interpreter. typedef struct _sharedexception { - char *name; - char *msg; + const char *name; + const char *msg; } _sharedexception; -static _sharedexception * -_sharedexception_new(void) -{ - _sharedexception *err = PyMem_NEW(_sharedexception, 1); - if (err == NULL) { - PyErr_NoMemory(); - return NULL; - } - err->name = NULL; - err->msg = NULL; - return err; -} +static const struct _sharedexception no_exception = { + .name = NULL, + .msg = NULL, +}; static void _sharedexception_clear(_sharedexception *exc) { if (exc->name != NULL) { - PyMem_Free(exc->name); + PyMem_RawFree((void *)exc->name); } if (exc->msg != NULL) { - PyMem_Free(exc->msg); + PyMem_RawFree((void *)exc->msg); } } -static void -_sharedexception_free(_sharedexception *exc) -{ - _sharedexception_clear(exc); - PyMem_Free(exc); -} - -static _sharedexception * -_sharedexception_bind(PyObject *exc) +static const char * +_sharedexception_bind(PyObject *exc, _sharedexception *sharedexc) { assert(exc != NULL); - char *failure = NULL; - - _sharedexception *err = _sharedexception_new(); - if (err == NULL) { - goto finally; - } + const char *failure = NULL; - PyObject *name = PyUnicode_FromFormat("%S", Py_TYPE(exc)); - if (name == NULL) { + PyObject *nameobj = PyUnicode_FromFormat("%S", Py_TYPE(exc)); + if (nameobj == NULL) { failure = "unable to format exception type name"; - goto finally; + goto error; } - err->name = _copy_raw_string(name); - Py_DECREF(name); - if (err->name == NULL) { + sharedexc->name = _copy_raw_string(nameobj); + Py_DECREF(nameobj); + if (sharedexc->name == NULL) { if (PyErr_ExceptionMatches(PyExc_MemoryError)) { failure = "out of memory copying exception type name"; } else { failure = "unable to encode and copy exception type name"; } - goto finally; + goto error; } if (exc != NULL) { - PyObject *msg = PyUnicode_FromFormat("%S", exc); - if (msg == NULL) { + PyObject *msgobj = PyUnicode_FromFormat("%S", exc); + if (msgobj == NULL) { failure = "unable to format exception message"; - goto finally; + goto error; } - err->msg = _copy_raw_string(msg); - Py_DECREF(msg); - if (err->msg == NULL) { + sharedexc->msg = _copy_raw_string(msgobj); + Py_DECREF(msgobj); + if (sharedexc->msg == NULL) { if (PyErr_ExceptionMatches(PyExc_MemoryError)) { failure = "out of memory copying exception message"; } else { failure = "unable to encode and copy exception message"; } - goto finally; + goto error; } } -finally: - if (failure != NULL) { - PyErr_Clear(); - if (err->name != NULL) { - PyMem_Free(err->name); - err->name = NULL; - } - err->msg = failure; - } - return err; + return NULL; + +error: + assert(failure != NULL); + PyErr_Clear(); + _sharedexception_clear(sharedexc); + *sharedexc = no_exception; + return failure; } static void @@ -430,7 +408,7 @@ _ensure_not_running(PyInterpreterState *interp) static int _run_script(PyInterpreterState *interp, const char *codestr, - _sharedns *shared, _sharedexception **exc) + _sharedns *shared, _sharedexception *sharedexc) { PyObject *excval = NULL; PyObject *main_mod = _PyInterpreterState_GetMainModule(interp); @@ -462,22 +440,20 @@ _run_script(PyInterpreterState *interp, const char *codestr, Py_DECREF(result); // We throw away the result. } - *exc = NULL; + *sharedexc = no_exception; return 0; error: excval = PyErr_GetRaisedException(); - _sharedexception *sharedexc = _sharedexception_bind(excval); - Py_XDECREF(excval); - if (sharedexc == NULL) { - fprintf(stderr, "RunFailedError: script raised an uncaught exception"); + const char *failure = _sharedexception_bind(excval, sharedexc); + if (failure != NULL) { + fprintf(stderr, + "RunFailedError: script raised an uncaught exception (%s)", + failure); PyErr_Clear(); - sharedexc = NULL; - } - else { - assert(!PyErr_Occurred()); } - *exc = sharedexc; + Py_XDECREF(excval); + assert(!PyErr_Occurred()); return -1; } @@ -505,7 +481,7 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp, } // Run the script. - _sharedexception *exc = NULL; + _sharedexception exc; int result = _run_script(interp, codestr, shared, &exc); // Switch back. @@ -514,10 +490,9 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp, } // Propagate any exception out to the caller. - if (exc != NULL) { + if (exc.name != NULL) { assert(state != NULL); - _sharedexception_apply(exc, state->RunFailedError); - _sharedexception_free(exc); + _sharedexception_apply(&exc, state->RunFailedError); } else if (result != 0) { // We were unable to allocate a shared exception. From b99132da13c2f7838877a1677b385838a0e86420 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 13 Mar 2023 15:08:45 -0700 Subject: [PATCH 093/280] gh-98831: Use DECREF_INPUTS() more (#102409) --- Python/bytecodes.c | 80 +++++++++++++++----------------------- Python/generated_cases.c.h | 15 ++++--- 2 files changed, 38 insertions(+), 57 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 204f702588fa5c..4cac5857a2cf42 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -457,8 +457,7 @@ dummy_func( if (!_PyErr_Occurred(tstate)) { _PyErr_SetKeyError(sub); } - Py_DECREF(dict); - Py_DECREF(sub); + DECREF_INPUTS(); ERROR_IF(true, error); } Py_INCREF(res); // Do this before DECREF'ing dict, sub @@ -493,7 +492,7 @@ dummy_func( inst(SET_ADD, (set, unused[oparg-1], v -- set, unused[oparg-1])) { int err = PySet_Add(set, v); - Py_DECREF(v); + DECREF_INPUTS(); ERROR_IF(err, error); PREDICT(JUMP_BACKWARD); } @@ -972,7 +971,7 @@ dummy_func( #endif /* ENABLE_SPECIALIZATION */ PyObject **top = stack_pointer + oparg - 1; int res = unpack_iterable(tstate, seq, oparg, -1, top); - Py_DECREF(seq); + DECREF_INPUTS(); ERROR_IF(res == 0, error); } @@ -983,7 +982,7 @@ dummy_func( STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - Py_DECREF(seq); + DECREF_INPUTS(); } inst(UNPACK_SEQUENCE_TUPLE, (unused/1, seq -- values[oparg])) { @@ -994,7 +993,7 @@ dummy_func( for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - Py_DECREF(seq); + DECREF_INPUTS(); } inst(UNPACK_SEQUENCE_LIST, (unused/1, seq -- values[oparg])) { @@ -1005,14 +1004,14 @@ dummy_func( for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - Py_DECREF(seq); + DECREF_INPUTS(); } inst(UNPACK_EX, (seq -- unused[oparg & 0xFF], unused, unused[oparg >> 8])) { int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); - Py_DECREF(seq); + DECREF_INPUTS(); ERROR_IF(res == 0, error); } @@ -1040,22 +1039,21 @@ dummy_func( #endif /* ENABLE_SPECIALIZATION */ PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, v); - Py_DECREF(v); - Py_DECREF(owner); + DECREF_INPUTS(); ERROR_IF(err, error); } inst(DELETE_ATTR, (owner --)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - Py_DECREF(owner); + DECREF_INPUTS(); ERROR_IF(err, error); } inst(STORE_GLOBAL, (v --)) { PyObject *name = GETITEM(frame->f_code->co_names, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - Py_DECREF(v); + DECREF_INPUTS(); ERROR_IF(err, error); } @@ -1322,9 +1320,7 @@ dummy_func( inst(BUILD_STRING, (pieces[oparg] -- str: PyUnicode_Type)) { str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - for (int i = 0; i < oparg; i++) { - Py_DECREF(pieces[i]); - } + DECREF_INPUTS(); ERROR_IF(str == NULL, error); } @@ -1387,10 +1383,7 @@ dummy_func( if (map == NULL) goto error; - for (int i = 0; i < oparg; i++) { - Py_DECREF(values[i*2]); - Py_DECREF(values[i*2+1]); - } + DECREF_INPUTS(); ERROR_IF(map == NULL, error); } @@ -1446,10 +1439,7 @@ dummy_func( map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - Py_DECREF(keys); - for (int i = 0; i < oparg; i++) { - Py_DECREF(values[i]); - } + DECREF_INPUTS(); ERROR_IF(map == NULL, error); } @@ -1537,7 +1527,7 @@ dummy_func( NULL | meth | arg1 | ... | argN */ - Py_DECREF(owner); + DECREF_INPUTS(); ERROR_IF(meth == NULL, error); res2 = NULL; res = meth; @@ -1546,7 +1536,7 @@ dummy_func( else { /* Classic, pushes one value. */ res = PyObject_GetAttr(owner, name); - Py_DECREF(owner); + DECREF_INPUTS(); ERROR_IF(res == NULL, error); } } @@ -1565,7 +1555,7 @@ dummy_func( STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - Py_DECREF(owner); + DECREF_INPUTS(); } inst(LOAD_ATTR_MODULE, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { @@ -1582,7 +1572,7 @@ dummy_func( STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - Py_DECREF(owner); + DECREF_INPUTS(); } inst(LOAD_ATTR_WITH_HINT, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { @@ -1613,7 +1603,7 @@ dummy_func( STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - Py_DECREF(owner); + DECREF_INPUTS(); } inst(LOAD_ATTR_SLOT, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) { @@ -1627,7 +1617,7 @@ dummy_func( STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - Py_DECREF(owner); + DECREF_INPUTS(); } inst(LOAD_ATTR_CLASS, (unused/1, type_version/2, unused/2, descr/4, cls -- res2 if (oparg & 1), res)) { @@ -1643,7 +1633,7 @@ dummy_func( res = descr; assert(res != NULL); Py_INCREF(res); - Py_DECREF(cls); + DECREF_INPUTS(); } inst(LOAD_ATTR_PROPERTY, (unused/1, type_version/2, func_version/2, fget/4, owner -- unused if (oparg & 1), unused)) { @@ -1780,8 +1770,7 @@ dummy_func( STAT_INC(COMPARE_OP, deferred); assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - Py_DECREF(left); - Py_DECREF(right); + DECREF_INPUTS(); ERROR_IF(res == NULL, error); } @@ -1807,8 +1796,7 @@ dummy_func( #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); PyObject *cond = PyObject_RichCompare(left, right, oparg>>4); - Py_DECREF(left); - Py_DECREF(right); + DECREF_INPUTS(); ERROR_IF(cond == NULL, error); assert(next_instr[1].op.code == POP_JUMP_IF_FALSE || next_instr[1].op.code == POP_JUMP_IF_TRUE); @@ -1963,7 +1951,7 @@ dummy_func( } else { int err = PyObject_IsTrue(cond); - Py_DECREF(cond); + DECREF_INPUTS(); if (err == 0) { JUMPBY(oparg); } @@ -2004,7 +1992,7 @@ dummy_func( } else { int err = PyObject_IsTrue(cond); - Py_DECREF(cond); + DECREF_INPUTS(); if (err > 0) { JUMPBY(oparg); } @@ -2038,7 +2026,7 @@ dummy_func( inst(POP_JUMP_IF_NOT_NONE, (value -- )) { if (!Py_IsNone(value)) { - Py_DECREF(value); + DECREF_INPUTS(); JUMPBY(oparg); } else { @@ -2063,7 +2051,7 @@ dummy_func( JUMPBY(oparg); } else { - Py_DECREF(value); + DECREF_INPUTS(); } } @@ -2270,7 +2258,7 @@ dummy_func( if (iter == NULL) { goto error; } - Py_DECREF(iterable); + DECREF_INPUTS(); } PREDICT(LOAD_CONST); } @@ -3168,9 +3156,7 @@ dummy_func( assert(PyTuple_CheckExact(callargs)); result = do_call_core(tstate, func, callargs, kwargs, cframe.use_tracing); - Py_DECREF(func); - Py_DECREF(callargs); - Py_XDECREF(kwargs); + DECREF_INPUTS(); assert(PEEK(3 + (oparg & 1)) == NULL); ERROR_IF(result == NULL, error); @@ -3237,9 +3223,7 @@ dummy_func( inst(BUILD_SLICE, (start, stop, step if (oparg == 3) -- slice)) { slice = PySlice_New(start, stop, step); - Py_DECREF(start); - Py_DECREF(stop); - Py_XDECREF(step); + DECREF_INPUTS(); ERROR_IF(slice == NULL, error); } @@ -3285,8 +3269,7 @@ dummy_func( } else { /* Actually call format(). */ result = PyObject_Format(value, fmt_spec); - Py_DECREF(value); - Py_XDECREF(fmt_spec); + DECREF_INPUTS(); ERROR_IF(result == NULL, error); } } @@ -3312,8 +3295,7 @@ dummy_func( assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - Py_DECREF(lhs); - Py_DECREF(rhs); + DECREF_INPUTS(); ERROR_IF(res == NULL, error); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index e9af7acafd9a47..2f5726c317eb1b 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1695,8 +1695,8 @@ PyObject **pieces = (stack_pointer - oparg); PyObject *str; str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - for (int i = 0; i < oparg; i++) { - Py_DECREF(pieces[i]); + for (int _i = oparg; --_i >= 0;) { + Py_DECREF(pieces[_i]); } if (str == NULL) { STACK_SHRINK(oparg); goto error; } STACK_SHRINK(oparg); @@ -1792,9 +1792,8 @@ if (map == NULL) goto error; - for (int i = 0; i < oparg; i++) { - Py_DECREF(values[i*2]); - Py_DECREF(values[i*2+1]); + for (int _i = oparg*2; --_i >= 0;) { + Py_DECREF(values[_i]); } if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } STACK_SHRINK(oparg*2); @@ -1859,10 +1858,10 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - Py_DECREF(keys); - for (int i = 0; i < oparg; i++) { - Py_DECREF(values[i]); + for (int _i = oparg; --_i >= 0;) { + Py_DECREF(values[_i]); } + Py_DECREF(keys); if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } STACK_SHRINK(oparg); stack_pointer[-1] = map; From e2be4e40f4fbea9948601d49b041ad83dbd62c75 Mon Sep 17 00:00:00 2001 From: Blind4Basics <32236948+Blind4Basics@users.noreply.github.com> Date: Mon, 13 Mar 2023 23:35:37 +0100 Subject: [PATCH 094/280] gh-102627: Replace address pointing toward malicious web page (#102630) * Replace known bad address pointing toward a malicious web page. Co-authored-by: C.A.M. Gerlach Co-authored-by: Hugo van Kemenade --- Doc/library/concurrent.futures.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index c543c849585b7f..09c9fc4e6e227a 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -202,7 +202,7 @@ ThreadPoolExecutor Example 'http://www.cnn.com/', 'http://europe.wsj.com/', 'http://www.bbc.co.uk/', - 'http://some-made-up-domain.com/'] + 'http://nonexistant-subdomain.python.org/'] # Retrieve a single page and report the URL and contents def load_url(url, timeout): From 5b8c3cbb5dfab98118112582a7a53f4c2eecc370 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Mon, 13 Mar 2023 20:06:43 -0500 Subject: [PATCH 095/280] GH-102670: Use sumprod() to simplify, speed up, and improve accuracy of statistics functions (GH-102649) --- Lib/statistics.py | 26 ++++++++++--------- Lib/test/test_statistics.py | 12 ++++++++- ...-03-13-18-27-00.gh-issue-102670.GyoThv.rst | 2 ++ 3 files changed, 27 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-03-13-18-27-00.gh-issue-102670.GyoThv.rst diff --git a/Lib/statistics.py b/Lib/statistics.py index 7d5d750193a5ab..6bd214bbfe2ff5 100644 --- a/Lib/statistics.py +++ b/Lib/statistics.py @@ -1036,7 +1036,7 @@ def covariance(x, y, /): raise StatisticsError('covariance requires at least two data points') xbar = fsum(x) / n ybar = fsum(y) / n - sxy = fsum((xi - xbar) * (yi - ybar) for xi, yi in zip(x, y)) + sxy = sumprod((xi - xbar for xi in x), (yi - ybar for yi in y)) return sxy / (n - 1) @@ -1074,11 +1074,14 @@ def correlation(x, y, /, *, method='linear'): start = (n - 1) / -2 # Center rankings around zero x = _rank(x, start=start) y = _rank(y, start=start) - xbar = fsum(x) / n - ybar = fsum(y) / n - sxy = fsum((xi - xbar) * (yi - ybar) for xi, yi in zip(x, y)) - sxx = fsum((d := xi - xbar) * d for xi in x) - syy = fsum((d := yi - ybar) * d for yi in y) + else: + xbar = fsum(x) / n + ybar = fsum(y) / n + x = [xi - xbar for xi in x] + y = [yi - ybar for yi in y] + sxy = sumprod(x, y) + sxx = sumprod(x, x) + syy = sumprod(y, y) try: return sxy / sqrt(sxx * syy) except ZeroDivisionError: @@ -1131,14 +1134,13 @@ def linear_regression(x, y, /, *, proportional=False): raise StatisticsError('linear regression requires that both inputs have same number of data points') if n < 2: raise StatisticsError('linear regression requires at least two data points') - if proportional: - sxy = fsum(xi * yi for xi, yi in zip(x, y)) - sxx = fsum(xi * xi for xi in x) - else: + if not proportional: xbar = fsum(x) / n ybar = fsum(y) / n - sxy = fsum((xi - xbar) * (yi - ybar) for xi, yi in zip(x, y)) - sxx = fsum((d := xi - xbar) * d for xi in x) + x = [xi - xbar for xi in x] # List because used three times below + y = (yi - ybar for yi in y) # Generator because only used once below + sxy = sumprod(x, y) + 0.0 # Add zero to coerce result to a float + sxx = sumprod(x, x) try: slope = sxy / sxx # equivalent to: covariance(x, y) / variance(x) except ZeroDivisionError: diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py index 31a3cb6b53a6f2..f0fa6454b1f91a 100644 --- a/Lib/test/test_statistics.py +++ b/Lib/test/test_statistics.py @@ -1,4 +1,4 @@ -"""Test suite for statistics module, including helper NumericTestCase and +x = """Test suite for statistics module, including helper NumericTestCase and approx_equal function. """ @@ -2610,6 +2610,16 @@ def test_proportional(self): self.assertAlmostEqual(slope, 20 + 1/150) self.assertEqual(intercept, 0.0) + def test_float_output(self): + x = [Fraction(2, 3), Fraction(3, 4)] + y = [Fraction(4, 5), Fraction(5, 6)] + slope, intercept = statistics.linear_regression(x, y) + self.assertTrue(isinstance(slope, float)) + self.assertTrue(isinstance(intercept, float)) + slope, intercept = statistics.linear_regression(x, y, proportional=True) + self.assertTrue(isinstance(slope, float)) + self.assertTrue(isinstance(intercept, float)) + class TestNormalDist: # General note on precision: The pdf(), cdf(), and overlap() methods diff --git a/Misc/NEWS.d/next/Library/2023-03-13-18-27-00.gh-issue-102670.GyoThv.rst b/Misc/NEWS.d/next/Library/2023-03-13-18-27-00.gh-issue-102670.GyoThv.rst new file mode 100644 index 00000000000000..3de09f86754f3e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-13-18-27-00.gh-issue-102670.GyoThv.rst @@ -0,0 +1,2 @@ +Optimized fmean(), correlation(), covariance(), and linear_regression() +using the new math.sumprod() function. From 91a5bd4c0eeec9c0fa2b4797764e1c2fd0b322fa Mon Sep 17 00:00:00 2001 From: Jacob Bower <1978924+jbower-fb@users.noreply.github.com> Date: Mon, 13 Mar 2023 20:35:54 -0500 Subject: [PATCH 096/280] gh-102013: Add PyUnstable_GC_VisitObjects (#102014) --- Doc/c-api/gcsupport.rst | 33 +++++++++ Include/objimpl.h | 19 +++++ ...-02-18-00-55-14.gh-issue-102013.83mrtI.rst | 1 + Modules/_testcapimodule.c | 69 +++++++++++++++++++ Modules/gcmodule.c | 24 +++++++ 5 files changed, 146 insertions(+) create mode 100644 Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst diff --git a/Doc/c-api/gcsupport.rst b/Doc/c-api/gcsupport.rst index 8c90d1e8991c10..cb5d64a50487fe 100644 --- a/Doc/c-api/gcsupport.rst +++ b/Doc/c-api/gcsupport.rst @@ -228,3 +228,36 @@ garbage collection runs. Returns the current state, 0 for disabled and 1 for enabled. .. versionadded:: 3.10 + + +Querying Garbage Collector State +-------------------------------- + +The C-API provides the following interface for querying information about +the garbage collector. + +.. c:function:: void PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg) + + Run supplied *callback* on all live GC-capable objects. *arg* is passed through to + all invocations of *callback*. + + .. warning:: + If new objects are (de)allocated by the callback it is undefined if they + will be visited. + + Garbage collection is disabled during operation. Explicitly running a collection + in the callback may lead to undefined behaviour e.g. visiting the same objects + multiple times or not at all. + + .. versionadded:: 3.12 + +.. c:type:: int (*gcvisitobjects_t)(PyObject *object, void *arg) + + Type of the visitor function to be passed to :c:func:`PyUnstable_GC_VisitObjects`. + *arg* is the same as the *arg* passed to ``PyUnstable_GC_VisitObjects``. + Return ``0`` to continue iteration, return ``1`` to stop iteration. Other return + values are reserved for now so behavior on returning anything else is undefined. + + .. versionadded:: 3.12 + + diff --git a/Include/objimpl.h b/Include/objimpl.h index dde8df34835328..ef871c5ea93ebe 100644 --- a/Include/objimpl.h +++ b/Include/objimpl.h @@ -157,6 +157,25 @@ PyAPI_FUNC(int) PyGC_Enable(void); PyAPI_FUNC(int) PyGC_Disable(void); PyAPI_FUNC(int) PyGC_IsEnabled(void); + +#if !defined(Py_LIMITED_API) +/* Visit all live GC-capable objects, similar to gc.get_objects(None). The + * supplied callback is called on every such object with the void* arg set + * to the supplied arg. Returning 0 from the callback ends iteration, returning + * 1 allows iteration to continue. Returning any other value may result in + * undefined behaviour. + * + * If new objects are (de)allocated by the callback it is undefined if they + * will be visited. + + * Garbage collection is disabled during operation. Explicitly running a + * collection in the callback may lead to undefined behaviour e.g. visiting the + * same objects multiple times or not at all. + */ +typedef int (*gcvisitobjects_t)(PyObject*, void*); +PyAPI_FUNC(void) PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void* arg); +#endif + /* Test if a type has a GC head */ #define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC) diff --git a/Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst b/Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst new file mode 100644 index 00000000000000..0350237ebc7390 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2023-02-18-00-55-14.gh-issue-102013.83mrtI.rst @@ -0,0 +1 @@ +Add a new (unstable) C-API function for iterating over GC'able objects using a callback: ``PyUnstable_VisitObjects``. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index ea67017a1ba3b1..f45d0312e94411 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3310,6 +3310,73 @@ function_set_kw_defaults(PyObject *self, PyObject *args) Py_RETURN_NONE; } +struct gc_visit_state_basic { + PyObject *target; + int found; +}; + +static int +gc_visit_callback_basic(PyObject *obj, void *arg) +{ + struct gc_visit_state_basic *state = (struct gc_visit_state_basic *)arg; + if (obj == state->target) { + state->found = 1; + return 0; + } + return 1; +} + +static PyObject * +test_gc_visit_objects_basic(PyObject *Py_UNUSED(self), + PyObject *Py_UNUSED(ignored)) +{ + PyObject *obj; + struct gc_visit_state_basic state; + + obj = PyList_New(0); + if (obj == NULL) { + return NULL; + } + state.target = obj; + state.found = 0; + + PyUnstable_GC_VisitObjects(gc_visit_callback_basic, &state); + Py_DECREF(obj); + if (!state.found) { + PyErr_SetString( + PyExc_AssertionError, + "test_gc_visit_objects_basic: Didn't find live list"); + return NULL; + } + Py_RETURN_NONE; +} + +static int +gc_visit_callback_exit_early(PyObject *obj, void *arg) + { + int *visited_i = (int *)arg; + (*visited_i)++; + if (*visited_i == 2) { + return 0; + } + return 1; +} + +static PyObject * +test_gc_visit_objects_exit_early(PyObject *Py_UNUSED(self), + PyObject *Py_UNUSED(ignored)) +{ + int visited_i = 0; + PyUnstable_GC_VisitObjects(gc_visit_callback_exit_early, &visited_i); + if (visited_i != 2) { + PyErr_SetString( + PyExc_AssertionError, + "test_gc_visit_objects_exit_early: did not exit when expected"); + } + Py_RETURN_NONE; +} + + static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *); static PyMethodDef TestMethods[] = { @@ -3452,6 +3519,8 @@ static PyMethodDef TestMethods[] = { {"function_set_defaults", function_set_defaults, METH_VARARGS, NULL}, {"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL}, {"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL}, + {"test_gc_visit_objects_basic", test_gc_visit_objects_basic, METH_NOARGS, NULL}, + {"test_gc_visit_objects_exit_early", test_gc_visit_objects_exit_early, METH_NOARGS, NULL}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 5879c5e11fe14a..4eaa5490b6134c 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -2401,3 +2401,27 @@ PyObject_GC_IsFinalized(PyObject *obj) } return 0; } + +void +PyUnstable_GC_VisitObjects(gcvisitobjects_t callback, void *arg) +{ + size_t i; + GCState *gcstate = get_gc_state(); + int origenstate = gcstate->enabled; + gcstate->enabled = 0; + for (i = 0; i < NUM_GENERATIONS; i++) { + PyGC_Head *gc_list, *gc; + gc_list = GEN_HEAD(gcstate, i); + for (gc = GC_NEXT(gc_list); gc != gc_list; gc = GC_NEXT(gc)) { + PyObject *op = FROM_GC(gc); + Py_INCREF(op); + int res = callback(op, arg); + Py_DECREF(op); + if (!res) { + goto done; + } + } + } +done: + gcstate->enabled = origenstate; +} From e65b6b835732f933a95738b0796b349dd02385b0 Mon Sep 17 00:00:00 2001 From: Joongi Kim Date: Tue, 14 Mar 2023 11:07:59 +0900 Subject: [PATCH 097/280] doc: Remove a duplicate 'versionchanged' in library/asyncio-task (gh-102677) --- Doc/library/asyncio-task.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 9b984243282268..5f1449e1b599ef 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -814,9 +814,6 @@ Waiting Primitives Raises :exc:`TimeoutError` if the timeout occurs before all Futures are done. - .. versionchanged:: 3.10 - Removed the *loop* parameter. - Example:: for coro in as_completed(aws): From 4d7f5d0f8339aa2ff8b823483b8b5f1c9a09c629 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Tue, 14 Mar 2023 14:22:21 +0530 Subject: [PATCH 098/280] GH-100227: cleanup initialization of global interned dict (#102682) --- Objects/unicodeobject.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 2d50f9c340f2f3..b9fb53147b9b51 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14533,6 +14533,15 @@ _PyUnicode_InitGlobalObjects(PyInterpreterState *interp) return _PyStatus_OK(); } + // Initialize the global interned dict + PyObject *interned = PyDict_New(); + if (interned == NULL) { + PyErr_Clear(); + return _PyStatus_ERR("failed to create interned dict"); + } + + set_interned_dict(interned); + /* Intern statically allocated string identifiers and deepfreeze strings. * This must be done before any module initialization so that statically * allocated string identifiers are used instead of heap allocated strings. @@ -14600,14 +14609,7 @@ PyUnicode_InternInPlace(PyObject **p) } PyObject *interned = get_interned_dict(); - if (interned == NULL) { - interned = PyDict_New(); - if (interned == NULL) { - PyErr_Clear(); /* Don't leave an exception */ - return; - } - set_interned_dict(interned); - } + assert(interned != NULL); PyObject *t = PyDict_SetDefault(interned, s, s); if (t == NULL) { From 9c6171822f0476e283045d7f6693a00ba145d1bb Mon Sep 17 00:00:00 2001 From: T Date: Tue, 14 Mar 2023 17:23:52 +0800 Subject: [PATCH 099/280] gh-100315: clarification to `__slots__` docs. (#102621) refer to tp_itemsize in discussion on "variable-length" built-in types --- Doc/reference/datamodel.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index f447bbb1216d52..1865d09fcaa127 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -1944,8 +1944,10 @@ Notes on using *__slots__* descriptor directly from the base class). This renders the meaning of the program undefined. In the future, a check may be added to prevent this. -* Nonempty *__slots__* does not work for classes derived from "variable-length" - built-in types such as :class:`int`, :class:`bytes` and :class:`tuple`. +* :exc:`TypeError` will be raised if nonempty *__slots__* are defined for a + class derived from a + :c:member:`"variable-length" built-in type ` such as + :class:`int`, :class:`bytes`, and :class:`tuple`. * Any non-string :term:`iterable` may be assigned to *__slots__*. From c92b445f4119da2f400067bec89177393bad680a Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Tue, 14 Mar 2023 15:21:38 +0530 Subject: [PATCH 100/280] GH-94851: check unicode consistency of static strings in debug mode (#102684) --- .../internal/pycore_unicodeobject_generated.h | 664 ++++++++++++++++++ Tools/build/generate_global_objects.py | 1 + 2 files changed, 665 insertions(+) diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 52af37a8e60aa8..fea9b6dbb1a75f 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -13,1332 +13,1996 @@ static inline void _PyUnicode_InitStaticStrings(void) { PyObject *string; string = &_Py_ID(CANCELLED); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(FINISHED); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(False); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(JSONDecodeError); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(PENDING); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(Py_Repr); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(TextIOWrapper); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(True); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(WarningMessage); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_WindowsConsoleIO); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__IOBase_closed); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__abc_tpflags__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__abs__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__abstractmethods__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__add__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__aenter__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__aexit__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__aiter__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__all__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__and__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__anext__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__annotations__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__args__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__asyncio_running_event_loop__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__await__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__bases__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__bool__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__build_class__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__builtins__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__bytes__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__call__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__cantrace__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__class__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__class_getitem__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__classcell__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__complex__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__contains__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__copy__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ctypes_from_outparam__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__del__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__delattr__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__delete__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__delitem__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__dict__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__dictoffset__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__dir__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__divmod__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__doc__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__enter__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__eq__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__exit__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__file__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__float__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__floordiv__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__format__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__fspath__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ge__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__get__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getattr__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getattribute__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getinitargs__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getitem__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getnewargs__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getnewargs_ex__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__getstate__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__gt__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__hash__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__iadd__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__iand__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ifloordiv__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ilshift__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__imatmul__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__imod__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__import__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__imul__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__index__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__init__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__init_subclass__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__instancecheck__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__int__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__invert__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ior__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ipow__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__irshift__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__isabstractmethod__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__isub__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__iter__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__itruediv__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ixor__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__le__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__len__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__length_hint__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__lltrace__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__loader__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__lshift__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__lt__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__main__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__matmul__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__missing__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__mod__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__module__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__mro_entries__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__mul__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__name__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ne__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__neg__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__new__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__newobj__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__newobj_ex__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__next__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__notes__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__or__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__orig_class__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__origin__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__package__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__parameters__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__path__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__pos__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__pow__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__prepare__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__qualname__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__radd__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rand__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rdivmod__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__reduce__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__reduce_ex__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__repr__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__reversed__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rfloordiv__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rlshift__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rmatmul__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rmod__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rmul__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__ror__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__round__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rpow__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rrshift__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rshift__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rsub__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rtruediv__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__rxor__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__set__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__set_name__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__setattr__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__setitem__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__setstate__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__sizeof__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__slotnames__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__slots__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__spec__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__str__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__sub__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__subclasscheck__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__subclasshook__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__truediv__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__trunc__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__typing_is_unpacked_typevartuple__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__typing_prepare_subst__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__typing_subst__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__typing_unpacked_tuple_args__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__warningregistry__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__weaklistoffset__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__weakref__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(__xor__); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_abc_impl); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_abstract_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_active); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_annotation); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_anonymous_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_argtypes_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_as_parameter_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_asyncio_future_blocking); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_blksize); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_bootstrap); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_check_retval_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_dealloc_warn); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_feature_version); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_fields_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_finalizing); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_find_and_load); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_fix_up_module); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_flags_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_get_sourcefile); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_handle_fromlist); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_initializing); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_io); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_is_text_encoding); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_length_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_limbo); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_lock_unlock_module); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_loop); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_needs_com_addref_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_pack_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_restype_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_showwarnmsg); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_shutdown); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_slotnames); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_strptime_datetime); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_swappedbytes_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_type_); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_uninitialized_submodules); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_warn_unawaited_coroutine); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(_xoptions); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(a); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(abs_tol); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(access); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(add); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(add_done_callback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(after_in_child); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(after_in_parent); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(aggregate_class); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(append); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(argdefs); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(arguments); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(argv); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(as_integer_ratio); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ast); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(attribute); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(authorizer_callback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(autocommit); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(b); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(backtick); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(base); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(before); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(big); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(binary_form); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(block); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(buffer); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(buffer_callback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(buffer_size); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(buffering); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(buffers); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(bufsize); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(builtins); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(byteorder); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(bytes); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(bytes_per_sep); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(c); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(c_call); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(c_exception); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(c_return); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cached_statements); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cadata); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cafile); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(call); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(call_exception_handler); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(call_soon); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cancel); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(capath); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(category); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cb_type); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(certfile); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(check_same_thread); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(clear); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(close); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(closed); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(closefd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(closure); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_argcount); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_cellvars); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_code); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_consts); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_exceptiontable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_filename); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_firstlineno); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_flags); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_freevars); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_kwonlyargcount); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_linetable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_name); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_names); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_nlocals); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_posonlyargcount); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_qualname); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_stacksize); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(co_varnames); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(code); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(command); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(comment_factory); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(consts); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(context); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cookie); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(copy); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(copyreg); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(coro); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(count); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(cwd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(d); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(data); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(database); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(decode); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(decoder); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(default); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(defaultaction); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(delete); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(depth); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(detect_types); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(deterministic); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(device); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dict); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dictcomp); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(difference_update); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(digest); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(digest_size); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(digestmod); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dir_fd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(discard); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dispatch_table); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(displayhook); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dklen); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(doc); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dont_inherit); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dst); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(dst_dir_fd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(duration); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(e); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(effective_ids); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(element_factory); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(encode); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(encoding); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(end); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(end_lineno); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(end_offset); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(endpos); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(env); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(errors); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(event); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(eventmask); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(exc_type); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(exc_value); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(excepthook); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(exception); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(exp); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(extend); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(facility); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(factory); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(false); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(family); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fanout); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fd2); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fdel); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fget); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(file); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(file_actions); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(filename); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fileno); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(filepath); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fillvalue); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(filters); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(final); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(find_class); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fix_imports); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(flags); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(flush); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(follow_symlinks); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(format); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(frequency); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(from_param); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fromlist); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fromtimestamp); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fromutc); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(fset); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(func); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(future); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(generation); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(genexpr); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(get); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(get_debug); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(get_event_loop); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(get_loop); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(get_source); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(getattr); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(getstate); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(gid); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(globals); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(groupindex); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(groups); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(handle); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(hash_name); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(header); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(headers); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(hi); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(hook); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(id); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ident); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ignore); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(imag); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(importlib); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(in_fd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(incoming); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(indexgroup); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(inf); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(inheritable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(initial); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(initial_bytes); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(initial_value); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(initval); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(inner_size); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(input); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(insert_comments); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(insert_pis); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(instructions); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(intern); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(intersection); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(isatty); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(isinstance); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(isoformat); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(isolation_level); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(istext); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(item); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(items); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(iter); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(iterable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(iterations); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(join); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(jump); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(keepends); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(key); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(keyfile); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(keys); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(kind); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(kw); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(kw1); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(kw2); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(lambda); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(last); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(last_node); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(last_traceback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(last_type); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(last_value); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(latin1); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(leaf_size); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(len); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(length); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(level); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(limit); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(line); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(line_buffering); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(lineno); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(listcomp); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(little); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(lo); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(locale); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(locals); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(logoption); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(loop); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(mapping); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(match); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(max_length); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(maxdigits); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(maxevents); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(maxmem); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(maxsplit); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(maxvalue); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(memLevel); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(memlimit); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(message); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(metaclass); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(method); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(mod); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(mode); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(module); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(module_globals); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(modules); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(mro); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(msg); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(mycmp); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(n); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(n_arg); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(n_fields); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(n_sequence_fields); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(n_unnamed_fields); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(name); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(name_from); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(namespace_separator); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(namespaces); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(narg); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ndigits); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(new_limit); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(newline); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(newlines); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(next); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(node_depth); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(node_offset); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ns); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(nstype); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(nt); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(null); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(number); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(obj); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(object); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(offset); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(offset_dst); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(offset_src); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(on_type_read); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(onceregistry); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(only_keys); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(oparg); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(opcode); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(open); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(opener); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(operation); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(optimize); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(options); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(order); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(out_fd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(outgoing); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(overlapped); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(owner); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(p); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pages); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(parent); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(password); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(path); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pattern); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(peek); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(persistent_id); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(persistent_load); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(person); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pi_factory); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pid); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(policy); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pos); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pos1); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(pos2); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(posix); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(print_file_and_line); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(priority); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(progress); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(progress_handler); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(proto); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(protocol); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ps1); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(ps2); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(query); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(quotetabs); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(r); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(raw); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(read); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(read1); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(readable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(readall); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(readinto); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(readinto1); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(readline); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(readonly); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(real); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(reducer_override); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(registry); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(rel_tol); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(reload); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(repl); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(replace); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(reserved); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(reset); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(resetids); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(return); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(reverse); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(reversed); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(s); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(salt); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sched_priority); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(scheduler); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(seek); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(seekable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(selectors); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(self); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(send); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sep); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sequence); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(server_hostname); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(server_side); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(session); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(setcomp); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(setpgroup); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(setsid); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(setsigdef); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(setsigmask); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(setstate); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(shape); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(show_cmd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(signed); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(size); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sizehint); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(skip_file_prefixes); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sleep); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sock); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sort); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sound); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(source); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(source_traceback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(src); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(src_dir_fd); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(stacklevel); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(start); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(statement); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(status); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(stderr); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(stdin); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(stdout); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(step); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(store_name); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(strategy); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(strftime); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(strict); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(strict_mode); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(string); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(sub_key); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(symmetric_difference_update); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tabsize); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tag); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(target); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(target_is_directory); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(task); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tb_frame); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tb_lasti); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tb_lineno); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tb_next); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tell); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(template); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(term); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(text); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(threading); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(throw); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(timeout); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(times); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(timetuple); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(top); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(trace_callback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(traceback); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(trailers); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(translate); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(true); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(truncate); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(twice); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(txt); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(type); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tz); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(tzname); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(uid); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(unlink); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(unraisablehook); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(uri); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(usedforsecurity); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(value); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(values); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(version); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(volume); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(warnings); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(warnoptions); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(wbits); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(week); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(weekday); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(which); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(who); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(withdata); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(writable); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(write); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(write_through); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(x); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(year); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); string = &_Py_ID(zdict); + assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); } /* End auto-generated code */ diff --git a/Tools/build/generate_global_objects.py b/Tools/build/generate_global_objects.py index 9ceae89878cda8..1f53f02d41ef39 100644 --- a/Tools/build/generate_global_objects.py +++ b/Tools/build/generate_global_objects.py @@ -360,6 +360,7 @@ def generate_static_strings_initializer(identifiers, strings): # This use of _Py_ID() is ignored by iter_global_strings() # since iter_files() ignores .h files. printer.write(f'string = &_Py_ID({i});') + printer.write(f'assert(_PyUnicode_CheckConsistency(string, 1));') printer.write(f'PyUnicode_InternInPlace(&string);') # XXX What about "strings"? printer.write(END) From 038b67ce91dfad85b4972f3c65c8797a824fdf33 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 14 Mar 2023 10:05:54 -0600 Subject: [PATCH 101/280] gh-81057: Add a CI Check for New Unsupported C Global Variables (gh-102506) This will keep us from adding new unsupported (i.e. non-const) C global variables, which would break interpreter isolation. FYI, historically it is very uncommon for new global variables to get added. Furthermore, it is rare for new code to break the c-analyzer. So the check should almost always pass unnoticed. Note that I've removed test_check_c_globals. A test wasn't a great fit conceptually and was super slow on debug builds. A CI check is a better fit. This also resolves gh-100237. https://github.com/python/cpython/issues/81057 --- .github/workflows/build.yml | 3 + Lib/test/test_check_c_globals.py | 34 ---------- Makefile.pre.in | 6 ++ .../c_parser/preprocessor/common.py | 6 +- Tools/c-analyzer/c_parser/preprocessor/gcc.py | 23 ++++--- Tools/c-analyzer/cpython/__main__.py | 62 ++++++++++++++++--- Tools/c-analyzer/cpython/_parser.py | 9 ++- Tools/c-analyzer/cpython/ignored.tsv | 1 + 8 files changed, 90 insertions(+), 54 deletions(-) delete mode 100644 Lib/test/test_check_c_globals.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2241b0b8aa409e..4e5328282f1224 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -111,6 +111,9 @@ jobs: run: make smelly - name: Check limited ABI symbols run: make check-limited-abi + - name: Check for unsupported C global variables + if: github.event_name == 'pull_request' # $GITHUB_EVENT_NAME + run: make check-c-globals build_win32: name: 'Windows (x86)' diff --git a/Lib/test/test_check_c_globals.py b/Lib/test/test_check_c_globals.py deleted file mode 100644 index 670be52422f799..00000000000000 --- a/Lib/test/test_check_c_globals.py +++ /dev/null @@ -1,34 +0,0 @@ -import unittest -import test.test_tools -from test.support.warnings_helper import save_restore_warnings_filters - - -# TODO: gh-92584: c-analyzer uses distutils which was removed in Python 3.12 -raise unittest.SkipTest("distutils has been removed in Python 3.12") - - -test.test_tools.skip_if_missing('c-analyzer') -with test.test_tools.imports_under_tool('c-analyzer'): - # gh-95349: Save/restore warnings filters to leave them unchanged. - # Importing the c-analyzer imports docutils which imports pkg_resources - # which adds a warnings filter. - with save_restore_warnings_filters(): - from cpython.__main__ import main - - -class ActualChecks(unittest.TestCase): - - # XXX Also run the check in "make check". - #@unittest.expectedFailure - # Failing on one of the buildbots (see https://bugs.python.org/issue36876). - @unittest.skip('activate this once all the globals have been resolved') - def test_check_c_globals(self): - try: - main('check', {}) - except NotImplementedError: - raise unittest.SkipTest('not supported on this host') - - -if __name__ == '__main__': - # Test needs to be a package, so we can do relative imports. - unittest.main() diff --git a/Makefile.pre.in b/Makefile.pre.in index 1a1853bf3d7871..59762165c10036 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2560,6 +2560,12 @@ distclean: clobber docclean smelly: all $(RUNSHARED) ./$(BUILDPYTHON) $(srcdir)/Tools/build/smelly.py +# Check if any unsupported C global variables have been added. +check-c-globals: + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/c-analyzer/check-c-globals.py \ + --format summary \ + --traceback + # Find files with funny names funny: find $(SUBDIRS) $(SUBDIRSTOO) \ diff --git a/Tools/c-analyzer/c_parser/preprocessor/common.py b/Tools/c-analyzer/c_parser/preprocessor/common.py index 4291a066337545..dbe1edeef38527 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/common.py +++ b/Tools/c-analyzer/c_parser/preprocessor/common.py @@ -115,15 +115,15 @@ def converted_error(tool, argv, filename): def convert_error(tool, argv, filename, stderr, rc): error = (stderr.splitlines()[0], rc) if (_expected := is_os_mismatch(filename, stderr)): - logger.debug(stderr.strip()) + logger.info(stderr.strip()) raise OSMismatchError(filename, _expected, argv, error, tool) elif (_missing := is_missing_dep(stderr)): - logger.debug(stderr.strip()) + logger.info(stderr.strip()) raise MissingDependenciesError(filename, (_missing,), argv, error, tool) elif '#error' in stderr: # XXX Ignore incompatible files. error = (stderr.splitlines()[1], rc) - logger.debug(stderr.strip()) + logger.info(stderr.strip()) raise ErrorDirectiveError(filename, argv, error, tool) else: # Try one more time, with stderr written to the terminal. diff --git a/Tools/c-analyzer/c_parser/preprocessor/gcc.py b/Tools/c-analyzer/c_parser/preprocessor/gcc.py index 7ef1a8afc3b135..24c1b0e9b9d48c 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/gcc.py +++ b/Tools/c-analyzer/c_parser/preprocessor/gcc.py @@ -6,6 +6,11 @@ TOOL = 'gcc' +META_FILES = { + '', + '', +} + # https://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html # flags: # 1 start of a new file @@ -75,11 +80,15 @@ def _iter_lines(text, reqfile, samefiles, cwd, raw=False): # The first line is special. # The next two lines are consistent. - for expected in [ - f'# 1 "{reqfile}"', - '# 1 ""', - '# 1 ""', - ]: + firstlines = [ + f'# 0 "{reqfile}"', + '# 0 ""', + '# 0 ""', + ] + if text.startswith('# 1 '): + # Some preprocessors emit a lineno of 1 for line-less entries. + firstlines = [l.replace('# 0 ', '# 1 ') for l in firstlines] + for expected in firstlines: line = next(lines) if line != expected: raise NotImplementedError((line, expected)) @@ -121,7 +130,7 @@ def _iter_top_include_lines(lines, topfile, cwd, # _parse_marker_line() that the preprocessor reported lno as 1. lno = 1 for line in lines: - if line == '# 1 "" 2': + if line == '# 0 "" 2' or line == '# 1 "" 2': # We're done with this top-level include. return @@ -174,8 +183,8 @@ def _parse_marker_line(line, reqfile=None): return None, None, None lno, origfile, flags = m.groups() lno = int(lno) + assert origfile not in META_FILES, (line,) assert lno > 0, (line, lno) - assert origfile not in ('', ''), (line,) flags = set(int(f) for f in flags.split()) if flags else () if 1 in flags: diff --git a/Tools/c-analyzer/cpython/__main__.py b/Tools/c-analyzer/cpython/__main__.py index 2b9e4233b95ac4..fe7a16726f45a9 100644 --- a/Tools/c-analyzer/cpython/__main__.py +++ b/Tools/c-analyzer/cpython/__main__.py @@ -1,5 +1,6 @@ import logging import sys +import textwrap from c_common.fsutil import expand_filenames, iter_files_by_suffix from c_common.scriptutil import ( @@ -26,6 +27,39 @@ logger = logging.getLogger(__name__) +CHECK_EXPLANATION = textwrap.dedent(''' + ------------------------- + + Non-constant global variables are generally not supported + in the CPython repo. We use a tool to analyze the C code + and report if any unsupported globals are found. The tool + may be run manually with: + + ./python Tools/c-analyzer/check-c-globals.py --format summary [FILE] + + Occasionally the tool is unable to parse updated code. + If this happens then add the file to the "EXCLUDED" list + in Tools/c-analyzer/cpython/_parser.py and create a new + issue for fixing the tool (and CC ericsnowcurrently + on the issue). + + If the tool reports an unsupported global variable and + it is actually const (and thus supported) then first try + fixing the declaration appropriately in the code. If that + doesn't work then add the variable to the "should be const" + section of Tools/c-analyzer/cpython/ignored.tsv. + + If the tool otherwise reports an unsupported global variable + then first try to make it non-global, possibly adding to + PyInterpreterState (for core code) or module state (for + extension modules). In an emergency, you can add the + variable to Tools/c-analyzer/cpython/globals-to-fix.tsv + to get CI passing, but doing so should be avoided. If + this course it taken, be sure to create an issue for + eliminating the global (and CC ericsnowcurrently). +''') + + def _resolve_filenames(filenames): if filenames: resolved = (_files.resolve_filename(f) for f in filenames) @@ -123,14 +157,26 @@ def _cli_check(parser, **kwargs): def cmd_check(filenames=None, **kwargs): filenames = _resolve_filenames(filenames) kwargs['get_file_preprocessor'] = _parser.get_preprocessor(log_err=print) - c_analyzer.cmd_check( - filenames, - relroot=REPO_ROOT, - _analyze=_analyzer.analyze, - _CHECKS=CHECKS, - file_maxsizes=_parser.MAX_SIZES, - **kwargs - ) + try: + c_analyzer.cmd_check( + filenames, + relroot=REPO_ROOT, + _analyze=_analyzer.analyze, + _CHECKS=CHECKS, + file_maxsizes=_parser.MAX_SIZES, + **kwargs + ) + except SystemExit as exc: + num_failed = exc.args[0] if getattr(exc, 'args', None) else None + if isinstance(num_failed, int): + if num_failed > 0: + sys.stderr.flush() + print(CHECK_EXPLANATION, flush=True) + raise # re-raise + except Exception: + sys.stderr.flush() + print(CHECK_EXPLANATION, flush=True) + raise # re-raise def cmd_analyze(filenames=None, **kwargs): diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index e7764165d36c4c..6da4fbbf4224f1 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -106,15 +106,20 @@ def clean_lines(text): * ./Include/internal Modules/_decimal/**/*.c Modules/_decimal/libmpdec +Modules/_elementtree.c Modules/expat Modules/_hacl/*.c Modules/_hacl/include Modules/_hacl/*.h Modules/_hacl/include -Modules/_tkinter.c /usr/include/tcl8.6 Modules/md5module.c Modules/_hacl/include Modules/sha1module.c Modules/_hacl/include Modules/sha2module.c Modules/_hacl/include -Modules/tkappinit.c /usr/include/tcl Objects/stringlib/*.h Objects +# possible system-installed headers, just in case +Modules/_tkinter.c /usr/include/tcl8.6 +Modules/_uuidmodule.c /usr/include/uuid +Modules/nismodule.c /usr/include/tirpc +Modules/tkappinit.c /usr/include/tcl + # @end=tsv@ ''')[1:] diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 700ddf2851839e..048112dd992555 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -228,6 +228,7 @@ Modules/_xxinterpchannelsmodule.c - _channelid_end_recv - Modules/_xxinterpchannelsmodule.c - _channelid_end_send - Modules/_zoneinfo.c - DAYS_BEFORE_MONTH - Modules/_zoneinfo.c - DAYS_IN_MONTH - +Modules/_xxsubinterpretersmodule.c - no_exception - Modules/arraymodule.c - descriptors - Modules/arraymodule.c - emptybuf - Modules/cjkcodecs/_codecs_cn.c - _mapping_list - From 41426fe588e204baddc4800c79d92dec7dbb1fd6 Mon Sep 17 00:00:00 2001 From: Paul Watson Date: Tue, 14 Mar 2023 13:40:12 -0500 Subject: [PATCH 102/280] gh-102354: change python3 to python in docs examples (#102696) --- Doc/library/__main__.rst | 2 +- Doc/library/importlib.metadata.rst | 2 +- Doc/library/pdb.rst | 4 ++-- Doc/tutorial/venv.rst | 2 +- Doc/using/venv-create.inc | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Doc/library/__main__.rst b/Doc/library/__main__.rst index 6a2a7a7317f711..761c88710f9891 100644 --- a/Doc/library/__main__.rst +++ b/Doc/library/__main__.rst @@ -259,7 +259,7 @@ one mentioned below are preferred. See :mod:`venv` for an example of a package with a minimal ``__main__.py`` in the standard library. It doesn't contain a ``if __name__ == '__main__'`` - block. You can invoke it with ``python3 -m venv [directory]``. + block. You can invoke it with ``python -m venv [directory]``. See :mod:`runpy` for more details on the :option:`-m` flag to the interpreter executable. diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst index 988d1a317f5960..6e084101995e25 100644 --- a/Doc/library/importlib.metadata.rst +++ b/Doc/library/importlib.metadata.rst @@ -73,7 +73,7 @@ something into it: .. code-block:: shell-session - $ python3 -m venv example + $ python -m venv example $ source example/bin/activate (example) $ python -m pip install wheel diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 4ae12a5d03a78d..21c6ca8622dceb 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -58,7 +58,7 @@ of the debugger is:: :file:`pdb.py` can also be invoked as a script to debug other scripts. For example:: - python3 -m pdb myscript.py + python -m pdb myscript.py When invoked as a script, pdb will automatically enter post-mortem debugging if the program being debugged exits abnormally. After post-mortem debugging (or @@ -72,7 +72,7 @@ useful than quitting the debugger upon program's exit. .. versionadded:: 3.7 :file:`pdb.py` now accepts a ``-m`` option that execute modules similar to the way - ``python3 -m`` does. As with a script, the debugger will pause execution just + ``python -m`` does. As with a script, the debugger will pause execution just before the first line of the module. diff --git a/Doc/tutorial/venv.rst b/Doc/tutorial/venv.rst index 05f0e6bbcc1b04..d1bba098d7d23b 100644 --- a/Doc/tutorial/venv.rst +++ b/Doc/tutorial/venv.rst @@ -44,7 +44,7 @@ whichever version you want. To create a virtual environment, decide upon a directory where you want to place it, and run the :mod:`venv` module as a script with the directory path:: - python3 -m venv tutorial-env + python -m venv tutorial-env This will create the ``tutorial-env`` directory if it doesn't exist, and also create directories inside it containing a copy of the Python diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc index d535b254f05698..43ee6b7807d57e 100644 --- a/Doc/using/venv-create.inc +++ b/Doc/using/venv-create.inc @@ -1,7 +1,7 @@ Creation of :ref:`virtual environments ` is done by executing the command ``venv``:: - python3 -m venv /path/to/new/virtual/environment + python -m venv /path/to/new/virtual/environment Running this command creates the target directory (creating any parent directories that don't exist already) and places a ``pyvenv.cfg`` file in it From f4367d5b83413c699ed89a51cff15cc155fa5f8b Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 14 Mar 2023 14:01:35 -0600 Subject: [PATCH 103/280] gh-102660: Handle m_copy Specially for the sys and builtins Modules (gh-102661) It doesn't make sense to use multi-phase init for these modules. Using a per-interpreter "m_copy" (instead of PyModuleDef.m_base.m_copy) makes this work okay. (This came up while working on gh-101660.) Note that we might instead end up disallowing re-load for sys/builtins since they are so special. https://github.com/python/cpython/issues/102660 --- Include/internal/pycore_interp.h | 1 + Python/bltinmodule.c | 3 +++ Python/import.c | 35 ++++++++++++++++++++++++++++---- Python/pystate.c | 1 + Python/sysmodule.c | 8 ++++++++ 5 files changed, 44 insertions(+), 4 deletions(-) diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index a3a582522361f1..fd7b92e86aa120 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -111,6 +111,7 @@ struct _is { PyObject *dict; /* Stores per-interpreter state */ + PyObject *sysdict_copy; PyObject *builtins_copy; // Initialized to _PyEval_EvalFrameDefault(). _PyFrameEvalFunction eval_frame; diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 12ca0ba6c4873c..a8a34620b9bcdf 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -3098,6 +3098,9 @@ _PyBuiltin_Init(PyInterpreterState *interp) } Py_DECREF(debug); + /* m_copy of Py_None means it is copied some other way. */ + builtinsmodule.m_base.m_copy = Py_NewRef(Py_None); + return mod; #undef ADD_TO_ALL #undef SETBUILTIN diff --git a/Python/import.c b/Python/import.c index 1bf4199e125aa5..612fee243bd9e7 100644 --- a/Python/import.c +++ b/Python/import.c @@ -978,6 +978,16 @@ _PyImport_CheckSubinterpIncompatibleExtensionAllowed(const char *name) return 0; } +static inline int +match_mod_name(PyObject *actual, const char *expected) +{ + if (PyUnicode_CompareWithASCIIString(actual, expected) == 0) { + return 1; + } + assert(!PyErr_Occurred()); + return 0; +} + static int fix_up_extension(PyObject *mod, PyObject *name, PyObject *filename) { @@ -1001,7 +1011,8 @@ fix_up_extension(PyObject *mod, PyObject *name, PyObject *filename) // when the extension module doesn't support sub-interpreters. // XXX Why special-case the main interpreter? if (_Py_IsMainInterpreter(tstate->interp) || def->m_size == -1) { - if (def->m_size == -1) { + /* m_copy of Py_None means it is copied some other way. */ + if (def->m_size == -1 && def->m_base.m_copy != Py_None) { if (def->m_base.m_copy) { /* Somebody already imported the module, likely under a different name. @@ -1055,18 +1066,34 @@ import_find_extension(PyThreadState *tstate, PyObject *name, PyObject *modules = MODULES(tstate->interp); if (def->m_size == -1) { + PyObject *m_copy = def->m_base.m_copy; /* Module does not support repeated initialization */ - if (def->m_base.m_copy == NULL) + if (m_copy == NULL) { return NULL; + } + else if (m_copy == Py_None) { + if (match_mod_name(name, "sys")) { + m_copy = tstate->interp->sysdict_copy; + } + else if (match_mod_name(name, "builtins")) { + m_copy = tstate->interp->builtins_copy; + } + else { + _PyErr_SetString(tstate, PyExc_ImportError, "missing m_copy"); + return NULL; + } + } + /* m_copy of Py_None means it is copied some other way. */ mod = import_add_module(tstate, name); - if (mod == NULL) + if (mod == NULL) { return NULL; + } mdict = PyModule_GetDict(mod); if (mdict == NULL) { Py_DECREF(mod); return NULL; } - if (PyDict_Update(mdict, def->m_base.m_copy)) { + if (PyDict_Update(mdict, m_copy)) { Py_DECREF(mod); return NULL; } diff --git a/Python/pystate.c b/Python/pystate.c index 28606e4f32f71c..3a2966c54a4c3b 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -805,6 +805,7 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) assert(interp->imports.importlib == NULL); assert(interp->imports.import_func == NULL); + Py_CLEAR(interp->sysdict_copy); Py_CLEAR(interp->builtins_copy); Py_CLEAR(interp->dict); #ifdef HAVE_FORK diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 764fb70bae6c38..fc0550266bf1af 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3425,12 +3425,20 @@ _PySys_Create(PyThreadState *tstate, PyObject **sysmod_p) return _PyStatus_ERR("failed to create a module object"); } + /* m_copy of Py_None means it is copied some other way. */ + sysmodule.m_base.m_copy = Py_NewRef(Py_None); + PyObject *sysdict = PyModule_GetDict(sysmod); if (sysdict == NULL) { goto error; } interp->sysdict = Py_NewRef(sysdict); + interp->sysdict_copy = PyDict_Copy(sysdict); + if (interp->sysdict_copy == NULL) { + goto error; + } + if (PyDict_SetItemString(sysdict, "modules", modules) < 0) { goto error; } From b608a1920bb22a2ebeed90103d6fd9258ccbdbdd Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Wed, 15 Mar 2023 05:20:14 +0900 Subject: [PATCH 104/280] gh-102674: Remove _specialization_stats from Lib/opcode.py (#102685) It's not use except in a test, so move it there instead. --- Lib/opcode.py | 8 -------- Lib/test/test__opcode.py | 3 +-- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/Lib/opcode.py b/Lib/opcode.py index e46327cfe680b7..01e574509d38d5 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -389,14 +389,6 @@ def pseudo_op(name, op, real_ops): _specialized_instructions = [ opcode for family in _specializations.values() for opcode in family ] -_specialization_stats = [ - "success", - "failure", - "hit", - "deferred", - "miss", - "deopt", -] _cache_format = { "LOAD_GLOBAL": { diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py index db831069c7aeb8..fb4ab15f7041ed 100644 --- a/Lib/test/test__opcode.py +++ b/Lib/test/test__opcode.py @@ -69,8 +69,7 @@ def test_stack_effect_jump(self): class SpecializationStatsTests(unittest.TestCase): def test_specialization_stats(self): - stat_names = opcode._specialization_stats - + stat_names = ["success", "failure", "hit", "deferred", "miss", "deopt"] specialized_opcodes = [ op.lower() for op in opcode._specializations From a5048304df5e6936076751bd2a5cdddcbe84da06 Mon Sep 17 00:00:00 2001 From: JosephSBoyle <48555120+JosephSBoyle@users.noreply.github.com> Date: Tue, 14 Mar 2023 22:16:45 +0000 Subject: [PATCH 105/280] Rename redundant enum tests so that they run (#102535) --- Lib/test/test_enum.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index 2b14590b2c21af..a11bb441f06e8e 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -4579,15 +4579,14 @@ class Double(Enum): TWO = 2 self.assertEqual(Double.__doc__, None) - - def test_doc_1(self): + def test_doc_3(self): class Triple(Enum): ONE = 1 TWO = 2 THREE = 3 self.assertEqual(Triple.__doc__, None) - def test_doc_1(self): + def test_doc_4(self): class Quadruple(Enum): ONE = 1 TWO = 2 From fedee27a1f88fb7eac90ecd025c80d164753566b Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Tue, 14 Mar 2023 22:38:15 +0000 Subject: [PATCH 106/280] gh-101578: mention in what's new in 3.12 that exceptions are now normalized before stored (#102702) --- Doc/whatsnew/3.12.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 9f33dbc808ddc0..217ffec1ee1007 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -982,6 +982,11 @@ Porting to Python 3.12 effects, these side effects are no longer duplicated. (Contributed by Victor Stinner in :gh:`98724`.) +* The interpreter's error indicator is now always normalized. This means + that :c:func:`PyErr_SetObject`, :c:func:`PyErr_SetString` and the other + functions that set the error indicator now normalize the exception + before storing it. (Contributed by Mark Shannon in :gh:`101578`.) + Deprecated ---------- From 2d5a20cd9e2ad95589a3db95bb52607737118797 Mon Sep 17 00:00:00 2001 From: "Robert Prater (B. Eng)" Date: Tue, 14 Mar 2023 20:03:43 -0400 Subject: [PATCH 107/280] gh-102703: Fix typo in modules tutorial documentation (GH-102707) **Before** This prevents directories with a common name, such as ``string``, unintentionally hiding ... **After** This prevents directories with a common name, such as ``string``, from unintentionally hiding ... --- Doc/tutorial/modules.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/tutorial/modules.rst b/Doc/tutorial/modules.rst index ad70d92994af49..4daafa49a34d2e 100644 --- a/Doc/tutorial/modules.rst +++ b/Doc/tutorial/modules.rst @@ -438,7 +438,7 @@ When importing the package, Python searches through the directories on The :file:`__init__.py` files are required to make Python treat directories containing the file as packages. This prevents directories with a common name, -such as ``string``, unintentionally hiding valid modules that occur later +such as ``string``, from unintentionally hiding valid modules that occur later on the module search path. In the simplest case, :file:`__init__.py` can just be an empty file, but it can also execute initialization code for the package or set the ``__all__`` variable, described later. From 9e47401b23e8dcfb3d19d5466499331e0aba4e5d Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Wed, 15 Mar 2023 00:07:30 +0000 Subject: [PATCH 108/280] gh-102519: Avoid failing tests due to inaccessible volumes (GH-102706) --- Lib/test/test_os.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 253e2a23238f12..42357fef80ec89 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -2683,12 +2683,17 @@ def test_listvolumes(self): def test_listmounts(self): for volume in os.listvolumes(): - mounts = os.listmounts(volume) - self.assertIsInstance(mounts, list) - self.assertSetEqual( - set(mounts), - self.known_mounts & set(mounts), - ) + try: + mounts = os.listmounts(volume) + except OSError as ex: + if support.verbose: + print("Skipping", volume, "because of", ex) + else: + self.assertIsInstance(mounts, list) + self.assertSetEqual( + set(mounts), + self.known_mounts & set(mounts), + ) @unittest.skipUnless(hasattr(os, 'readlink'), 'needs os.readlink()') From b78ead8662d6a71cb170f0eec01ddb2d25e49097 Mon Sep 17 00:00:00 2001 From: JosephSBoyle <48555120+JosephSBoyle@users.noreply.github.com> Date: Wed, 15 Mar 2023 00:33:19 +0000 Subject: [PATCH 109/280] gh-102560 Add docstrings to asyncio.TaskGroup (#102565) --- Lib/asyncio/taskgroups.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py index 911419e1769c17..0fdea3697ece3d 100644 --- a/Lib/asyncio/taskgroups.py +++ b/Lib/asyncio/taskgroups.py @@ -10,7 +10,21 @@ class TaskGroup: + """Asynchronous context manager for managing groups of tasks. + Example use: + + async with asyncio.TaskGroup() as group: + task1 = group.create_task(some_coroutine(...)) + task2 = group.create_task(other_coroutine(...)) + print("Both tasks have completed now.") + + All tasks are awaited when the context manager exits. + + Any exceptions other than `asyncio.CancelledError` raised within + a task will cancel all remaining tasks and wait for them to exit. + The exceptions are then combined and raised as an `ExceptionGroup`. + """ def __init__(self): self._entered = False self._exiting = False @@ -135,6 +149,10 @@ async def __aexit__(self, et, exc, tb): self._errors = None def create_task(self, coro, *, name=None, context=None): + """Create a new task in this group and return it. + + Similar to `asyncio.create_task`. + """ if not self._entered: raise RuntimeError(f"TaskGroup {self!r} has not been entered") if self._exiting and not self._tasks: From 669c82ac5f4f970aef21f7deae3ab822a273a430 Mon Sep 17 00:00:00 2001 From: Andre Hora Date: Tue, 14 Mar 2023 23:36:31 -0300 Subject: [PATCH 110/280] gh-101377: improving test_locale_calendar_formatweekday of calendar (#101378) --------- Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Terry Jan Reedy --- Lib/test/test_calendar.py | 8 ++++++-- .../Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 3d9dcf12f2dad8..ccfbeede0be949 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -568,11 +568,15 @@ def test_locale_calendar_formatweekday(self): try: # formatweekday uses different day names based on the available width. cal = calendar.LocaleTextCalendar(locale='en_US') + # For really short widths, the abbreviated name is truncated. + self.assertEqual(cal.formatweekday(0, 1), "M") + self.assertEqual(cal.formatweekday(0, 2), "Mo") # For short widths, a centered, abbreviated name is used. + self.assertEqual(cal.formatweekday(0, 3), "Mon") self.assertEqual(cal.formatweekday(0, 5), " Mon ") - # For really short widths, even the abbreviated name is truncated. - self.assertEqual(cal.formatweekday(0, 2), "Mo") + self.assertEqual(cal.formatweekday(0, 8), " Mon ") # For long widths, the full day name is used. + self.assertEqual(cal.formatweekday(0, 9), " Monday ") self.assertEqual(cal.formatweekday(0, 10), " Monday ") except locale.Error: raise unittest.SkipTest('cannot set the en_US locale') diff --git a/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst b/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst new file mode 100644 index 00000000000000..a9c19ce060e3ab --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-01-27-18-10-40.gh-issue-101377.IJGpqh.rst @@ -0,0 +1 @@ +Improved test_locale_calendar_formatweekday of calendar. From ff52779c54552f94745df5e1b6075c306c980700 Mon Sep 17 00:00:00 2001 From: Tom Levy Date: Wed, 15 Mar 2023 20:06:32 +1300 Subject: [PATCH 111/280] Remove misformatted exclamation marks in docs (#102694) Remove the exclamation mark from :program:`!foo` in .rst files because it inadvertently shows up in the rendered HTML. (Sphinx's cross-referencing roles use a '!' prefix to suppress hyperlinking[1], but :program: is not a cross-referencing role so the '!' is displayed verbatim.) The exclamation marks in venv.rst were introduced in #98350. See comments [2] and [3] for additional discussion. [1]: https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#cross-referencing-syntax [2]: https://github.com/python/cpython/pull/98350#issuecomment-1285965759 [3]: https://github.com/python/cpython/pull/98350#issuecomment-1286394047 Reported-by: Vinay Sajip --- Doc/library/venv.rst | 4 ++-- Misc/NEWS.d/3.12.0a2.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst index 8eb0b35eaa12df..240ab139838db9 100644 --- a/Doc/library/venv.rst +++ b/Doc/library/venv.rst @@ -61,7 +61,7 @@ running from a virtual environment. A virtual environment may be "activated" using a script in its binary directory (``bin`` on POSIX; ``Scripts`` on Windows). This will prepend that directory to your :envvar:`!PATH`, so that running -:program:`!python` will invoke the environment's Python interpreter +:program:`python` will invoke the environment's Python interpreter and you can run installed scripts without having to use their full path. The invocation of the activation script is platform-specific (:samp:`{}` must be replaced by the path to the directory @@ -84,7 +84,7 @@ containing the virtual environment): +-------------+------------+--------------------------------------------------+ .. versionadded:: 3.4 - :program:`!fish` and :program:`!csh` activation scripts. + :program:`fish` and :program:`csh` activation scripts. .. versionadded:: 3.8 PowerShell activation scripts installed under POSIX for PowerShell Core diff --git a/Misc/NEWS.d/3.12.0a2.rst b/Misc/NEWS.d/3.12.0a2.rst index 117be21a3221b6..d871384903e7cd 100644 --- a/Misc/NEWS.d/3.12.0a2.rst +++ b/Misc/NEWS.d/3.12.0a2.rst @@ -959,7 +959,7 @@ Fix ``make regen-test-levenshtein`` for out-of-tree builds. Don't use vendored ``libmpdec`` headers if :option:`--with-system-libmpdec` is passed to :program:`configure`. Don't use vendored ``libexpat`` headers -if :option:`--with-system-expat` is passed to :program:`!configure`. +if :option:`--with-system-expat` is passed to :program:`configure`. .. From 4de1e653e7c98fdf60c644ff82b95193672872d1 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Wed, 15 Mar 2023 12:33:41 +0300 Subject: [PATCH 112/280] gh-102615: Use `list` instead of `tuple` in `repr` of paramspec (#102637) Co-authored-by: Alex Waygood --- Lib/test/test_typing.py | 45 +++++++++++++++++++ Lib/typing.py | 7 +-- ...-03-13-12-05-55.gh-issue-102615.NcA_ZL.rst | 3 ++ 3 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-03-13-12-05-55.gh-issue-102615.NcA_ZL.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index c17be6cd0bbc4a..89c725cda54f12 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -3809,6 +3809,51 @@ class Y(C[int]): self.assertEqual(Y.__qualname__, 'GenericTests.test_repr_2..Y') + def test_repr_3(self): + T = TypeVar('T') + T1 = TypeVar('T1') + P = ParamSpec('P') + P2 = ParamSpec('P2') + Ts = TypeVarTuple('Ts') + + class MyCallable(Generic[P, T]): + pass + + class DoubleSpec(Generic[P, P2, T]): + pass + + class TsP(Generic[*Ts, P]): + pass + + object_to_expected_repr = { + MyCallable[P, T]: "MyCallable[~P, ~T]", + MyCallable[Concatenate[T1, P], T]: "MyCallable[typing.Concatenate[~T1, ~P], ~T]", + MyCallable[[], bool]: "MyCallable[[], bool]", + MyCallable[[int], bool]: "MyCallable[[int], bool]", + MyCallable[[int, str], bool]: "MyCallable[[int, str], bool]", + MyCallable[[int, list[int]], bool]: "MyCallable[[int, list[int]], bool]", + MyCallable[Concatenate[*Ts, P], T]: "MyCallable[typing.Concatenate[*Ts, ~P], ~T]", + + DoubleSpec[P2, P, T]: "DoubleSpec[~P2, ~P, ~T]", + DoubleSpec[[int], [str], bool]: "DoubleSpec[[int], [str], bool]", + DoubleSpec[[int, int], [str, str], bool]: "DoubleSpec[[int, int], [str, str], bool]", + + TsP[*Ts, P]: "TsP[*Ts, ~P]", + TsP[int, str, list[int], []]: "TsP[int, str, list[int], []]", + TsP[int, [str, list[int]]]: "TsP[int, [str, list[int]]]", + + # These lines are just too long to fit: + MyCallable[Concatenate[*Ts, P], int][int, str, [bool, float]]: + "MyCallable[[int, str, bool, float], int]", + } + + for obj, expected_repr in object_to_expected_repr.items(): + with self.subTest(obj=obj, expected_repr=expected_repr): + self.assertRegex( + repr(obj), + fr"^{re.escape(MyCallable.__module__)}.*\.{re.escape(expected_repr)}$", + ) + def test_eq_1(self): self.assertEqual(Generic, Generic) self.assertEqual(Generic[T], Generic[T]) diff --git a/Lib/typing.py b/Lib/typing.py index 8d40e923bb1d08..ab334395676159 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -230,16 +230,17 @@ def _type_repr(obj): typically enough to uniquely identify a type. For everything else, we fall back on repr(obj). """ - if isinstance(obj, types.GenericAlias): - return repr(obj) if isinstance(obj, type): if obj.__module__ == 'builtins': return obj.__qualname__ return f'{obj.__module__}.{obj.__qualname__}' if obj is ...: - return('...') + return '...' if isinstance(obj, types.FunctionType): return obj.__name__ + if isinstance(obj, tuple): + # Special case for `repr` of types with `ParamSpec`: + return '[' + ', '.join(_type_repr(t) for t in obj) + ']' return repr(obj) diff --git a/Misc/NEWS.d/next/Library/2023-03-13-12-05-55.gh-issue-102615.NcA_ZL.rst b/Misc/NEWS.d/next/Library/2023-03-13-12-05-55.gh-issue-102615.NcA_ZL.rst new file mode 100644 index 00000000000000..333068369bc4f7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-13-12-05-55.gh-issue-102615.NcA_ZL.rst @@ -0,0 +1,3 @@ +Typing: Improve the ``repr`` of generic aliases for classes generic over a +:class:`~typing.ParamSpec`. (Use square brackets to represent a parameter +list.) From 06915ed9a23809993ba26b9ad07634646e5e741b Mon Sep 17 00:00:00 2001 From: Max Bachmann Date: Wed, 15 Mar 2023 13:58:43 +0100 Subject: [PATCH 113/280] gh-102281: Fix potential nullptr dereference + use of uninitialized memory (gh-102282) --- .../2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst | 1 + Modules/getpath.c | 5 ++++- Python/fileutils.c | 6 +++++- 3 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst new file mode 100644 index 00000000000000..b0269dd3d92bd5 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-02-13-49-21.gh-issue-102281.QCuu2N.rst @@ -0,0 +1 @@ +Fix potential nullptr dereference and use of uninitialized memory in fileutils. Patch by Max Bachmann. diff --git a/Modules/getpath.c b/Modules/getpath.c index 2f20521592ce2e..237fe8c0c2c221 100644 --- a/Modules/getpath.c +++ b/Modules/getpath.c @@ -446,7 +446,10 @@ getpath_realpath(PyObject *Py_UNUSED(self) , PyObject *args) if (s) { *s = L'\0'; } - path2 = _Py_normpath(_Py_join_relfile(path, resolved), -1); + path2 = _Py_join_relfile(path, resolved); + if (path2) { + path2 = _Py_normpath(path2, -1); + } PyMem_RawFree((void *)path); path = path2; } diff --git a/Python/fileutils.c b/Python/fileutils.c index 4ac759c45a3a1e..f48b626b444016 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -2233,7 +2233,10 @@ _Py_join_relfile(const wchar_t *dirname, const wchar_t *relfile) } assert(wcslen(dirname) < MAXPATHLEN); assert(wcslen(relfile) < MAXPATHLEN - wcslen(dirname)); - join_relfile(filename, bufsize, dirname, relfile); + if (join_relfile(filename, bufsize, dirname, relfile) < 0) { + PyMem_RawFree(filename); + return NULL; + } return filename; } @@ -2271,6 +2274,7 @@ _Py_find_basename(const wchar_t *filename) wchar_t * _Py_normpath(wchar_t *path, Py_ssize_t size) { + assert(path != NULL); if (!path[0] || size == 0) { return path; } From 939f5a6019e07c102b8247a06047c7f9e5d5838b Mon Sep 17 00:00:00 2001 From: Julien Palard Date: Wed, 15 Mar 2023 16:10:03 +0100 Subject: [PATCH 114/280] gh-101100: Documenting --prefix and --exec-prefix. (GH-102695) Co-authored-by: Erlend E. Aasland --- Doc/c-api/init.rst | 2 +- Doc/c-api/intro.rst | 10 +++++----- Doc/library/sys.rst | 2 +- Doc/using/configure.rst | 16 ++++++++++++++++ Doc/using/unix.rst | 2 +- 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index b50ee3b3803e29..38e324fb6409bc 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -513,7 +513,7 @@ Process-wide parameters program name is ``'/usr/local/bin/python'``, the prefix is ``'/usr/local'``. The returned string points into static storage; the caller should not modify its value. This corresponds to the :makevar:`prefix` variable in the top-level - :file:`Makefile` and the ``--prefix`` argument to the :program:`configure` + :file:`Makefile` and the :option:`--prefix` argument to the :program:`configure` script at build time. The value is available to Python code as ``sys.prefix``. It is only useful on Unix. See also the next function. diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 85eb24a495b640..acd4e033dfbc4b 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -78,19 +78,19 @@ used by extension writers. Structure member names do not have a reserved prefix. The header files are typically installed with Python. On Unix, these are located in the directories :file:`{prefix}/include/pythonversion/` and -:file:`{exec_prefix}/include/pythonversion/`, where :envvar:`prefix` and -:envvar:`exec_prefix` are defined by the corresponding parameters to Python's +:file:`{exec_prefix}/include/pythonversion/`, where :option:`prefix <--prefix>` and +:option:`exec_prefix <--exec-prefix>` are defined by the corresponding parameters to Python's :program:`configure` script and *version* is ``'%d.%d' % sys.version_info[:2]``. On Windows, the headers are installed -in :file:`{prefix}/include`, where :envvar:`prefix` is the installation +in :file:`{prefix}/include`, where ``prefix`` is the installation directory specified to the installer. To include the headers, place both directories (if different) on your compiler's search path for includes. Do *not* place the parent directories on the search path and then use ``#include ``; this will break on multi-platform builds since the platform independent headers under -:envvar:`prefix` include the platform specific headers from -:envvar:`exec_prefix`. +:option:`prefix <--prefix>` include the platform specific headers from +:option:`exec_prefix <--exec-prefix>`. C++ users should note that although the API is defined entirely using C, the header files properly declare the entry points to be ``extern "C"``. As a result, diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 23c5bbed0c6f9c..a53d4908783e15 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1323,7 +1323,7 @@ always available. A string giving the site-specific directory prefix where the platform independent Python files are installed; on Unix, the default is - ``'/usr/local'``. This can be set at build time with the ``--prefix`` + :file:`/usr/local`. This can be set at build time with the :option:`--prefix` argument to the :program:`configure` script. See :ref:`installation_paths` for derived paths. diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 8936bd381c9d97..ce858ab2c8d79e 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -216,6 +216,22 @@ WebAssembly Options Install Options --------------- +.. cmdoption:: --prefix=PREFIX + + Install architecture-independent files in PREFIX. On Unix, it + defaults to :file:`/usr/local`. + + This value can be retrived at runtime using :data:`sys.prefix`. + + As an example, one can use ``--prefix="$HOME/.local/"`` to install + a Python in its home directory. + +.. cmdoption:: --exec-prefix=EPREFIX + + Install architecture-dependent files in EPREFIX, defaults to :option:`--prefix`. + + This value can be retrived at runtime using :data:`sys.exec_prefix`. + .. cmdoption:: --disable-test-modules Don't build nor install test modules, like the :mod:`test` package or the diff --git a/Doc/using/unix.rst b/Doc/using/unix.rst index 24c02c99f871d5..067ff4cce5e48d 100644 --- a/Doc/using/unix.rst +++ b/Doc/using/unix.rst @@ -93,7 +93,7 @@ Python-related paths and files ============================== These are subject to difference depending on local installation conventions; -:envvar:`prefix` (``${prefix}``) and :envvar:`exec_prefix` (``${exec_prefix}``) +:option:`prefix <--prefix>` and :option:`exec_prefix <--exec-prefix>` are installation-dependent and should be interpreted as for GNU software; they may be the same. From 71190acad1e4393c21e89da5c5f105203df2d84d Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Wed, 15 Mar 2023 08:37:36 -0700 Subject: [PATCH 115/280] gh-102654: Insert #line directives in generated_cases.c.h (#102669) This behavior is optional, because in some extreme cases it may just make debugging harder. The tool defaults it to off, but it is on in Makefile.pre.in. Also note that this makes diffs to generated_cases.c.h noisier, since whenever you insert or delete a line in bytecodes.c, all subsequent #line directives will change. --- Makefile.pre.in | 1 + Python/generated_cases.c.h | 6 +- Tools/cases_generator/generate_cases.py | 89 ++++++++++++++++++++----- 3 files changed, 77 insertions(+), 19 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in index 59762165c10036..8f13198e7e34b3 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1485,6 +1485,7 @@ regen-cases: PYTHONPATH=$(srcdir)/Tools/cases_generator \ $(PYTHON_FOR_REGEN) \ $(srcdir)/Tools/cases_generator/generate_cases.py \ + --emit-line-directives \ -o $(srcdir)/Python/generated_cases.c.h.new \ -m $(srcdir)/Python/opcode_metadata.h.new \ $(srcdir)/Python/bytecodes.c diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 2f5726c317eb1b..9fb532209041ce 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -75,7 +75,7 @@ TARGET(LOAD_CONST) { PREDICTED(LOAD_CONST); PyObject *value; - value = GETITEM(frame->f_code->co_consts, oparg); + value = GETITEM(consts, oparg); Py_INCREF(value); STACK_GROW(1); stack_pointer[-1] = value; @@ -149,7 +149,7 @@ oparg = (next_instr++)->op.arg; { PyObject *value; - value = GETITEM(frame->f_code->co_consts, oparg); + value = GETITEM(consts, oparg); Py_INCREF(value); _tmp_1 = value; } @@ -198,7 +198,7 @@ PyObject *_tmp_2; { PyObject *value; - value = GETITEM(frame->f_code->co_consts, oparg); + value = GETITEM(consts, oparg); Py_INCREF(value); _tmp_2 = value; } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 16128dc85a7402..46223c9dee99be 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -15,6 +15,7 @@ from enum import Enum, auto +import lexer as lx import parser from parser import StackEffect from parser import TypeSrcLiteral, TypeSrcConst, TypeSrcLocals, TypeSrcStackInput @@ -87,6 +88,9 @@ arg_parser.add_argument( "-m", "--metadata", type=str, help="Generated metadata", default=DEFAULT_METADATA_OUTPUT ) +arg_parser.add_argument( + "-l", "--emit-line-directives", help="Emit #line directives", action="store_true" +) arg_parser.add_argument( "input", nargs=argparse.REMAINDER, help="Instruction definition file(s)" ) @@ -158,14 +162,35 @@ class Formatter: stream: typing.TextIO prefix: str postfix: str - - def __init__(self, stream: typing.TextIO, indent: int) -> None: + emit_line_directives: bool = False + lineno: int # Next line number, 1-based + filename: str # Slightly improved stream.filename + nominal_lineno: int + nominal_filename: str + + def __init__( + self, stream: typing.TextIO, indent: int, emit_line_directives: bool = False + ) -> None: self.stream = stream self.prefix = " " * indent self.postfix = "" + self.emit_line_directives = emit_line_directives + self.lineno = 1 + # Make filename more user-friendly and less platform-specific + filename = self.stream.name.replace("\\", "/") + if filename.startswith("./"): + filename = filename[2:] + if filename.endswith(".new"): + filename = filename[:-4] + self.filename = filename + self.nominal_lineno = 1 + self.nominal_filename = filename def write_raw(self, s: str) -> None: self.stream.write(s) + newlines = s.count("\n") + self.lineno += newlines + self.nominal_lineno += newlines def emit(self, arg: str) -> None: if arg: @@ -173,6 +198,17 @@ def emit(self, arg: str) -> None: else: self.write_raw("\n") + def set_lineno(self, lineno: int, filename: str) -> None: + if self.emit_line_directives: + if lineno != self.nominal_lineno or filename != self.nominal_filename: + self.emit(f'#line {lineno} "{filename}"') + self.nominal_lineno = lineno + self.nominal_filename = filename + + def reset_lineno(self) -> None: + if self.lineno != self.nominal_lineno or self.filename != self.nominal_filename: + self.set_lineno(self.lineno + 1, self.filename) + @contextlib.contextmanager def indent(self): self.prefix += " " @@ -253,6 +289,7 @@ class Instruction: block: parser.Block block_text: list[str] # Block.text, less curlies, less PREDICT() calls predictions: list[str] # Prediction targets (instruction names) + block_line: int # First line of block in original code # Computed by constructor always_exits: bool @@ -278,7 +315,7 @@ def __init__(self, inst: parser.InstDef): self.kind = inst.kind self.name = inst.name self.block = inst.block - self.block_text, self.check_eval_breaker, self.predictions = \ + self.block_text, self.check_eval_breaker, self.predictions, self.block_line = \ extract_block_text(self.block) self.always_exits = always_exits(self.block_text) self.cache_effects = [ @@ -587,7 +624,13 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None assert dedent <= 0 extra = " " * -dedent names_to_skip = self.unmoved_names | frozenset({UNUSED, "null"}) + offset = 0 + context = self.block.context + assert context != None + filename = context.owner.filename for line in self.block_text: + out.set_lineno(self.block_line + offset, filename) + offset += 1 if m := re.match(r"(\s*)U_INST\((.+)\);\s*$", line): space, label = m.groups() out.emit(f"UOP_{label}();") @@ -618,6 +661,7 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None out.write_raw(f"{space}if ({cond}) goto {label};{out.postfix}\n") elif m := re.match(r"(\s*)DECREF_INPUTS\(\);\s*(?://.*)?$", line): if not self.register: + out.reset_lineno() space = extra + m.group(1) for ieff in self.input_effects: if ieff.name in names_to_skip: @@ -633,6 +677,7 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None out.write_raw(f"{space}Py_{decref}({ieff.name});\n") else: out.write_raw(extra + line.rstrip("\n") + out.postfix + "\n") + out.reset_lineno() InstructionOrCacheEffect = Instruction | parser.CacheEffect @@ -707,6 +752,7 @@ class Analyzer: output_filename: str metadata_filename: str errors: int = 0 + emit_line_directives: bool = False def __init__(self, input_filenames: list[str], output_filename: str, metadata_filename: str): """Read the input file.""" @@ -772,6 +818,10 @@ def parse_file(self, filename: str, instrs_idx: dict[str, int]) -> None: with open(filename) as file: src = file.read() + # Make filename more user-friendly and less platform-specific + filename = filename.replace("\\", "/") + if filename.startswith("./"): + filename = filename[2:] psr = parser.Parser(src, filename=filename) # Skip until begin marker @@ -1220,13 +1270,14 @@ def write_metadata(self) -> None: format_enums = [INSTR_FMT_PREFIX + format for format in sorted(all_formats)] with open(self.metadata_filename, "w") as f: + # Create formatter + self.out = Formatter(f, 0) + # Write provenance header - f.write(f"// This file is generated by {THIS}\n") - f.write(self.from_source_files()) - f.write(f"// Do not edit!\n") + self.out.write_raw(f"// This file is generated by {THIS}\n") + self.out.write_raw(self.from_source_files()) + self.out.write_raw(f"// Do not edit!\n") - # Create formatter; the rest of the code uses this - self.out = Formatter(f, 0) self.write_stack_effect_functions() @@ -1302,13 +1353,13 @@ def write_metadata_for_macro(self, mac: MacroInstruction) -> None: def write_instructions(self) -> None: """Write instructions to output file.""" with open(self.output_filename, "w") as f: - # Write provenance header - f.write(f"// This file is generated by {THIS}\n") - f.write(self.from_source_files()) - f.write(f"// Do not edit!\n") + # Create formatter + self.out = Formatter(f, 8, self.emit_line_directives) - # Create formatter; the rest of the code uses this - self.out = Formatter(f, 8) + # Write provenance header + self.out.write_raw(f"// This file is generated by {THIS}\n") + self.out.write_raw(self.from_source_files()) + self.out.write_raw(f"// Do not edit!\n") # Write and count instructions of all kinds n_instrs = 0 @@ -1478,13 +1529,16 @@ def wrap_super_or_macro(self, up: SuperOrMacroInstruction): self.out.emit(f"DISPATCH();") -def extract_block_text(block: parser.Block) -> tuple[list[str], bool, list[str]]: +def extract_block_text(block: parser.Block) -> tuple[list[str], bool, list[str], int]: # Get lines of text with proper dedent blocklines = block.text.splitlines(True) + first_token: lx.Token = block.tokens[0] # IndexError means the context is broken + block_line = first_token.begin[0] # Remove blank lines from both ends while blocklines and not blocklines[0].strip(): blocklines.pop(0) + block_line += 1 while blocklines and not blocklines[-1].strip(): blocklines.pop() @@ -1493,6 +1547,7 @@ def extract_block_text(block: parser.Block) -> tuple[list[str], bool, list[str]] assert blocklines and blocklines[-1].strip() == "}" blocklines.pop() blocklines.pop(0) + block_line += 1 # Remove trailing blank lines while blocklines and not blocklines[-1].strip(): @@ -1512,7 +1567,7 @@ def extract_block_text(block: parser.Block) -> tuple[list[str], bool, list[str]] predictions.insert(0, m.group(1)) blocklines.pop() - return blocklines, check_eval_breaker, predictions + return blocklines, check_eval_breaker, predictions, block_line def always_exits(lines: list[str]) -> bool: @@ -1548,6 +1603,8 @@ def main(): if len(args.input) == 0: args.input.append(DEFAULT_INPUT) a = Analyzer(args.input, args.output, args.metadata) # Raises OSError if input unreadable + if args.emit_line_directives: + a.emit_line_directives = True a.parse() # Raises SyntaxError on failure a.analyze() # Prints messages and sets a.errors on failure if a.errors: From 7204c41d7df1b5c1669d20df998e035ceadbb034 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Wed, 15 Mar 2023 18:19:07 +0000 Subject: [PATCH 116/280] Exclude `ceval.c` from the C-analyzer tool (#102735) The "check if generated files are up to date" CI check appears to be currently failing on all PRs (but not on pushes to main) See, for example: - https://github.com/python/cpython/pull/94468 - https://github.com/python/cpython/pull/94468 - https://github.com/python/cpython/pull/102731 This appears to be because the C-analyzer tool doesn't like the `#line` directives introduced in https://github.com/python/cpython/commit/70185de1abfe428049a5c43d58fcb656b46db96c. I'm advised by the message printed to the terminal in https://github.com/python/cpython/actions/runs/4428706945/jobs/7768216988#step:14:84 that this is the appropriate short-term fix! --- Tools/c-analyzer/cpython/_parser.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index 6da4fbbf4224f1..a2911e030ffee1 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -91,10 +91,15 @@ def clean_lines(text): # XXX Fix the parser. EXCLUDED += clean_lines(''' # The tool should be able to parse these... + # The problem with xmlparse.c is that something # has gone wrong where # we handle "maybe inline actual" # in Tools/c-analyzer/c_parser/parser/_global.py. Modules/expat/xmlparse.c + +# The parser doesn't like the #line directives +# that originate from generated_cases.c.h +Python/ceval.c ''') INCL_DIRS = clean_lines(''' From b537248ce7e294e8adaf4c864695a2906f55e6f7 Mon Sep 17 00:00:00 2001 From: Martin Breuss Date: Wed, 15 Mar 2023 20:18:18 +0100 Subject: [PATCH 117/280] Fix typo in code comment (#102726) --- Lib/test/test_traceback.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 92c5a000585855..7ef93b3f0ac332 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -2987,7 +2987,7 @@ class MyClass: def test_getattr_suggestions_do_not_trigger_for_big_dicts(self): class A: blech = None - # A class with a very big __dict__ will not be consider + # A class with a very big __dict__ will not be considered # for suggestions. for index in range(2000): setattr(A, f"index_{index}", None) From 824309ed60032609140df2e6f00a32c93c6b1183 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Wed, 15 Mar 2023 15:15:23 -0500 Subject: [PATCH 118/280] Simplify and speed-up math.hypot() and math.dist() (GH-102734) --- Modules/mathmodule.c | 293 ++++++++++++++++++++----------------------- 1 file changed, 139 insertions(+), 154 deletions(-) diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 544560e8322c72..ae9e3211c072d8 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -92,6 +92,113 @@ get_math_module_state(PyObject *module) return (math_module_state *)state; } +/* +Double and triple length extended precision algorithms from: + + Accurate Sum and Dot Product + by Takeshi Ogita, Siegfried M. Rump, and Shin’Ichi Oishi + https://doi.org/10.1137/030601818 + https://www.tuhh.de/ti3/paper/rump/OgRuOi05.pdf + +*/ + +typedef struct{ double hi; double lo; } DoubleLength; + +static DoubleLength +dl_fast_sum(double a, double b) +{ + /* Algorithm 1.1. Compensated summation of two floating point numbers. */ + assert(fabs(a) >= fabs(b)); + double x = a + b; + double y = (a - x) + b; + return (DoubleLength) {x, y}; +} + +static DoubleLength +dl_sum(double a, double b) +{ + /* Algorithm 3.1 Error-free transformation of the sum */ + double x = a + b; + double z = x - a; + double y = (a - (x - z)) + (b - z); + return (DoubleLength) {x, y}; +} + +#ifndef UNRELIABLE_FMA + +static DoubleLength +dl_mul(double x, double y) +{ + /* Algorithm 3.5. Error-free transformation of a product */ + double z = x * y; + double zz = fma(x, y, -z); + return (DoubleLength) {z, zz}; +} + +#else + +/* + The default implementation of dl_mul() depends on the C math library + having an accurate fma() function as required by § 7.12.13.1 of the + C99 standard. + + The UNRELIABLE_FMA option is provided as a slower but accurate + alternative for builds where the fma() function is found wanting. + The speed penalty may be modest (17% slower on an Apple M1 Max), + so don't hesitate to enable this build option. + + The algorithms are from the T. J. Dekker paper: + A Floating-Point Technique for Extending the Available Precision + https://csclub.uwaterloo.ca/~pbarfuss/dekker1971.pdf +*/ + +static DoubleLength +dl_split(double x) { + // Dekker (5.5) and (5.6). + double t = x * 134217729.0; // Veltkamp constant = 2.0 ** 27 + 1 + double hi = t - (t - x); + double lo = x - hi; + return (DoubleLength) {hi, lo}; +} + +static DoubleLength +dl_mul(double x, double y) +{ + // Dekker (5.12) and mul12() + DoubleLength xx = dl_split(x); + DoubleLength yy = dl_split(y); + double p = xx.hi * yy.hi; + double q = xx.hi * yy.lo + xx.lo * yy.hi; + double z = p + q; + double zz = p - z + q + xx.lo * yy.lo; + return (DoubleLength) {z, zz}; +} + +#endif + +typedef struct { double hi; double lo; double tiny; } TripleLength; + +static const TripleLength tl_zero = {0.0, 0.0, 0.0}; + +static TripleLength +tl_fma(double x, double y, TripleLength total) +{ + /* Algorithm 5.10 with SumKVert for K=3 */ + DoubleLength pr = dl_mul(x, y); + DoubleLength sm = dl_sum(total.hi, pr.hi); + DoubleLength r1 = dl_sum(total.lo, pr.lo); + DoubleLength r2 = dl_sum(r1.hi, sm.lo); + return (TripleLength) {sm.hi, r2.hi, total.tiny + r1.lo + r2.lo}; +} + +static double +tl_to_d(TripleLength total) +{ + DoubleLength last = dl_sum(total.lo, total.hi); + return total.tiny + last.lo + last.hi; +} + + /* sin(pi*x), giving accurate results for all finite x (especially x integral or close to an integer). This is here for use in the @@ -2301,6 +2408,7 @@ that are almost always correctly rounded, four techniques are used: * lossless scaling using a power-of-two scaling factor * accurate squaring using Veltkamp-Dekker splitting [1] + or an equivalent with an fma() call * compensated summation using a variant of the Neumaier algorithm [2] * differential correction of the square root [3] @@ -2359,14 +2467,21 @@ algorithm, effectively doubling the number of accurate bits. This technique is used in Dekker's SQRT2 algorithm and again in Borges' ALGORITHM 4 and 5. -Without proof for all cases, hypot() cannot claim to be always -correctly rounded. However for n <= 1000, prior to the final addition -that rounds the overall result, the internal accuracy of "h" together -with its correction of "x / (2.0 * h)" is at least 100 bits. [6] -Also, hypot() was tested against a Decimal implementation with -prec=300. After 100 million trials, no incorrectly rounded examples -were found. In addition, perfect commutativity (all permutations are -exactly equal) was verified for 1 billion random inputs with n=5. [7] +The hypot() function is faithfully rounded (less than 1 ulp error) +and usually correctly rounded (within 1/2 ulp). The squaring +step is exact. The Neumaier summation computes as if in doubled +precision (106 bits) and has the advantage that its input squares +are non-negative so that the condition number of the sum is one. +The square root with a differential correction is likewise computed +as if in double precision. + +For n <= 1000, prior to the final addition that rounds the overall +result, the internal accuracy of "h" together with its correction of +"x / (2.0 * h)" is at least 100 bits. [6] Also, hypot() was tested +against a Decimal implementation with prec=300. After 100 million +trials, no incorrectly rounded examples were found. In addition, +perfect commutativity (all permutations are exactly equal) was +verified for 1 billion random inputs with n=5. [7] References: @@ -2383,9 +2498,8 @@ exactly equal) was verified for 1 billion random inputs with n=5. [7] static inline double vector_norm(Py_ssize_t n, double *vec, double max, int found_nan) { - const double T27 = 134217729.0; /* ldexp(1.0, 27) + 1.0) */ - double x, scale, oldcsum, csum = 1.0, frac1 = 0.0, frac2 = 0.0, frac3 = 0.0; - double t, hi, lo, h; + double x, h, scale, oldcsum, csum = 1.0, frac1 = 0.0, frac2 = 0.0; + DoubleLength pr, sm; int max_e; Py_ssize_t i; @@ -2410,54 +2524,21 @@ vector_norm(Py_ssize_t n, double *vec, double max, int found_nan) x *= scale; assert(fabs(x) < 1.0); - t = x * T27; - hi = t - (t - x); - lo = x - hi; - assert(hi + lo == x); - - x = hi * hi; - assert(x <= 1.0); - assert(fabs(csum) >= fabs(x)); - oldcsum = csum; - csum += x; - frac1 += (oldcsum - csum) + x; - - x = 2.0 * hi * lo; - assert(fabs(csum) >= fabs(x)); - oldcsum = csum; - csum += x; - frac2 += (oldcsum - csum) + x; - - assert(csum + lo * lo == csum); - frac3 += lo * lo; - } - h = sqrt(csum - 1.0 + (frac1 + frac2 + frac3)); - - x = h; - t = x * T27; - hi = t - (t - x); - lo = x - hi; - assert (hi + lo == x); + pr = dl_mul(x, x); + assert(pr.hi <= 1.0); - x = -hi * hi; - assert(fabs(csum) >= fabs(x)); - oldcsum = csum; - csum += x; - frac1 += (oldcsum - csum) + x; - - x = -2.0 * hi * lo; - assert(fabs(csum) >= fabs(x)); - oldcsum = csum; - csum += x; - frac2 += (oldcsum - csum) + x; - - x = -lo * lo; - assert(fabs(csum) >= fabs(x)); - oldcsum = csum; - csum += x; - frac3 += (oldcsum - csum) + x; - - x = csum - 1.0 + (frac1 + frac2 + frac3); + sm = dl_fast_sum(csum, pr.hi); + csum = sm.hi; + frac1 += pr.lo; + frac2 += sm.lo; + } + h = sqrt(csum - 1.0 + (frac1 + frac2)); + pr = dl_mul(-h, h); + sm = dl_fast_sum(csum, pr.hi); + csum = sm.hi; + frac1 += pr.lo; + frac2 += sm.lo; + x = csum - 1.0 + (frac1 + frac2); return (h + x / (2.0 * h)) / scale; } /* When max_e < -1023, ldexp(1.0, -max_e) overflows. @@ -2646,102 +2727,6 @@ long_add_would_overflow(long a, long b) return (a > 0) ? (b > LONG_MAX - a) : (b < LONG_MIN - a); } -/* -Double and triple length extended precision algorithms from: - - Accurate Sum and Dot Product - by Takeshi Ogita, Siegfried M. Rump, and Shin’Ichi Oishi - https://doi.org/10.1137/030601818 - https://www.tuhh.de/ti3/paper/rump/OgRuOi05.pdf - -*/ - -typedef struct{ double hi; double lo; } DoubleLength; - -static DoubleLength -dl_sum(double a, double b) -{ - /* Algorithm 3.1 Error-free transformation of the sum */ - double x = a + b; - double z = x - a; - double y = (a - (x - z)) + (b - z); - return (DoubleLength) {x, y}; -} - -#ifndef UNRELIABLE_FMA - -static DoubleLength -dl_mul(double x, double y) -{ - /* Algorithm 3.5. Error-free transformation of a product */ - double z = x * y; - double zz = fma(x, y, -z); - return (DoubleLength) {z, zz}; -} - -#else - -/* - The default implementation of dl_mul() depends on the C math library - having an accurate fma() function as required by § 7.12.13.1 of the - C99 standard. - - The UNRELIABLE_FMA option is provided as a slower but accurate - alternative for builds where the fma() function is found wanting. - The speed penalty may be modest (17% slower on an Apple M1 Max), - so don't hesitate to enable this build option. - - The algorithms are from the T. J. Dekker paper: - A Floating-Point Technique for Extending the Available Precision - https://csclub.uwaterloo.ca/~pbarfuss/dekker1971.pdf -*/ - -static DoubleLength -dl_split(double x) { - // Dekker (5.5) and (5.6). - double t = x * 134217729.0; // Veltkamp constant = 2.0 ** 27 + 1 - double hi = t - (t - x); - double lo = x - hi; - return (DoubleLength) {hi, lo}; -} - -static DoubleLength -dl_mul(double x, double y) -{ - // Dekker (5.12) and mul12() - DoubleLength xx = dl_split(x); - DoubleLength yy = dl_split(y); - double p = xx.hi * yy.hi; - double q = xx.hi * yy.lo + xx.lo * yy.hi; - double z = p + q; - double zz = p - z + q + xx.lo * yy.lo; - return (DoubleLength) {z, zz}; -} - -#endif - -typedef struct { double hi; double lo; double tiny; } TripleLength; - -static const TripleLength tl_zero = {0.0, 0.0, 0.0}; - -static TripleLength -tl_fma(double x, double y, TripleLength total) -{ - /* Algorithm 5.10 with SumKVert for K=3 */ - DoubleLength pr = dl_mul(x, y); - DoubleLength sm = dl_sum(total.hi, pr.hi); - DoubleLength r1 = dl_sum(total.lo, pr.lo); - DoubleLength r2 = dl_sum(r1.hi, sm.lo); - return (TripleLength) {sm.hi, r2.hi, total.tiny + r1.lo + r2.lo}; -} - -static double -tl_to_d(TripleLength total) -{ - DoubleLength last = dl_sum(total.lo, total.hi); - return total.tiny + last.lo + last.hi; -} - /*[clinic input] math.sumprod From bc1ff3a48934ddfca6772256195a69bb1143028d Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Wed, 15 Mar 2023 21:25:31 +0000 Subject: [PATCH 119/280] gh-102738: remove from cases generator the code related to register instructions (#102739) --- .../pycore_global_objects_fini_generated.h | 1 + Include/internal/pycore_global_strings.h | 1 + .../internal/pycore_runtime_init_generated.h | 1 + .../internal/pycore_unicodeobject_generated.h | 3 + Python/opcode_metadata.h | 398 +++++++++--------- Tools/cases_generator/generate_cases.py | 190 +++------ 6 files changed, 267 insertions(+), 327 deletions(-) diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 4b12ae523c3260..14dfd9ea5823ed 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -995,6 +995,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(kw2)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(lambda)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last_exc)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last_node)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last_traceback)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(last_type)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 17fb9ffbbf9f11..6f430bb25eb8d3 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -481,6 +481,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(kw2) STRUCT_FOR_ID(lambda) STRUCT_FOR_ID(last) + STRUCT_FOR_ID(last_exc) STRUCT_FOR_ID(last_node) STRUCT_FOR_ID(last_traceback) STRUCT_FOR_ID(last_type) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index b240be57369d9d..0452c4c61551de 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -987,6 +987,7 @@ extern "C" { INIT_ID(kw2), \ INIT_ID(lambda), \ INIT_ID(last), \ + INIT_ID(last_exc), \ INIT_ID(last_node), \ INIT_ID(last_traceback), \ INIT_ID(last_type), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index fea9b6dbb1a75f..0a8865942e6d5b 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1296,6 +1296,9 @@ _PyUnicode_InitStaticStrings(void) { string = &_Py_ID(last); assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); + string = &_Py_ID(last_exc); + assert(_PyUnicode_CheckConsistency(string, 1)); + PyUnicode_InternInPlace(&string); string = &_Py_ID(last_node); assert(_PyUnicode_CheckConsistency(string, 1)); PyUnicode_InternInPlace(&string); diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 24a861100bca47..5a00fe70a7c0bf 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -815,12 +815,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { } #endif -enum Direction { DIR_NONE, DIR_READ, DIR_WRITE }; enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC0, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; struct opcode_metadata { - enum Direction dir_op1; - enum Direction dir_op2; - enum Direction dir_op3; bool valid_entry; enum InstructionFormat instr_format; }; @@ -829,202 +825,202 @@ struct opcode_metadata { extern const struct opcode_metadata _PyOpcode_opcode_metadata[256]; #else const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { - [NOP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [RESUME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [RESUME_QUICK] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_CLOSURE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_FAST_CHECK] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_FAST_NO_INCREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_CONST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_FAST_BOXED_UNBOXED] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_FAST_UNBOXED_BOXED] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_FAST_UNBOXED_UNBOXED] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_FAST__LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [LOAD_FAST__LOAD_CONST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [STORE_FAST__LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [STORE_FAST__STORE_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [LOAD_CONST__LOAD_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBIB }, - [POP_TOP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [POP_TOP_NO_DECREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [PUSH_NULL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [END_FOR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [UNARY_NEGATIVE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [UNARY_NOT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [UNARY_INVERT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BINARY_OP_MULTIPLY_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_MULTIPLY_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_SUBTRACT_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_SUBTRACT_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_ADD_UNICODE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_OP_INPLACE_ADD_UNICODE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BINARY_OP_ADD_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_CHECK_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [UNARY_CHECK_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BINARY_OP_ADD_FLOAT_UNBOXED] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [UNBOX_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BOX_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BINARY_OP_ADD_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [BINARY_CHECK_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BINARY_OP_ADD_INT_REST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BINARY_SUBSCR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [BINARY_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [STORE_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BINARY_SUBSCR_LIST_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [BINARY_SUBSCR_TUPLE_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [BINARY_SUBSCR_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [BINARY_SUBSCR_GETITEM] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [LIST_APPEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [SET_ADD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_SUBSCR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [STORE_SUBSCR_LIST_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [STORE_SUBSCR_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [DELETE_SUBSCR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [CALL_INTRINSIC_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL_INTRINSIC_2] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [RAISE_VARARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [INTERPRETER_EXIT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [RETURN_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [RETURN_CONST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [GET_AITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [GET_ANEXT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [GET_AWAITABLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [SEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [SEND_GEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [YIELD_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [POP_EXCEPT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [RERAISE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [END_ASYNC_FOR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [CLEANUP_THROW] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [LOAD_ASSERTION_ERROR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [LOAD_BUILD_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [STORE_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DELETE_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [UNPACK_SEQUENCE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [UNPACK_SEQUENCE_TWO_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [UNPACK_SEQUENCE_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [UNPACK_SEQUENCE_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [UNPACK_EX] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_ATTR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [DELETE_ATTR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_GLOBAL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DELETE_GLOBAL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_GLOBAL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [LOAD_GLOBAL_MODULE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [LOAD_GLOBAL_BUILTIN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [DELETE_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [MAKE_CELL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DELETE_DEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_CLASSDEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_DEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [STORE_DEREF] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [COPY_FREE_VARS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_STRING] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LIST_EXTEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [SET_UPDATE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_SET] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BUILD_MAP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [SETUP_ANNOTATIONS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BUILD_CONST_KEY_MAP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DICT_UPDATE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [DICT_MERGE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [MAP_ADD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [LOAD_ATTR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_INSTANCE_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_MODULE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_WITH_HINT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_SLOT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_PROPERTY] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [STORE_ATTR_INSTANCE_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [STORE_ATTR_WITH_HINT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [STORE_ATTR_SLOT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC000 }, - [COMPARE_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [COMPARE_AND_BRANCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_FLOAT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_INT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_STR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC0 }, - [IS_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CONTAINS_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CHECK_EG_MATCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [CHECK_EXC_MATCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [IMPORT_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [IMPORT_FROM] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [JUMP_FORWARD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [JUMP_BACKWARD] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [JUMP_BACKWARD_QUICK] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [POP_JUMP_IF_FALSE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BB_TEST_POP_IF_FALSE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [POP_JUMP_IF_TRUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BB_TEST_POP_IF_TRUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [POP_JUMP_IF_NOT_NONE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BB_TEST_POP_IF_NOT_NONE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [POP_JUMP_IF_NONE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BB_TEST_POP_IF_NONE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [JUMP_IF_FALSE_OR_POP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BB_TEST_IF_FALSE_OR_POP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [JUMP_IF_TRUE_OR_POP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BB_TEST_IF_TRUE_OR_POP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [JUMP_BACKWARD_NO_INTERRUPT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [GET_LEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [MATCH_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [MATCH_MAPPING] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [MATCH_SEQUENCE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [MATCH_KEYS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [GET_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [GET_YIELD_FROM_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [FOR_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [BB_TEST_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, - [FOR_ITER_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [FOR_ITER_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [FOR_ITER_RANGE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [FOR_ITER_GEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [BEFORE_ASYNC_WITH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BEFORE_WITH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [WITH_EXCEPT_START] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [PUSH_EXC_INFO] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [LOAD_ATTR_METHOD_WITH_VALUES] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_METHOD_NO_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [LOAD_ATTR_METHOD_LAZY_DICT] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC00000000 }, - [KW_NAMES] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CALL] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_BOUND_METHOD_EXACT_ARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_PY_EXACT_ARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_PY_WITH_DEFAULTS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_TYPE_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_STR_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_TUPLE_1] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_BUILTIN_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_BUILTIN_O] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_BUILTIN_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_LEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_ISINSTANCE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_LIST_APPEND] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_METHOD_DESCRIPTOR_O] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 }, - [CALL_FUNCTION_EX] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [MAKE_FUNCTION] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [RETURN_GENERATOR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BUILD_SLICE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [FORMAT_VALUE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [COPY] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [BINARY_OP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [SWAP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [EXTENDED_ARG] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [CACHE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [BB_BRANCH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [BB_BRANCH_IF_FLAG_UNSET] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [BB_JUMP_IF_FLAG_UNSET] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [BB_BRANCH_IF_FLAG_SET] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [BB_JUMP_IF_FLAG_SET] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, - [BB_JUMP_BACKWARD_LAZY] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [NOP] = { true, INSTR_FMT_IX }, + [RESUME] = { true, INSTR_FMT_IX }, + [RESUME_QUICK] = { true, INSTR_FMT_IB }, + [LOAD_CLOSURE] = { true, INSTR_FMT_IB }, + [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB }, + [LOAD_FAST] = { true, INSTR_FMT_IB }, + [LOAD_FAST_NO_INCREF] = { true, INSTR_FMT_IB }, + [LOAD_CONST] = { true, INSTR_FMT_IB }, + [STORE_FAST] = { true, INSTR_FMT_IB }, + [STORE_FAST_BOXED_UNBOXED] = { true, INSTR_FMT_IB }, + [STORE_FAST_UNBOXED_BOXED] = { true, INSTR_FMT_IB }, + [STORE_FAST_UNBOXED_UNBOXED] = { true, INSTR_FMT_IB }, + [LOAD_FAST__LOAD_FAST] = { true, INSTR_FMT_IBIB }, + [LOAD_FAST__LOAD_CONST] = { true, INSTR_FMT_IBIB }, + [STORE_FAST__LOAD_FAST] = { true, INSTR_FMT_IBIB }, + [STORE_FAST__STORE_FAST] = { true, INSTR_FMT_IBIB }, + [LOAD_CONST__LOAD_FAST] = { true, INSTR_FMT_IBIB }, + [POP_TOP] = { true, INSTR_FMT_IX }, + [POP_TOP_NO_DECREF] = { true, INSTR_FMT_IX }, + [PUSH_NULL] = { true, INSTR_FMT_IX }, + [END_FOR] = { true, INSTR_FMT_IB }, + [UNARY_NEGATIVE] = { true, INSTR_FMT_IX }, + [UNARY_NOT] = { true, INSTR_FMT_IX }, + [UNARY_INVERT] = { true, INSTR_FMT_IX }, + [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC }, + [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC }, + [BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IXC }, + [BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IXC }, + [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC }, + [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IX }, + [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC }, + [BINARY_CHECK_FLOAT] = { true, INSTR_FMT_IX }, + [UNARY_CHECK_FLOAT] = { true, INSTR_FMT_IB }, + [BINARY_OP_ADD_FLOAT_UNBOXED] = { true, INSTR_FMT_IX }, + [UNBOX_FLOAT] = { true, INSTR_FMT_IB }, + [BOX_FLOAT] = { true, INSTR_FMT_IB }, + [BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC }, + [BINARY_CHECK_INT] = { true, INSTR_FMT_IX }, + [BINARY_OP_ADD_INT_REST] = { true, INSTR_FMT_IX }, + [BINARY_SUBSCR] = { true, INSTR_FMT_IXC000 }, + [BINARY_SLICE] = { true, INSTR_FMT_IX }, + [STORE_SLICE] = { true, INSTR_FMT_IX }, + [BINARY_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC000 }, + [BINARY_SUBSCR_TUPLE_INT] = { true, INSTR_FMT_IXC000 }, + [BINARY_SUBSCR_DICT] = { true, INSTR_FMT_IXC000 }, + [BINARY_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC000 }, + [LIST_APPEND] = { true, INSTR_FMT_IB }, + [SET_ADD] = { true, INSTR_FMT_IB }, + [STORE_SUBSCR] = { true, INSTR_FMT_IXC }, + [STORE_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC }, + [STORE_SUBSCR_DICT] = { true, INSTR_FMT_IXC }, + [DELETE_SUBSCR] = { true, INSTR_FMT_IX }, + [CALL_INTRINSIC_1] = { true, INSTR_FMT_IB }, + [CALL_INTRINSIC_2] = { true, INSTR_FMT_IB }, + [RAISE_VARARGS] = { true, INSTR_FMT_IB }, + [INTERPRETER_EXIT] = { true, INSTR_FMT_IX }, + [RETURN_VALUE] = { true, INSTR_FMT_IX }, + [RETURN_CONST] = { true, INSTR_FMT_IB }, + [GET_AITER] = { true, INSTR_FMT_IX }, + [GET_ANEXT] = { true, INSTR_FMT_IX }, + [GET_AWAITABLE] = { true, INSTR_FMT_IB }, + [SEND] = { true, INSTR_FMT_IBC }, + [SEND_GEN] = { true, INSTR_FMT_IBC }, + [YIELD_VALUE] = { true, INSTR_FMT_IX }, + [POP_EXCEPT] = { true, INSTR_FMT_IX }, + [RERAISE] = { true, INSTR_FMT_IB }, + [END_ASYNC_FOR] = { true, INSTR_FMT_IX }, + [CLEANUP_THROW] = { true, INSTR_FMT_IX }, + [LOAD_ASSERTION_ERROR] = { true, INSTR_FMT_IX }, + [LOAD_BUILD_CLASS] = { true, INSTR_FMT_IX }, + [STORE_NAME] = { true, INSTR_FMT_IB }, + [DELETE_NAME] = { true, INSTR_FMT_IB }, + [UNPACK_SEQUENCE] = { true, INSTR_FMT_IBC }, + [UNPACK_SEQUENCE_TWO_TUPLE] = { true, INSTR_FMT_IBC }, + [UNPACK_SEQUENCE_TUPLE] = { true, INSTR_FMT_IBC }, + [UNPACK_SEQUENCE_LIST] = { true, INSTR_FMT_IBC }, + [UNPACK_EX] = { true, INSTR_FMT_IB }, + [STORE_ATTR] = { true, INSTR_FMT_IBC000 }, + [DELETE_ATTR] = { true, INSTR_FMT_IB }, + [STORE_GLOBAL] = { true, INSTR_FMT_IB }, + [DELETE_GLOBAL] = { true, INSTR_FMT_IB }, + [LOAD_NAME] = { true, INSTR_FMT_IB }, + [LOAD_GLOBAL] = { true, INSTR_FMT_IBC000 }, + [LOAD_GLOBAL_MODULE] = { true, INSTR_FMT_IBC000 }, + [LOAD_GLOBAL_BUILTIN] = { true, INSTR_FMT_IBC000 }, + [DELETE_FAST] = { true, INSTR_FMT_IB }, + [MAKE_CELL] = { true, INSTR_FMT_IB }, + [DELETE_DEREF] = { true, INSTR_FMT_IB }, + [LOAD_CLASSDEREF] = { true, INSTR_FMT_IB }, + [LOAD_DEREF] = { true, INSTR_FMT_IB }, + [STORE_DEREF] = { true, INSTR_FMT_IB }, + [COPY_FREE_VARS] = { true, INSTR_FMT_IB }, + [BUILD_STRING] = { true, INSTR_FMT_IB }, + [BUILD_TUPLE] = { true, INSTR_FMT_IB }, + [BUILD_LIST] = { true, INSTR_FMT_IB }, + [LIST_EXTEND] = { true, INSTR_FMT_IB }, + [SET_UPDATE] = { true, INSTR_FMT_IB }, + [BUILD_SET] = { true, INSTR_FMT_IB }, + [BUILD_MAP] = { true, INSTR_FMT_IB }, + [SETUP_ANNOTATIONS] = { true, INSTR_FMT_IX }, + [BUILD_CONST_KEY_MAP] = { true, INSTR_FMT_IB }, + [DICT_UPDATE] = { true, INSTR_FMT_IB }, + [DICT_MERGE] = { true, INSTR_FMT_IB }, + [MAP_ADD] = { true, INSTR_FMT_IB }, + [LOAD_ATTR] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000 }, + [STORE_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IXC000 }, + [STORE_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC000 }, + [STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC000 }, + [COMPARE_OP] = { true, INSTR_FMT_IBC }, + [COMPARE_AND_BRANCH] = { true, INSTR_FMT_IBC0 }, + [COMPARE_AND_BRANCH_FLOAT] = { true, INSTR_FMT_IBC0 }, + [COMPARE_AND_BRANCH_INT] = { true, INSTR_FMT_IBC0 }, + [COMPARE_AND_BRANCH_STR] = { true, INSTR_FMT_IBC0 }, + [IS_OP] = { true, INSTR_FMT_IB }, + [CONTAINS_OP] = { true, INSTR_FMT_IB }, + [CHECK_EG_MATCH] = { true, INSTR_FMT_IX }, + [CHECK_EXC_MATCH] = { true, INSTR_FMT_IX }, + [IMPORT_NAME] = { true, INSTR_FMT_IB }, + [IMPORT_FROM] = { true, INSTR_FMT_IB }, + [JUMP_FORWARD] = { true, INSTR_FMT_IB }, + [JUMP_BACKWARD] = { true, INSTR_FMT_IX }, + [JUMP_BACKWARD_QUICK] = { true, INSTR_FMT_IB }, + [POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB }, + [BB_TEST_POP_IF_FALSE] = { true, INSTR_FMT_IX }, + [POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB }, + [BB_TEST_POP_IF_TRUE] = { true, INSTR_FMT_IX }, + [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB }, + [BB_TEST_POP_IF_NOT_NONE] = { true, INSTR_FMT_IX }, + [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB }, + [BB_TEST_POP_IF_NONE] = { true, INSTR_FMT_IX }, + [JUMP_IF_FALSE_OR_POP] = { true, INSTR_FMT_IB }, + [BB_TEST_IF_FALSE_OR_POP] = { true, INSTR_FMT_IX }, + [JUMP_IF_TRUE_OR_POP] = { true, INSTR_FMT_IB }, + [BB_TEST_IF_TRUE_OR_POP] = { true, INSTR_FMT_IX }, + [JUMP_BACKWARD_NO_INTERRUPT] = { true, INSTR_FMT_IB }, + [GET_LEN] = { true, INSTR_FMT_IX }, + [MATCH_CLASS] = { true, INSTR_FMT_IB }, + [MATCH_MAPPING] = { true, INSTR_FMT_IX }, + [MATCH_SEQUENCE] = { true, INSTR_FMT_IX }, + [MATCH_KEYS] = { true, INSTR_FMT_IX }, + [GET_ITER] = { true, INSTR_FMT_IX }, + [GET_YIELD_FROM_ITER] = { true, INSTR_FMT_IX }, + [FOR_ITER] = { true, INSTR_FMT_IBC }, + [BB_TEST_ITER] = { true, INSTR_FMT_IXC }, + [FOR_ITER_LIST] = { true, INSTR_FMT_IBC }, + [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC }, + [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC }, + [FOR_ITER_GEN] = { true, INSTR_FMT_IBC }, + [BEFORE_ASYNC_WITH] = { true, INSTR_FMT_IX }, + [BEFORE_WITH] = { true, INSTR_FMT_IX }, + [WITH_EXCEPT_START] = { true, INSTR_FMT_IX }, + [PUSH_EXC_INFO] = { true, INSTR_FMT_IX }, + [LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000 }, + [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000 }, + [KW_NAMES] = { true, INSTR_FMT_IB }, + [CALL] = { true, INSTR_FMT_IBC000 }, + [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC000 }, + [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC000 }, + [CALL_PY_WITH_DEFAULTS] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_TYPE_1] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_STR_1] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_TUPLE_1] = { true, INSTR_FMT_IBC000 }, + [CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_BUILTIN_O] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_BUILTIN_FAST] = { true, INSTR_FMT_IBC000 }, + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_LEN] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_ISINSTANCE] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_LIST_APPEND] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC000 }, + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC000 }, + [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC000 }, + [CALL_FUNCTION_EX] = { true, INSTR_FMT_IB }, + [MAKE_FUNCTION] = { true, INSTR_FMT_IB }, + [RETURN_GENERATOR] = { true, INSTR_FMT_IX }, + [BUILD_SLICE] = { true, INSTR_FMT_IB }, + [FORMAT_VALUE] = { true, INSTR_FMT_IB }, + [COPY] = { true, INSTR_FMT_IB }, + [BINARY_OP] = { true, INSTR_FMT_IBC }, + [SWAP] = { true, INSTR_FMT_IB }, + [EXTENDED_ARG] = { true, INSTR_FMT_IB }, + [CACHE] = { true, INSTR_FMT_IX }, + [BB_BRANCH] = { true, INSTR_FMT_IBC }, + [BB_BRANCH_IF_FLAG_UNSET] = { true, INSTR_FMT_IBC }, + [BB_JUMP_IF_FLAG_UNSET] = { true, INSTR_FMT_IBC }, + [BB_BRANCH_IF_FLAG_SET] = { true, INSTR_FMT_IBC }, + [BB_JUMP_IF_FLAG_SET] = { true, INSTR_FMT_IBC }, + [BB_JUMP_BACKWARD_LAZY] = { true, INSTR_FMT_IB }, }; #endif diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 46223c9dee99be..31b6926f805485 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -283,7 +283,6 @@ class Instruction: # Parts of the underlying instruction definition inst: parser.InstDef - register: bool kind: parser.INST_KINDS name: str block: parser.Block @@ -301,17 +300,12 @@ class Instruction: unmoved_names: frozenset[str] instr_fmt: str - # Parallel to input_effects; set later - input_registers: list[str] = dataclasses.field(repr=False) - output_registers: list[str] = dataclasses.field(repr=False) - # Set later family: parser.Family | None = None predicted: bool = False def __init__(self, inst: parser.InstDef): self.inst = inst - self.register = inst.register self.kind = inst.kind self.name = inst.name self.block = inst.block @@ -334,15 +328,10 @@ def __init__(self, inst: parser.InstDef): else: break self.unmoved_names = frozenset(unmoved_names) - if self.register: - num_regs = len(self.input_effects) + len(self.output_effects) - num_dummies = (num_regs // 2) * 2 + 1 - num_regs - fmt = "I" + "B" * num_regs + "X" * num_dummies + if variable_used(inst, "oparg"): + fmt = "IB" else: - if variable_used(inst, "oparg"): - fmt = "IB" - else: - fmt = "IX" + fmt = "IX" cache = "C" for ce in self.cache_effects: for _ in range(ce.size): @@ -350,20 +339,6 @@ def __init__(self, inst: parser.InstDef): cache = "0" self.instr_fmt = fmt - def analyze_registers(self, a: "Analyzer") -> None: - regs = iter(("REG(oparg1)", "REG(oparg2)", "REG(oparg3)")) - try: - self.input_registers = [ - next(regs) for ieff in self.input_effects if ieff.name != UNUSED - ] - self.output_registers = [ - next(regs) for oeff in self.output_effects if oeff.name != UNUSED - ] - except StopIteration: # Running out of registers - a.error( - f"Instruction {self.name} has too many register effects", node=self.inst - ) - def write_typeprop(self, out: Formatter) -> None: """Write one instruction's type propagation rules""" @@ -518,25 +493,19 @@ def write(self, out: Formatter) -> None: f'{self.cache_offset}, "incorrect cache size");' ) - if not self.register: - # Write input stack effect variable declarations and initializations - ieffects = list(reversed(self.input_effects)) - for i, ieffect in enumerate(ieffects): - isize = string_effect_size( - list_effect_size([ieff for ieff in ieffects[: i + 1]]) - ) - if ieffect.size: - src = StackEffect(f"(stack_pointer - {maybe_parenthesize(isize)})", "PyObject **") - elif ieffect.cond: - src = StackEffect(f"({ieffect.cond}) ? stack_pointer[-{maybe_parenthesize(isize)}] : NULL", "") - else: - src = StackEffect(f"stack_pointer[-{maybe_parenthesize(isize)}]", "") - out.declare(ieffect, src) - else: - # Write input register variable declarations and initializations - for ieffect, reg in zip(self.input_effects, self.input_registers): - src = StackEffect(reg, "") - out.declare(ieffect, src) + # Write input stack effect variable declarations and initializations + ieffects = list(reversed(self.input_effects)) + for i, ieffect in enumerate(ieffects): + isize = string_effect_size( + list_effect_size([ieff for ieff in ieffects[: i + 1]]) + ) + if ieffect.size: + src = StackEffect(f"(stack_pointer - {maybe_parenthesize(isize)})", "PyObject **") + elif ieffect.cond: + src = StackEffect(f"({ieffect.cond}) ? stack_pointer[-{maybe_parenthesize(isize)}] : NULL", "") + else: + src = StackEffect(f"stack_pointer[-{maybe_parenthesize(isize)}]", "") + out.declare(ieffect, src) # Write output stack effect variable declarations isize = string_effect_size(list_effect_size(self.input_effects)) @@ -566,32 +535,26 @@ def write(self, out: Formatter) -> None: if self.always_exits: return - if not self.register: - # Write net stack growth/shrinkage - out.stack_adjust( - 0, - [ieff for ieff in self.input_effects], - [oeff for oeff in self.output_effects], - ) + # Write net stack growth/shrinkage + out.stack_adjust( + 0, + [ieff for ieff in self.input_effects], + [oeff for oeff in self.output_effects], + ) - # Write output stack effect assignments - oeffects = list(reversed(self.output_effects)) - for i, oeffect in enumerate(oeffects): - if oeffect.name in self.unmoved_names: - continue - osize = string_effect_size( - list_effect_size([oeff for oeff in oeffects[: i + 1]]) - ) - if oeffect.size: - dst = StackEffect(f"stack_pointer - {maybe_parenthesize(osize)}", "PyObject **") - else: - dst = StackEffect(f"stack_pointer[-{maybe_parenthesize(osize)}]", "") - out.assign(dst, oeffect) - else: - # Write output register assignments - for oeffect, reg in zip(self.output_effects, self.output_registers): - dst = StackEffect(reg, "") - out.assign(dst, oeffect) + # Write output stack effect assignments + oeffects = list(reversed(self.output_effects)) + for i, oeffect in enumerate(oeffects): + if oeffect.name in self.unmoved_names: + continue + osize = string_effect_size( + list_effect_size([oeff for oeff in oeffects[: i + 1]]) + ) + if oeffect.size: + dst = StackEffect(f"stack_pointer - {maybe_parenthesize(osize)}", "PyObject **") + else: + dst = StackEffect(f"stack_pointer[-{maybe_parenthesize(osize)}]", "") + out.assign(dst, oeffect) # Write cache effect if self.cache_offset: @@ -640,19 +603,17 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None # ERROR_IF() must pop the inputs from the stack. # The code block is responsible for DECREF()ing them. # NOTE: If the label doesn't exist, just add it to ceval.c. - if not self.register: - # Don't pop common input/output effects at the bottom! - # These aren't DECREF'ed so they can stay. - ieffs = list(self.input_effects) - oeffs = list(self.output_effects) - while ieffs and oeffs and ieffs[0] == oeffs[0]: - ieffs.pop(0) - oeffs.pop(0) - ninputs, symbolic = list_effect_size(ieffs) - if ninputs: - label = f"pop_{ninputs}_{label}" - else: - symbolic = "" + + # Don't pop common input/output effects at the bottom! + # These aren't DECREF'ed so they can stay. + ieffs = list(self.input_effects) + oeffs = list(self.output_effects) + while ieffs and oeffs and ieffs[0] == oeffs[0]: + ieffs.pop(0) + oeffs.pop(0) + ninputs, symbolic = list_effect_size(ieffs) + if ninputs: + label = f"pop_{ninputs}_{label}" if symbolic: out.write_raw( f"{space}if ({cond}) {{ STACK_SHRINK({symbolic}); goto {label}; }}\n" @@ -660,21 +621,20 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None else: out.write_raw(f"{space}if ({cond}) goto {label};{out.postfix}\n") elif m := re.match(r"(\s*)DECREF_INPUTS\(\);\s*(?://.*)?$", line): - if not self.register: - out.reset_lineno() - space = extra + m.group(1) - for ieff in self.input_effects: - if ieff.name in names_to_skip: - continue - if ieff.size: - out.write_raw( - f"{space}for (int _i = {ieff.size}; --_i >= 0;) {{\n" - ) - out.write_raw(f"{space} Py_DECREF({ieff.name}[_i]);\n") - out.write_raw(f"{space}}}\n") - else: - decref = "XDECREF" if ieff.cond else "DECREF" - out.write_raw(f"{space}Py_{decref}({ieff.name});\n") + out.reset_lineno() + space = extra + m.group(1) + for ieff in self.input_effects: + if ieff.name in names_to_skip: + continue + if ieff.size: + out.write_raw( + f"{space}for (int _i = {ieff.size}; --_i >= 0;) {{\n" + ) + out.write_raw(f"{space} Py_DECREF({ieff.name}[_i]);\n") + out.write_raw(f"{space}}}\n") + else: + decref = "XDECREF" if ieff.cond else "DECREF" + out.write_raw(f"{space}Py_{decref}({ieff.name});\n") else: out.write_raw(extra + line.rstrip("\n") + out.postfix + "\n") out.reset_lineno() @@ -887,7 +847,6 @@ def analyze(self) -> None: Raises SystemExit if there is an error. """ self.find_predictions() - self.analyze_register_instrs() self.analyze_supers_and_macros() self.map_families() self.check_families() @@ -997,11 +956,6 @@ def effect_counts(self, name: str) -> tuple[int, int, int]: assert False, f"Unknown instruction {name!r}" return cache, input, output - def analyze_register_instrs(self) -> None: - for instr in self.instrs.values(): - if instr.register: - instr.analyze_registers(self) - def analyze_supers_and_macros(self) -> None: """Analyze each super- and macro instruction.""" self.super_instrs = {} @@ -1033,7 +987,7 @@ def analyze_macro(self, macro: parser.Macro) -> MacroInstruction: stack, initial_sp = self.stack_analysis(components) sp = initial_sp parts: list[Component | parser.CacheEffect] = [] - format = "IB" # Macros don't support register instructions yet + format = "IB" cache = "C" for component in components: match component: @@ -1282,13 +1236,9 @@ def write_metadata(self) -> None: self.write_stack_effect_functions() # Write type definitions - self.out.emit("enum Direction { DIR_NONE, DIR_READ, DIR_WRITE };") self.out.emit(f"enum InstructionFormat {{ {', '.join(format_enums)} }};") self.out.emit("struct opcode_metadata {") with self.out.indent(): - self.out.emit("enum Direction dir_op1;") - self.out.emit("enum Direction dir_op2;") - self.out.emit("enum Direction dir_op3;") self.out.emit("bool valid_entry;") self.out.emit("enum InstructionFormat instr_format;") self.out.emit("};") @@ -1322,32 +1272,20 @@ def write_metadata(self) -> None: def write_metadata_for_inst(self, instr: Instruction) -> None: """Write metadata for a single instruction.""" - dir_op1 = dir_op2 = dir_op3 = "DIR_NONE" - if instr.kind == "legacy": - assert not instr.register - else: - if instr.register: - directions: list[str] = [] - directions.extend("DIR_READ" for _ in instr.input_effects) - directions.extend("DIR_WRITE" for _ in instr.output_effects) - directions.extend("DIR_NONE" for _ in range(3)) - dir_op1, dir_op2, dir_op3 = directions[:3] self.out.emit( - f" [{instr.name}] = {{ {dir_op1}, {dir_op2}, {dir_op3}, true, {INSTR_FMT_PREFIX}{instr.instr_fmt} }}," + f" [{instr.name}] = {{ true, {INSTR_FMT_PREFIX}{instr.instr_fmt} }}," ) def write_metadata_for_super(self, sup: SuperInstruction) -> None: """Write metadata for a super-instruction.""" - dir_op1 = dir_op2 = dir_op3 = "DIR_NONE" self.out.emit( - f" [{sup.name}] = {{ {dir_op1}, {dir_op2}, {dir_op3}, true, {INSTR_FMT_PREFIX}{sup.instr_fmt} }}," + f" [{sup.name}] = {{ true, {INSTR_FMT_PREFIX}{sup.instr_fmt} }}," ) def write_metadata_for_macro(self, mac: MacroInstruction) -> None: """Write metadata for a macro-instruction.""" - dir_op1 = dir_op2 = dir_op3 = "DIR_NONE" self.out.emit( - f" [{mac.name}] = {{ {dir_op1}, {dir_op2}, {dir_op3}, true, {INSTR_FMT_PREFIX}{mac.instr_fmt} }}," + f" [{mac.name}] = {{ true, {INSTR_FMT_PREFIX}{mac.instr_fmt} }}," ) def write_instructions(self) -> None: From 93685570a9431a34142939e44403beca951739e4 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 15 Mar 2023 18:43:54 -0600 Subject: [PATCH 120/280] gh-102660: Fix Refleaks in import.c (#102744) gh-102661 introduced some leaks. This fixes them. https://github.com/python/cpython/issues/102660 --- Python/bltinmodule.c | 3 --- Python/import.c | 50 +++++++++++++++++++++++++------------------- Python/sysmodule.c | 3 --- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index a8a34620b9bcdf..12ca0ba6c4873c 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -3098,9 +3098,6 @@ _PyBuiltin_Init(PyInterpreterState *interp) } Py_DECREF(debug); - /* m_copy of Py_None means it is copied some other way. */ - builtinsmodule.m_base.m_copy = Py_NewRef(Py_None); - return mod; #undef ADD_TO_ALL #undef SETBUILTIN diff --git a/Python/import.c b/Python/import.c index 612fee243bd9e7..9f80c6d8dd49a8 100644 --- a/Python/import.c +++ b/Python/import.c @@ -978,14 +978,29 @@ _PyImport_CheckSubinterpIncompatibleExtensionAllowed(const char *name) return 0; } -static inline int -match_mod_name(PyObject *actual, const char *expected) +static PyObject * +get_core_module_dict(PyInterpreterState *interp, + PyObject *name, PyObject *filename) { - if (PyUnicode_CompareWithASCIIString(actual, expected) == 0) { - return 1; + /* Only builtin modules are core. */ + if (filename == name) { + assert(!PyErr_Occurred()); + if (PyUnicode_CompareWithASCIIString(name, "sys") == 0) { + return interp->sysdict_copy; + } + assert(!PyErr_Occurred()); + if (PyUnicode_CompareWithASCIIString(name, "builtins") == 0) { + return interp->builtins_copy; + } + assert(!PyErr_Occurred()); } - assert(!PyErr_Occurred()); - return 0; + return NULL; +} + +static inline int +is_core_module(PyInterpreterState *interp, PyObject *name, PyObject *filename) +{ + return get_core_module_dict(interp, name, filename) != NULL; } static int @@ -1009,10 +1024,8 @@ fix_up_extension(PyObject *mod, PyObject *name, PyObject *filename) // bpo-44050: Extensions and def->m_base.m_copy can be updated // when the extension module doesn't support sub-interpreters. - // XXX Why special-case the main interpreter? - if (_Py_IsMainInterpreter(tstate->interp) || def->m_size == -1) { - /* m_copy of Py_None means it is copied some other way. */ - if (def->m_size == -1 && def->m_base.m_copy != Py_None) { + if (def->m_size == -1) { + if (!is_core_module(tstate->interp, name, filename)) { if (def->m_base.m_copy) { /* Somebody already imported the module, likely under a different name. @@ -1028,7 +1041,10 @@ fix_up_extension(PyObject *mod, PyObject *name, PyObject *filename) return -1; } } + } + // XXX Why special-case the main interpreter? + if (_Py_IsMainInterpreter(tstate->interp) || def->m_size == -1) { if (_extensions_cache_set(filename, name, def) < 0) { return -1; } @@ -1069,21 +1085,11 @@ import_find_extension(PyThreadState *tstate, PyObject *name, PyObject *m_copy = def->m_base.m_copy; /* Module does not support repeated initialization */ if (m_copy == NULL) { - return NULL; - } - else if (m_copy == Py_None) { - if (match_mod_name(name, "sys")) { - m_copy = tstate->interp->sysdict_copy; - } - else if (match_mod_name(name, "builtins")) { - m_copy = tstate->interp->builtins_copy; - } - else { - _PyErr_SetString(tstate, PyExc_ImportError, "missing m_copy"); + m_copy = get_core_module_dict(tstate->interp, name, filename); + if (m_copy == NULL) { return NULL; } } - /* m_copy of Py_None means it is copied some other way. */ mod = import_add_module(tstate, name); if (mod == NULL) { return NULL; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index fc0550266bf1af..d282104dcad414 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -3425,9 +3425,6 @@ _PySys_Create(PyThreadState *tstate, PyObject **sysmod_p) return _PyStatus_ERR("failed to create a module object"); } - /* m_copy of Py_None means it is copied some other way. */ - sysmodule.m_base.m_copy = Py_NewRef(Py_None); - PyObject *sysdict = PyModule_GetDict(sysmod); if (sysdict == NULL) { goto error; From b05f294a1a5761e6a159fcb2f3d5f31f77825977 Mon Sep 17 00:00:00 2001 From: Jamoo721 <81095953+Jamoo721@users.noreply.github.com> Date: Thu, 16 Mar 2023 13:52:11 +1100 Subject: [PATCH 121/280] gh-102690: Use Edge as fallback in webbrowser instead of IE (#102691) --- Lib/webbrowser.py | 12 ++++++++---- .../2023-03-14-10-52-43.gh-issue-102690.sbXtqk.rst | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2023-03-14-10-52-43.gh-issue-102690.sbXtqk.rst diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py index 44974d433b4696..a56ff33dbbdc69 100755 --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -542,11 +542,15 @@ def register_standard_browsers(): # First try to use the default Windows browser register("windows-default", WindowsDefault) - # Detect some common Windows browsers, fallback to IE - iexplore = os.path.join(os.environ.get("PROGRAMFILES", "C:\\Program Files"), - "Internet Explorer\\IEXPLORE.EXE") + # Detect some common Windows browsers, fallback to Microsoft Edge + # location in 64-bit Windows + edge64 = os.path.join(os.environ.get("PROGRAMFILES(x86)", "C:\\Program Files (x86)"), + "Microsoft\\Edge\\Application\\msedge.exe") + # location in 32-bit Windows + edge32 = os.path.join(os.environ.get("PROGRAMFILES", "C:\\Program Files"), + "Microsoft\\Edge\\Application\\msedge.exe") for browser in ("firefox", "firebird", "seamonkey", "mozilla", - "netscape", "opera", iexplore): + "opera", edge64, edge32): if shutil.which(browser): register(browser, None, BackgroundBrowser(browser)) else: diff --git a/Misc/NEWS.d/next/Windows/2023-03-14-10-52-43.gh-issue-102690.sbXtqk.rst b/Misc/NEWS.d/next/Windows/2023-03-14-10-52-43.gh-issue-102690.sbXtqk.rst new file mode 100644 index 00000000000000..5669ebbb442c24 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-03-14-10-52-43.gh-issue-102690.sbXtqk.rst @@ -0,0 +1 @@ +Update :mod:`webbrowser` to fall back to Microsoft Edge instead of Internet Explorer. From edd10d063f28af15898b624c49a067c0957e136e Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Thu, 16 Mar 2023 09:20:43 +0530 Subject: [PATCH 122/280] GH-100112: avoid using iterable coroutines in asyncio internally (#100128) --- Lib/asyncio/tasks.py | 22 +++++-------------- Lib/test/test_asyncio/test_tasks.py | 15 +++++++++++++ ...-03-10-13-51-21.gh-issue-100112.VHh4mw.rst | 1 + 3 files changed, 22 insertions(+), 16 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-03-10-13-51-21.gh-issue-100112.VHh4mw.rst diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index 1c20754b839b69..c90d32c97add78 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -25,7 +25,6 @@ from . import exceptions from . import futures from . import timeouts -from .coroutines import _is_coroutine # Helper to generate new task names # This uses itertools.count() instead of a "+= 1" operation because the latter @@ -635,11 +634,14 @@ def ensure_future(coro_or_future, *, loop=None): raise ValueError('The future belongs to a different loop than ' 'the one specified as the loop argument') return coro_or_future - called_wrap_awaitable = False + should_close = True if not coroutines.iscoroutine(coro_or_future): if inspect.isawaitable(coro_or_future): + async def _wrap_awaitable(awaitable): + return await awaitable + coro_or_future = _wrap_awaitable(coro_or_future) - called_wrap_awaitable = True + should_close = False else: raise TypeError('An asyncio.Future, a coroutine or an awaitable ' 'is required') @@ -649,23 +651,11 @@ def ensure_future(coro_or_future, *, loop=None): try: return loop.create_task(coro_or_future) except RuntimeError: - if not called_wrap_awaitable: + if should_close: coro_or_future.close() raise -@types.coroutine -def _wrap_awaitable(awaitable): - """Helper for asyncio.ensure_future(). - - Wraps awaitable (an object with __await__) into a coroutine - that will later be wrapped in a Task by ensure_future(). - """ - return (yield from awaitable.__await__()) - -_wrap_awaitable._is_coroutine = _is_coroutine - - class _GatheringFuture(futures.Future): """Helper for gather(). diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index e533d5273e9f38..5b935b526541a1 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -8,6 +8,7 @@ import re import sys import traceback +import types import unittest from unittest import mock from types import GenericAlias @@ -274,6 +275,20 @@ async def coro(): loop.run_until_complete(fut) self.assertEqual(fut.result(), 'ok') + def test_ensure_future_task_awaitable(self): + class Aw: + def __await__(self): + return asyncio.sleep(0, result='ok').__await__() + + loop = asyncio.new_event_loop() + self.set_event_loop(loop) + task = asyncio.ensure_future(Aw(), loop=loop) + loop.run_until_complete(task) + self.assertTrue(task.done()) + self.assertEqual(task.result(), 'ok') + self.assertIsInstance(task.get_coro(), types.CoroutineType) + loop.close() + def test_ensure_future_neither(self): with self.assertRaises(TypeError): asyncio.ensure_future('ok') diff --git a/Misc/NEWS.d/next/Library/2023-03-10-13-51-21.gh-issue-100112.VHh4mw.rst b/Misc/NEWS.d/next/Library/2023-03-10-13-51-21.gh-issue-100112.VHh4mw.rst new file mode 100644 index 00000000000000..eff77c40e30c48 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-10-13-51-21.gh-issue-100112.VHh4mw.rst @@ -0,0 +1 @@ +:meth:`asyncio.Task.get_coro` now always returns a coroutine when wrapping an awaitable object. Patch by Kumar Aditya. From f9f542d7e3de3f5989a40328438b55641b6ea432 Mon Sep 17 00:00:00 2001 From: yonatanp Date: Thu, 16 Mar 2023 00:44:52 -0400 Subject: [PATCH 123/280] gh-94440: Fix issue of ProcessPoolExecutor shutdown hanging (#94468) Fix an issue of concurrent.futures ProcessPoolExecutor shutdown hanging. Co-authored-by: Alex Waygood --- Lib/concurrent/futures/process.py | 5 ++++ Lib/test/test_concurrent_futures.py | 28 +++++++++++++++++++ Misc/ACKS | 1 + ...2-06-30-21-28-41.gh-issue-94440.LtgX0d.rst | 2 ++ 4 files changed, 36 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index 3a8637b6fa1b47..816edab99f63e3 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -366,6 +366,11 @@ def run(self): if self.is_shutting_down(): self.flag_executor_shutting_down() + # When only canceled futures remain in pending_work_items, our + # next call to wait_result_broken_or_wakeup would hang forever. + # This makes sure we have some running futures or none at all. + self.add_call_item_to_queue() + # Since no new work items can be added, it is safe to shutdown # this thread if there are no pending work items. if not self.pending_work_items: diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py index b3520ae3994e03..a20cb844a293c9 100644 --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -14,6 +14,7 @@ from logging.handlers import QueueHandler import os import queue +import signal import sys import threading import time @@ -397,6 +398,33 @@ def test_hang_gh83386(self): self.assertFalse(err) self.assertEqual(out.strip(), b"apple") + def test_hang_gh94440(self): + """shutdown(wait=True) doesn't hang when a future was submitted and + quickly canceled right before shutdown. + + See https://github.com/python/cpython/issues/94440. + """ + if not hasattr(signal, 'alarm'): + raise unittest.SkipTest( + "Tested platform does not support the alarm signal") + + def timeout(_signum, _frame): + raise RuntimeError("timed out waiting for shutdown") + + kwargs = {} + if getattr(self, 'ctx', None): + kwargs['mp_context'] = self.get_context() + executor = self.executor_type(max_workers=1, **kwargs) + executor.submit(int).result() + old_handler = signal.signal(signal.SIGALRM, timeout) + try: + signal.alarm(5) + executor.submit(int).cancel() + executor.shutdown(wait=True) + finally: + signal.alarm(0) + signal.signal(signal.SIGALRM, old_handler) + class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest, BaseTestCase): def test_threads_terminate(self): diff --git a/Misc/ACKS b/Misc/ACKS index 7bbde3af99782b..8cf5166a2bb1f4 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1385,6 +1385,7 @@ Thomas Perl Mathieu Perreault Mark Perrego Trevor Perrin +Yonatan Perry Gabriel de Perthuis Tim Peters Benjamin Peterson diff --git a/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst b/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst new file mode 100644 index 00000000000000..3eee82e59dfafb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-06-30-21-28-41.gh-issue-94440.LtgX0d.rst @@ -0,0 +1,2 @@ +Fix a :mod:`concurrent.futures.process` bug where ``ProcessPoolExecutor`` shutdown +could hang after a future has been quickly submitted and canceled. From a965c5e755161e922f58e5a5b81f8ee5ea361004 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Thu, 16 Mar 2023 10:16:01 +0000 Subject: [PATCH 124/280] gh-102594: PyErr_SetObject adds note to exception raised on normalization error (#102675) --- Include/cpython/pyerrors.h | 4 ++ Lib/test/test_capi/test_exceptions.py | 20 ++++++++++ ...-03-14-00-11-46.gh-issue-102594.BjU-m2.rst | 1 + Modules/_testcapi/exceptions.c | 21 ++++++++++ Objects/exceptions.c | 15 +++++++ Python/errors.c | 40 ++++++++++++++++--- 6 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-03-14-00-11-46.gh-issue-102594.BjU-m2.rst diff --git a/Include/cpython/pyerrors.h b/Include/cpython/pyerrors.h index 0d9cc9922f7368..d0300f6ee56a25 100644 --- a/Include/cpython/pyerrors.h +++ b/Include/cpython/pyerrors.h @@ -112,6 +112,10 @@ PyAPI_FUNC(PyObject *) _PyErr_FormatFromCause( /* In exceptions.c */ +PyAPI_FUNC(int) _PyException_AddNote( + PyObject *exc, + PyObject *note); + /* Helper that attempts to replace the current exception with one of the * same type but with a prefix added to the exception text. The resulting * exception description looks like: diff --git a/Lib/test/test_capi/test_exceptions.py b/Lib/test/test_capi/test_exceptions.py index 55f131699a2567..b1c1a61e20685e 100644 --- a/Lib/test/test_capi/test_exceptions.py +++ b/Lib/test/test_capi/test_exceptions.py @@ -169,5 +169,25 @@ class Broken(Exception, metaclass=Meta): with self.assertRaises(ZeroDivisionError) as e: _testcapi.exc_set_object(Broken, Broken()) + def test_set_object_and_fetch(self): + class Broken(Exception): + def __init__(self, *arg): + raise ValueError("Broken __init__") + + exc = _testcapi.exc_set_object_fetch(Broken, 'abcd') + self.assertIsInstance(exc, ValueError) + self.assertEqual(exc.__notes__[0], + "Normalization failed: type=Broken args='abcd'") + + class BadArg: + def __repr__(self): + raise TypeError('Broken arg type') + + exc = _testcapi.exc_set_object_fetch(Broken, BadArg()) + self.assertIsInstance(exc, ValueError) + self.assertEqual(exc.__notes__[0], + 'Normalization failed: type=Broken args=') + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-14-00-11-46.gh-issue-102594.BjU-m2.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-14-00-11-46.gh-issue-102594.BjU-m2.rst new file mode 100644 index 00000000000000..0b95b5ec98e811 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-14-00-11-46.gh-issue-102594.BjU-m2.rst @@ -0,0 +1 @@ +Add note to exception raised in ``PyErr_SetObject`` when normalization fails. diff --git a/Modules/_testcapi/exceptions.c b/Modules/_testcapi/exceptions.c index a0575213987ffc..c64b823663c32f 100644 --- a/Modules/_testcapi/exceptions.c +++ b/Modules/_testcapi/exceptions.c @@ -92,6 +92,26 @@ exc_set_object(PyObject *self, PyObject *args) return NULL; } +static PyObject * +exc_set_object_fetch(PyObject *self, PyObject *args) +{ + PyObject *exc; + PyObject *obj; + PyObject *type; + PyObject *value; + PyObject *tb; + + if (!PyArg_ParseTuple(args, "OO:exc_set_object", &exc, &obj)) { + return NULL; + } + + PyErr_SetObject(exc, obj); + PyErr_Fetch(&type, &value, &tb); + Py_XDECREF(type); + Py_XDECREF(tb); + return value; +} + static PyObject * raise_exception(PyObject *self, PyObject *args) { @@ -262,6 +282,7 @@ static PyMethodDef test_methods[] = { {"make_exception_with_doc", _PyCFunction_CAST(make_exception_with_doc), METH_VARARGS | METH_KEYWORDS}, {"exc_set_object", exc_set_object, METH_VARARGS}, + {"exc_set_object_fetch", exc_set_object_fetch, METH_VARARGS}, {"raise_exception", raise_exception, METH_VARARGS}, {"raise_memoryerror", raise_memoryerror, METH_NOARGS}, {"set_exc_info", test_set_exc_info, METH_VARARGS}, diff --git a/Objects/exceptions.c b/Objects/exceptions.c index c6fb6a3f19b2d0..d69f7400ca6042 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -3749,6 +3749,21 @@ _PyExc_Fini(PyInterpreterState *interp) _PyExc_FiniTypes(interp); } +int +_PyException_AddNote(PyObject *exc, PyObject *note) +{ + if (!PyExceptionInstance_Check(exc)) { + PyErr_Format(PyExc_TypeError, + "exc must be an exception, not '%s'", + Py_TYPE(exc)->tp_name); + return -1; + } + PyObject *r = BaseException_add_note(exc, note); + int res = r == NULL ? -1 : 0; + Py_XDECREF(r); + return res; +} + /* Helper to do the equivalent of "raise X from Y" in C, but always using * the current exception rather than passing one in. * diff --git a/Python/errors.c b/Python/errors.c index bbf6d397ce8097..bdcbac317eb9ee 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -135,6 +135,28 @@ _PyErr_GetTopmostException(PyThreadState *tstate) return exc_info; } +static PyObject * +get_normalization_failure_note(PyThreadState *tstate, PyObject *exception, PyObject *value) +{ + PyObject *args = PyObject_Repr(value); + if (args == NULL) { + _PyErr_Clear(tstate); + args = PyUnicode_FromFormat(""); + } + PyObject *note; + const char *tpname = ((PyTypeObject*)exception)->tp_name; + if (args == NULL) { + _PyErr_Clear(tstate); + note = PyUnicode_FromFormat("Normalization failed: type=%s", tpname); + } + else { + note = PyUnicode_FromFormat("Normalization failed: type=%s args=%S", + tpname, args); + Py_DECREF(args); + } + return note; +} + void _PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value) { @@ -160,19 +182,27 @@ _PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value) Py_XINCREF(value); if (!is_subclass) { /* We must normalize the value right now */ - PyObject *fixed_value; /* Issue #23571: functions must not be called with an exception set */ _PyErr_Clear(tstate); - fixed_value = _PyErr_CreateException(exception, value); - Py_XDECREF(value); + PyObject *fixed_value = _PyErr_CreateException(exception, value); if (fixed_value == NULL) { + PyObject *exc = _PyErr_GetRaisedException(tstate); + assert(PyExceptionInstance_Check(exc)); + + PyObject *note = get_normalization_failure_note(tstate, exception, value); + Py_XDECREF(value); + if (note != NULL) { + /* ignore errors in _PyException_AddNote - they will be overwritten below */ + _PyException_AddNote(exc, note); + Py_DECREF(note); + } + _PyErr_SetRaisedException(tstate, exc); return; } - - value = fixed_value; + Py_XSETREF(value, fixed_value); } exc_value = _PyErr_GetTopmostException(tstate)->exc_value; From e3461ea352c74c341ad0b8c3d310e6f4683c38fc Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Thu, 16 Mar 2023 16:05:38 +0300 Subject: [PATCH 125/280] Add comments to `{typing,_collections_abc}._type_repr` about each other (#102752) Remove `if` condition in `_collections_abc._type_repr` that's no longer needed, bringing it in sync with `typing._type_repr`. --- Lib/_collections_abc.py | 3 +-- Lib/typing.py | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py index c62233b81a5c95..f86b91a5e6fb0d 100644 --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -517,9 +517,8 @@ def _type_repr(obj): Copied from :mod:`typing` since collections.abc shouldn't depend on that module. + (Keep this roughly in sync with the typing version.) """ - if isinstance(obj, GenericAlias): - return repr(obj) if isinstance(obj, type): if obj.__module__ == 'builtins': return obj.__qualname__ diff --git a/Lib/typing.py b/Lib/typing.py index ab334395676159..3ee9679e50c0c4 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -230,6 +230,9 @@ def _type_repr(obj): typically enough to uniquely identify a type. For everything else, we fall back on repr(obj). """ + # When changing this function, don't forget about + # `_collections_abc._type_repr`, which does the same thing + # and must be consistent with this one. if isinstance(obj, type): if obj.__module__ == 'builtins': return obj.__qualname__ From 97306821d42cc2b0f6f331a70b988371b548f3f0 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Thu, 16 Mar 2023 09:32:18 -0500 Subject: [PATCH 126/280] GH-102653: Make recipe docstring show the correct distribution (#102742) --- Doc/library/random.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/library/random.rst b/Doc/library/random.rst index 4522f5a8d26b9d..098684d7270ffa 100644 --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -610,7 +610,8 @@ from the combinatoric iterators in the :mod:`itertools` module: return tuple(pool[i] for i in indices) def random_combination_with_replacement(iterable, r): - "Random selection from itertools.combinations_with_replacement(iterable, r)" + "Choose r elements with replacement. Order the result to match the iterable." + # Result will be in set(itertools.combinations_with_replacement(iterable, r)). pool = tuple(iterable) n = len(pool) indices = sorted(random.choices(range(n), k=r)) From dd97b7551b788d7df53d1cec71f3c59245d5f48b Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Thu, 16 Mar 2023 17:47:30 +0300 Subject: [PATCH 127/280] gh-102721: Improve coverage of `_collections_abc._CallableGenericAlias` (#102722) Co-authored-by: Alex Waygood --- Lib/_collections_abc.py | 7 ------- Lib/test/test_typing.py | 39 ++++++++++++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py index f86b91a5e6fb0d..9d7724c33474cc 100644 --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -481,15 +481,8 @@ def __getitem__(self, item): # rather than the default types.GenericAlias object. Most of the # code is copied from typing's _GenericAlias and the builtin # types.GenericAlias. - if not isinstance(item, tuple): item = (item,) - # A special case in PEP 612 where if X = Callable[P, int], - # then X[int, str] == X[[int, str]]. - if (len(self.__parameters__) == 1 - and _is_param_expr(self.__parameters__[0]) - and item and not _is_param_expr(item[0])): - item = (item,) new_args = super().__getitem__(item).__args__ diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 89c725cda54f12..c9f55de95c548f 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1921,14 +1921,29 @@ def test_weakref(self): self.assertEqual(weakref.ref(alias)(), alias) def test_pickle(self): + global T_pickle, P_pickle, TS_pickle # needed for pickling Callable = self.Callable - alias = Callable[[int, str], float] - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - s = pickle.dumps(alias, proto) - loaded = pickle.loads(s) - self.assertEqual(alias.__origin__, loaded.__origin__) - self.assertEqual(alias.__args__, loaded.__args__) - self.assertEqual(alias.__parameters__, loaded.__parameters__) + T_pickle = TypeVar('T_pickle') + P_pickle = ParamSpec('P_pickle') + TS_pickle = TypeVarTuple('TS_pickle') + + samples = [ + Callable[[int, str], float], + Callable[P_pickle, int], + Callable[P_pickle, T_pickle], + Callable[Concatenate[int, P_pickle], int], + Callable[Concatenate[*TS_pickle, P_pickle], int], + ] + for alias in samples: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(alias=alias, proto=proto): + s = pickle.dumps(alias, proto) + loaded = pickle.loads(s) + self.assertEqual(alias.__origin__, loaded.__origin__) + self.assertEqual(alias.__args__, loaded.__args__) + self.assertEqual(alias.__parameters__, loaded.__parameters__) + + del T_pickle, P_pickle, TS_pickle # cleaning up global state def test_var_substitution(self): Callable = self.Callable @@ -1954,6 +1969,16 @@ def test_var_substitution(self): self.assertEqual(C5[int, str, float], Callable[[typing.List[int], tuple[str, int], float], int]) + def test_type_subst_error(self): + Callable = self.Callable + P = ParamSpec('P') + T = TypeVar('T') + + pat = "Expected a list of types, an ellipsis, ParamSpec, or Concatenate." + + with self.assertRaisesRegex(TypeError, pat): + Callable[P, T][0, int] + def test_type_erasure(self): Callable = self.Callable class C1(Callable): From a123f260030a417bdeb0c3055d851efcfaacd72e Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Thu, 16 Mar 2023 20:28:10 +0530 Subject: [PATCH 128/280] GH-102748: remove legacy support for generator based coroutines from `asyncio.iscoroutine` (#102749) Co-authored-by: Alex Waygood --- Doc/whatsnew/3.12.rst | 4 ++++ Lib/asyncio/coroutines.py | 3 +-- Lib/test/test_asyncio/test_pep492.py | 6 ++++++ .../Library/2023-03-16-08-17-29.gh-issue-102748.WNACpI.rst | 3 +++ 4 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-03-16-08-17-29.gh-issue-102748.WNACpI.rst diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 217ffec1ee1007..b9c668543e1b73 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -237,6 +237,10 @@ asyncio * Add C implementation of :func:`asyncio.current_task` for 4x-6x speedup. (Contributed by Itamar Ostricher and Pranav Thulasiram Bhat in :gh:`100344`.) +* :func:`asyncio.iscoroutine` now returns ``False`` for generators as + :mod:`asyncio` does not support legacy generator-based coroutines. + (Contributed by Kumar Aditya in :gh:`102748`.) + inspect ------- diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py index 7fda0e449d500a..ab4f30eb51ba2c 100644 --- a/Lib/asyncio/coroutines.py +++ b/Lib/asyncio/coroutines.py @@ -25,8 +25,7 @@ def iscoroutinefunction(func): # Prioritize native coroutine check to speed-up # asyncio.iscoroutine. -_COROUTINE_TYPES = (types.CoroutineType, types.GeneratorType, - collections.abc.Coroutine) +_COROUTINE_TYPES = (types.CoroutineType, collections.abc.Coroutine) _iscoroutine_typecache = set() diff --git a/Lib/test/test_asyncio/test_pep492.py b/Lib/test/test_asyncio/test_pep492.py index f833f788dcb98f..dc25a46985e349 100644 --- a/Lib/test/test_asyncio/test_pep492.py +++ b/Lib/test/test_asyncio/test_pep492.py @@ -119,6 +119,12 @@ async def foo(): pass self.assertTrue(asyncio.iscoroutine(FakeCoro())) + def test_iscoroutine_generator(self): + def foo(): yield + + self.assertFalse(asyncio.iscoroutine(foo())) + + def test_iscoroutinefunction(self): async def foo(): pass self.assertTrue(asyncio.iscoroutinefunction(foo)) diff --git a/Misc/NEWS.d/next/Library/2023-03-16-08-17-29.gh-issue-102748.WNACpI.rst b/Misc/NEWS.d/next/Library/2023-03-16-08-17-29.gh-issue-102748.WNACpI.rst new file mode 100644 index 00000000000000..b1dc67f38fe85d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-16-08-17-29.gh-issue-102748.WNACpI.rst @@ -0,0 +1,3 @@ +:func:`asyncio.iscoroutine` now returns ``False`` for generators as +:mod:`asyncio` does not support legacy generator-based coroutines. +Patch by Kumar Aditya. From df9a32283e3a751b1b664975f4c294e522ccb121 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Thu, 16 Mar 2023 09:26:42 -0600 Subject: [PATCH 129/280] gh-102737: Un-ignore ceval.c in the CI globals check (gh-102745) The tool now allows user-added #LINE preprocessor directives. https://github.com/python/cpython/issues/102737 --- Tools/c-analyzer/c_parser/preprocessor/gcc.py | 10 +++++++--- Tools/c-analyzer/cpython/_parser.py | 4 ---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Tools/c-analyzer/c_parser/preprocessor/gcc.py b/Tools/c-analyzer/c_parser/preprocessor/gcc.py index 24c1b0e9b9d48c..c680f351f22416 100644 --- a/Tools/c-analyzer/c_parser/preprocessor/gcc.py +++ b/Tools/c-analyzer/c_parser/preprocessor/gcc.py @@ -153,9 +153,13 @@ def _iter_top_include_lines(lines, topfile, cwd, # XXX How can a file return to line 1? #assert lno > 1, (line, lno) else: - # It's the next line from the file. - assert included == files[-1], (line, files) - assert lno > 1, (line, lno) + if included == files[-1]: + # It's the next line from the file. + assert lno > 1, (line, lno) + else: + # We ran into a user-added #LINE directive, + # which we promptly ignore. + pass elif not files: raise NotImplementedError((line,)) elif filter_reqfile(files[-1]): diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index a2911e030ffee1..acf30e2c4020b3 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -96,10 +96,6 @@ def clean_lines(text): # has gone wrong where # we handle "maybe inline actual" # in Tools/c-analyzer/c_parser/parser/_global.py. Modules/expat/xmlparse.c - -# The parser doesn't like the #line directives -# that originate from generated_cases.c.h -Python/ceval.c ''') INCL_DIRS = clean_lines(''' From 6b9d4cbfb450cdc4ddec6daad6be6afebd4a21ea Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Thu, 16 Mar 2023 16:21:49 +0000 Subject: [PATCH 130/280] gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives (#102743) --- Python/pythonrun.c | 79 ++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 44 deletions(-) diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 34a44dd92847ba..5381b105a39fed 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -698,30 +698,30 @@ _Py_HandleSystemExit(int *exitcode_p) return 0; } - PyObject *exception, *value, *tb; - PyErr_Fetch(&exception, &value, &tb); - fflush(stdout); int exitcode = 0; - if (value == NULL || value == Py_None) { + + PyObject *exc = PyErr_GetRaisedException(); + if (exc == NULL) { goto done; } + assert(PyExceptionInstance_Check(exc)); - if (PyExceptionInstance_Check(value)) { - /* The error code should be in the `code' attribute. */ - PyObject *code = PyObject_GetAttr(value, &_Py_ID(code)); - if (code) { - Py_SETREF(value, code); - if (value == Py_None) - goto done; + /* The error code should be in the `code' attribute. */ + PyObject *code = PyObject_GetAttr(exc, &_Py_ID(code)); + if (code) { + Py_SETREF(exc, code); + if (exc == Py_None) { + goto done; } - /* If we failed to dig out the 'code' attribute, - just let the else clause below print the error. */ } + /* If we failed to dig out the 'code' attribute, + * just let the else clause below print the error. + */ - if (PyLong_Check(value)) { - exitcode = (int)PyLong_AsLong(value); + if (PyLong_Check(exc)) { + exitcode = (int)PyLong_AsLong(exc); } else { PyThreadState *tstate = _PyThreadState_GET(); @@ -732,20 +732,17 @@ _Py_HandleSystemExit(int *exitcode_p) */ PyErr_Clear(); if (sys_stderr != NULL && sys_stderr != Py_None) { - PyFile_WriteObject(value, sys_stderr, Py_PRINT_RAW); + PyFile_WriteObject(exc, sys_stderr, Py_PRINT_RAW); } else { - PyObject_Print(value, stderr, Py_PRINT_RAW); + PyObject_Print(exc, stderr, Py_PRINT_RAW); fflush(stderr); } PySys_WriteStderr("\n"); exitcode = 1; } - done: - /* Cleanup the exception */ - Py_CLEAR(exception); - Py_CLEAR(value); - Py_CLEAR(tb); +done: + Py_CLEAR(exc); *exitcode_p = exitcode; return 1; } @@ -1641,35 +1638,29 @@ PyRun_FileExFlags(FILE *fp, const char *filename, int start, PyObject *globals, } - static void -flush_io(void) +flush_io_stream(PyThreadState *tstate, PyObject *name) { - PyObject *f, *r; - PyObject *type, *value, *traceback; - - /* Save the current exception */ - PyErr_Fetch(&type, &value, &traceback); - - PyThreadState *tstate = _PyThreadState_GET(); - f = _PySys_GetAttr(tstate, &_Py_ID(stderr)); - if (f != NULL) { - r = _PyObject_CallMethodNoArgs(f, &_Py_ID(flush)); - if (r) - Py_DECREF(r); - else - PyErr_Clear(); - } - f = _PySys_GetAttr(tstate, &_Py_ID(stdout)); + PyObject *f = _PySys_GetAttr(tstate, name); if (f != NULL) { - r = _PyObject_CallMethodNoArgs(f, &_Py_ID(flush)); - if (r) + PyObject *r = _PyObject_CallMethodNoArgs(f, &_Py_ID(flush)); + if (r) { Py_DECREF(r); - else + } + else { PyErr_Clear(); + } } +} - PyErr_Restore(type, value, traceback); +static void +flush_io(void) +{ + PyThreadState *tstate = _PyThreadState_GET(); + PyObject *exc = _PyErr_GetRaisedException(tstate); + flush_io_stream(tstate, &_Py_ID(stderr)); + flush_io_stream(tstate, &_Py_ID(stdout)); + _PyErr_SetRaisedException(tstate, exc); } static PyObject * From ba65c48bafe0d6e12d3cc5504731fb54dcf54446 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Thu, 16 Mar 2023 16:41:10 +0000 Subject: [PATCH 131/280] gh-102192: remove redundant exception fields from ssl module socket (#102466) --- Modules/_ssl.c | 28 +++++++++------------------- Modules/_ssl/debughelpers.c | 7 +++---- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 28112317bc289e..121d18884d0a9f 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -318,9 +318,7 @@ typedef struct { * store exception information on the socket. The handshake, read, write, * and shutdown methods check for chained exceptions. */ - PyObject *exc_type; - PyObject *exc_value; - PyObject *exc_tb; + PyObject *exc; } PySSLSocket; typedef struct { @@ -564,13 +562,11 @@ fill_and_set_sslerror(_sslmodulestate *state, static int PySSL_ChainExceptions(PySSLSocket *sslsock) { - if (sslsock->exc_type == NULL) + if (sslsock->exc == NULL) return 0; - _PyErr_ChainExceptions(sslsock->exc_type, sslsock->exc_value, sslsock->exc_tb); - sslsock->exc_type = NULL; - sslsock->exc_value = NULL; - sslsock->exc_tb = NULL; + _PyErr_ChainExceptions1(sslsock->exc); + sslsock->exc = NULL; return -1; } @@ -807,9 +803,7 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, self->owner = NULL; self->server_hostname = NULL; self->err = err; - self->exc_type = NULL; - self->exc_value = NULL; - self->exc_tb = NULL; + self->exc = NULL; /* Make sure the SSL error state is initialized */ ERR_clear_error(); @@ -2179,9 +2173,7 @@ Passed as \"self\" in servername callback."); static int PySSL_traverse(PySSLSocket *self, visitproc visit, void *arg) { - Py_VISIT(self->exc_type); - Py_VISIT(self->exc_value); - Py_VISIT(self->exc_tb); + Py_VISIT(self->exc); Py_VISIT(Py_TYPE(self)); return 0; } @@ -2189,9 +2181,7 @@ PySSL_traverse(PySSLSocket *self, visitproc visit, void *arg) static int PySSL_clear(PySSLSocket *self) { - Py_CLEAR(self->exc_type); - Py_CLEAR(self->exc_value); - Py_CLEAR(self->exc_tb); + Py_CLEAR(self->exc); return 0; } @@ -2536,7 +2526,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len, PySSL_SetError(self, retval, __FILE__, __LINE__); goto error; } - if (self->exc_type != NULL) + if (self->exc != NULL) goto error; done: @@ -2662,7 +2652,7 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self) PySSL_SetError(self, ret, __FILE__, __LINE__); return NULL; } - if (self->exc_type != NULL) + if (self->exc != NULL) goto error; if (sock) /* It's already INCREF'ed */ diff --git a/Modules/_ssl/debughelpers.c b/Modules/_ssl/debughelpers.c index 08f3457035b90c..217f224942556e 100644 --- a/Modules/_ssl/debughelpers.c +++ b/Modules/_ssl/debughelpers.c @@ -74,7 +74,7 @@ _PySSL_msg_callback(int write_p, int version, int content_type, buf, len ); if (res == NULL) { - PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value, &ssl_obj->exc_tb); + ssl_obj->exc = PyErr_GetRaisedException(); } else { Py_DECREF(res); } @@ -138,8 +138,7 @@ _PySSL_keylog_callback(const SSL *ssl, const char *line) lock = PyThread_allocate_lock(); if (lock == NULL) { PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); - PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value, - &ssl_obj->exc_tb); + ssl_obj->exc = PyErr_GetRaisedException(); return; } } @@ -156,7 +155,7 @@ _PySSL_keylog_callback(const SSL *ssl, const char *line) errno = e; PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, ssl_obj->ctx->keylog_filename); - PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value, &ssl_obj->exc_tb); + ssl_obj->exc = PyErr_GetRaisedException(); } PyGILState_Release(threadstate); } From a10c1f221a5248cedf476736eea365e1dfc84910 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Thu, 16 Mar 2023 17:27:21 +0000 Subject: [PATCH 132/280] gh-99726: Improves correctness of stat results for Windows, and uses faster API when available (GH-102149) This deprecates `st_ctime` fields on Windows, with the intent to change them to contain the correct value in 3.14. For now, they should keep returning the creation time as they always have. --- Doc/library/os.rst | 88 +++++--- Doc/whatsnew/3.12.rst | 16 ++ Include/internal/pycore_fileutils.h | 5 +- Include/internal/pycore_fileutils_windows.h | 80 ++++++++ Lib/test/test_os.py | 12 +- ...3-02-22-17-26-10.gh-issue-99726.76t957.rst | 2 + Modules/posixmodule.c | 191 +++++++++++++----- PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 3 + Python/fileutils.c | 130 ++++++++++-- 10 files changed, 446 insertions(+), 82 deletions(-) create mode 100644 Include/internal/pycore_fileutils_windows.h create mode 100644 Misc/NEWS.d/next/Windows/2023-02-22-17-26-10.gh-issue-99726.76t957.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 5b9f49be1fad55..3153f79e10ce1f 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -2858,6 +2858,12 @@ features: Added support for the :class:`~os.PathLike` interface. Added support for :class:`bytes` paths on Windows. + .. versionchanged:: 3.12 + The ``st_ctime`` attribute of a stat result is deprecated on Windows. + The file creation time is properly available as ``st_birthtime``, and + in the future ``st_ctime`` may be changed to return zero or the + metadata change time, if available. + .. function:: stat(path, *, dir_fd=None, follow_symlinks=True) @@ -2973,10 +2979,12 @@ features: .. attribute:: st_ctime - Platform dependent: + Time of most recent metadata change expressed in seconds. - * the time of most recent metadata change on Unix, - * the time of creation on Windows, expressed in seconds. + .. versionchanged:: 3.12 + ``st_ctime`` is deprecated on Windows. Use ``st_birthtime`` for + the file creation time. In the future, ``st_ctime`` will contain + the time of the most recent metadata change, as for other platforms. .. attribute:: st_atime_ns @@ -2989,29 +2997,48 @@ features: .. attribute:: st_ctime_ns - Platform dependent: + Time of most recent metadata change expressed in nanoseconds as an + integer. + + .. versionchanged:: 3.12 + ``st_ctime_ns`` is deprecated on Windows. Use ``st_birthtime_ns`` + for the file creation time. In the future, ``st_ctime`` will contain + the time of the most recent metadata change, as for other platforms. + + .. attribute:: st_birthtime + + Time of file creation expressed in seconds. This attribute is not + always available, and may raise :exc:`AttributeError`. + + .. versionchanged:: 3.12 + ``st_birthtime`` is now available on Windows. + + .. attribute:: st_birthtime_ns - * the time of most recent metadata change on Unix, - * the time of creation on Windows, expressed in nanoseconds as an - integer. + Time of file creation expressed in nanoseconds as an integer. + This attribute is not always available, and may raise + :exc:`AttributeError`. + + .. versionadded:: 3.12 .. note:: The exact meaning and resolution of the :attr:`st_atime`, - :attr:`st_mtime`, and :attr:`st_ctime` attributes depend on the operating - system and the file system. For example, on Windows systems using the FAT - or FAT32 file systems, :attr:`st_mtime` has 2-second resolution, and - :attr:`st_atime` has only 1-day resolution. See your operating system - documentation for details. + :attr:`st_mtime`, :attr:`st_ctime` and :attr:`st_birthtime` attributes + depend on the operating system and the file system. For example, on + Windows systems using the FAT32 file systems, :attr:`st_mtime` has + 2-second resolution, and :attr:`st_atime` has only 1-day resolution. + See your operating system documentation for details. Similarly, although :attr:`st_atime_ns`, :attr:`st_mtime_ns`, - and :attr:`st_ctime_ns` are always expressed in nanoseconds, many - systems do not provide nanosecond precision. On systems that do - provide nanosecond precision, the floating-point object used to - store :attr:`st_atime`, :attr:`st_mtime`, and :attr:`st_ctime` - cannot preserve all of it, and as such will be slightly inexact. - If you need the exact timestamps you should always use - :attr:`st_atime_ns`, :attr:`st_mtime_ns`, and :attr:`st_ctime_ns`. + :attr:`st_ctime_ns` and :attr:`st_birthtime_ns` are always expressed in + nanoseconds, many systems do not provide nanosecond precision. On + systems that do provide nanosecond precision, the floating-point object + used to store :attr:`st_atime`, :attr:`st_mtime`, :attr:`st_ctime` and + :attr:`st_birthtime` cannot preserve all of it, and as such will be + slightly inexact. If you need the exact timestamps you should always use + :attr:`st_atime_ns`, :attr:`st_mtime_ns`, :attr:`st_ctime_ns` and + :attr:`st_birthtime_ns`. On some Unix systems (such as Linux), the following attributes may also be available: @@ -3041,10 +3068,6 @@ features: File generation number. - .. attribute:: st_birthtime - - Time of file creation. - On Solaris and derivatives, the following attributes may also be available: @@ -3117,6 +3140,25 @@ features: files as :const:`S_IFCHR`, :const:`S_IFIFO` or :const:`S_IFBLK` as appropriate. + .. versionchanged:: 3.12 + On Windows, :attr:`st_ctime` is deprecated. Eventually, it will + contain the last metadata change time, for consistency with other + platforms, but for now still contains creation time. + Use :attr:`st_birthtime` for the creation time. + + .. versionchanged:: 3.12 + On Windows, :attr:`st_ino` may now be up to 128 bits, depending + on the file system. Previously it would not be above 64 bits, and + larger file identifiers would be arbitrarily packed. + + .. versionchanged:: 3.12 + On Windows, :attr:`st_rdev` no longer returns a value. Previously + it would contain the same as :attr:`st_dev`, which was incorrect. + + .. versionadded:: 3.12 + Added the :attr:`st_birthtime` member on Windows. + + .. function:: statvfs(path) Perform a :c:func:`statvfs` system call on the given path. The return value is diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index b9c668543e1b73..03b1f975746787 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -306,6 +306,16 @@ os functions on Windows for enumerating drives, volumes and mount points. (Contributed by Steve Dower in :gh:`102519`.) +* :func:`os.stat` and :func:`os.lstat` are now more accurate on Windows. + The ``st_birthtime`` field will now be filled with the creation time + of the file, and ``st_ctime`` is deprecated but still contains the + creation time (but in the future will return the last metadata change, + for consistency with other platforms). ``st_dev`` may be up to 64 bits + and ``st_ino`` up to 128 bits depending on your file system, and + ``st_rdev`` is always set to zero rather than incorrect values. + Both functions may be significantly faster on newer releases of + Windows. (Contributed by Steve Dower in :gh:`99726`.) + os.path ------- @@ -469,6 +479,12 @@ Deprecated warning at compile time. This field will be removed in Python 3.14. (Contributed by Ramvikrams and Kumar Aditya in :gh:`101193`. PEP by Ken Jin.) +* The ``st_ctime`` fields return by :func:`os.stat` and :func:`os.lstat` on + Windows are deprecated. In a future release, they will contain the last + metadata change time, consistent with other platforms. For now, they still + contain the creation time, which is also available in the new ``st_birthtime`` + field. (Contributed by Steve Dower in :gh:`99726`.) + Pending Removal in Python 3.13 ------------------------------ diff --git a/Include/internal/pycore_fileutils.h b/Include/internal/pycore_fileutils.h index 445ac0a3d955d9..ef6642d00f1b54 100644 --- a/Include/internal/pycore_fileutils.h +++ b/Include/internal/pycore_fileutils.h @@ -66,7 +66,7 @@ PyAPI_FUNC(PyObject *) _Py_device_encoding(int); #ifdef MS_WINDOWS struct _Py_stat_struct { - unsigned long st_dev; + uint64_t st_dev; uint64_t st_ino; unsigned short st_mode; int st_nlink; @@ -80,8 +80,11 @@ struct _Py_stat_struct { int st_mtime_nsec; time_t st_ctime; int st_ctime_nsec; + time_t st_birthtime; + int st_birthtime_nsec; unsigned long st_file_attributes; unsigned long st_reparse_tag; + uint64_t st_ino_high; }; #else # define _Py_stat_struct stat diff --git a/Include/internal/pycore_fileutils_windows.h b/Include/internal/pycore_fileutils_windows.h new file mode 100644 index 00000000000000..44874903b092f3 --- /dev/null +++ b/Include/internal/pycore_fileutils_windows.h @@ -0,0 +1,80 @@ +#ifndef Py_INTERNAL_FILEUTILS_WINDOWS_H +#define Py_INTERNAL_FILEUTILS_WINDOWS_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "Py_BUILD_CORE must be defined to include this header" +#endif + +#ifdef MS_WINDOWS + +#if !defined(NTDDI_WIN10_NI) || !(NTDDI_VERSION >= NTDDI_WIN10_NI) +typedef struct _FILE_STAT_BASIC_INFORMATION { + LARGE_INTEGER FileId; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; + ULONG ReparseTag; + ULONG NumberOfLinks; + ULONG DeviceType; + ULONG DeviceCharacteristics; + ULONG Reserved; + FILE_ID_128 FileId128; + LARGE_INTEGER VolumeSerialNumber; +} FILE_STAT_BASIC_INFORMATION; + +typedef enum _FILE_INFO_BY_NAME_CLASS { + FileStatByNameInfo, + FileStatLxByNameInfo, + FileCaseSensitiveByNameInfo, + FileStatBasicByNameInfo, + MaximumFileInfoByNameClass +} FILE_INFO_BY_NAME_CLASS; +#endif + +typedef BOOL (WINAPI *PGetFileInformationByName)( + PCWSTR FileName, + FILE_INFO_BY_NAME_CLASS FileInformationClass, + PVOID FileInfoBuffer, + ULONG FileInfoBufferSize +); + +static inline BOOL _Py_GetFileInformationByName( + PCWSTR FileName, + FILE_INFO_BY_NAME_CLASS FileInformationClass, + PVOID FileInfoBuffer, + ULONG FileInfoBufferSize +) { + static PGetFileInformationByName GetFileInformationByName = NULL; + static int GetFileInformationByName_init = -1; + + if (GetFileInformationByName_init < 0) { + HMODULE hMod = LoadLibraryW(L"api-ms-win-core-file-l2-1-4"); + GetFileInformationByName_init = 0; + if (hMod) { + GetFileInformationByName = (PGetFileInformationByName)GetProcAddress( + hMod, "GetFileInformationByName"); + if (GetFileInformationByName) { + GetFileInformationByName_init = 1; + } else { + FreeLibrary(hMod); + } + } + } + + if (GetFileInformationByName_init <= 0) { + SetLastError(ERROR_NOT_SUPPORTED); + return FALSE; + } + return GetFileInformationByName(FileName, FileInformationClass, FileInfoBuffer, FileInfoBufferSize); +} + +#endif + +#endif diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 42357fef80ec89..74ece3ffb4ed17 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -556,6 +556,15 @@ def trunc(x): return x nanosecondy = getattr(result, name + "_ns") // 10000 self.assertAlmostEqual(floaty, nanosecondy, delta=2) + # Ensure both birthtime and birthtime_ns roughly agree, if present + try: + floaty = int(result.st_birthtime * 100000) + nanosecondy = result.st_birthtime_ns // 10000 + except AttributeError: + pass + else: + self.assertAlmostEqual(floaty, nanosecondy, delta=2) + try: result[200] self.fail("No exception raised") @@ -4234,7 +4243,8 @@ def assert_stat_equal(self, stat1, stat2, skip_fields): for attr in dir(stat1): if not attr.startswith("st_"): continue - if attr in ("st_dev", "st_ino", "st_nlink"): + if attr in ("st_dev", "st_ino", "st_nlink", "st_ctime", + "st_ctime_ns"): continue self.assertEqual(getattr(stat1, attr), getattr(stat2, attr), diff --git a/Misc/NEWS.d/next/Windows/2023-02-22-17-26-10.gh-issue-99726.76t957.rst b/Misc/NEWS.d/next/Windows/2023-02-22-17-26-10.gh-issue-99726.76t957.rst new file mode 100644 index 00000000000000..e2578620017894 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2023-02-22-17-26-10.gh-issue-99726.76t957.rst @@ -0,0 +1,2 @@ +Improves correctness of stat results for Windows, and uses faster API when +available diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 7d91f7e4bac76b..e38caf7cc0abee 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -41,6 +41,7 @@ #ifndef MS_WINDOWS # include "posixmodule.h" #else +# include "pycore_fileutils_windows.h" # include "winreparse.h" #endif @@ -668,8 +669,11 @@ PyOS_AfterFork(void) #ifdef MS_WINDOWS /* defined in fileutils.c */ void _Py_time_t_to_FILE_TIME(time_t, int, FILETIME *); -void _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *, - ULONG, struct _Py_stat_struct *); +void _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *, ULONG, + FILE_BASIC_INFO *, FILE_ID_INFO *, + struct _Py_stat_struct *); +void _Py_stat_basic_info_to_stat(FILE_STAT_BASIC_INFORMATION *, + struct _Py_stat_struct *); #endif @@ -1819,12 +1823,39 @@ attributes_from_dir(LPCWSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *re return TRUE; } + +static void +update_st_mode_from_path(const wchar_t *path, DWORD attr, + struct _Py_stat_struct *result) +{ + if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { + /* Fix the file execute permissions. This hack sets S_IEXEC if + the filename has an extension that is commonly used by files + that CreateProcessW can execute. A real implementation calls + GetSecurityInfo, OpenThreadToken/OpenProcessToken, and + AccessCheck to check for generic read, write, and execute + access. */ + const wchar_t *fileExtension = wcsrchr(path, '.'); + if (fileExtension) { + if (_wcsicmp(fileExtension, L".exe") == 0 || + _wcsicmp(fileExtension, L".bat") == 0 || + _wcsicmp(fileExtension, L".cmd") == 0 || + _wcsicmp(fileExtension, L".com") == 0) { + result->st_mode |= 0111; + } + } + } +} + + static int -win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result, - BOOL traverse) +win32_xstat_slow_impl(const wchar_t *path, struct _Py_stat_struct *result, + BOOL traverse) { HANDLE hFile; BY_HANDLE_FILE_INFORMATION fileInfo; + FILE_BASIC_INFO basicInfo; + FILE_ID_INFO idInfo; FILE_ATTRIBUTE_TAG_INFO tagInfo = { 0 }; DWORD fileType, error; BOOL isUnhandledTag = FALSE; @@ -1954,12 +1985,16 @@ win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result, for an unhandled tag. */ } else if (!isUnhandledTag) { CloseHandle(hFile); - return win32_xstat_impl(path, result, TRUE); + return win32_xstat_slow_impl(path, result, TRUE); } } } - if (!GetFileInformationByHandle(hFile, &fileInfo)) { + if (!GetFileInformationByHandle(hFile, &fileInfo) || + !GetFileInformationByHandleEx(hFile, FileBasicInfo, + &basicInfo, sizeof(basicInfo)) || + !GetFileInformationByHandleEx(hFile, FileIdInfo, + &idInfo, sizeof(idInfo))) { switch (GetLastError()) { case ERROR_INVALID_PARAMETER: case ERROR_INVALID_FUNCTION: @@ -1975,25 +2010,8 @@ win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result, } } - _Py_attribute_data_to_stat(&fileInfo, tagInfo.ReparseTag, result); - - if (!(fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - /* Fix the file execute permissions. This hack sets S_IEXEC if - the filename has an extension that is commonly used by files - that CreateProcessW can execute. A real implementation calls - GetSecurityInfo, OpenThreadToken/OpenProcessToken, and - AccessCheck to check for generic read, write, and execute - access. */ - const wchar_t *fileExtension = wcsrchr(path, '.'); - if (fileExtension) { - if (_wcsicmp(fileExtension, L".exe") == 0 || - _wcsicmp(fileExtension, L".bat") == 0 || - _wcsicmp(fileExtension, L".cmd") == 0 || - _wcsicmp(fileExtension, L".com") == 0) { - result->st_mode |= 0111; - } - } - } + _Py_attribute_data_to_stat(&fileInfo, tagInfo.ReparseTag, &basicInfo, &idInfo, result); + update_st_mode_from_path(path, fileInfo.dwFileAttributes, result); cleanup: if (hFile != INVALID_HANDLE_VALUE) { @@ -2010,6 +2028,39 @@ win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result, return retval; } +static int +win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result, + BOOL traverse) +{ + FILE_STAT_BASIC_INFORMATION statInfo; + if (_Py_GetFileInformationByName(path, FileStatBasicByNameInfo, + &statInfo, sizeof(statInfo))) { + if (// Cannot use fast path for reparse points ... + !(statInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + // ... unless it's a name surrogate (symlink) and we're not following + || (!traverse && IsReparseTagNameSurrogate(statInfo.ReparseTag)) + ) { + _Py_stat_basic_info_to_stat(&statInfo, result); + update_st_mode_from_path(path, statInfo.FileAttributes, result); + return 0; + } + } else { + switch(GetLastError()) { + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_NOT_READY: + case ERROR_BAD_NET_NAME: + /* These errors aren't worth retrying with the slow path */ + return -1; + case ERROR_NOT_SUPPORTED: + /* indicates the API couldn't be loaded */ + break; + } + } + + return win32_xstat_slow_impl(path, result, traverse); +} + static int win32_xstat(const wchar_t *path, struct _Py_stat_struct *result, BOOL traverse) { @@ -2017,6 +2068,10 @@ win32_xstat(const wchar_t *path, struct _Py_stat_struct *result, BOOL traverse) setting it to a POSIX error. Callers should use GetLastError. */ int code = win32_xstat_impl(path, result, traverse); errno = 0; + + /* ctime is only deprecated from 3.12, so we copy birthtime across */ + result->st_ctime = result->st_birthtime; + result->st_ctime_nsec = result->st_birthtime_nsec; return code; } /* About the following functions: win32_lstat_w, win32_stat, win32_stat_w @@ -2087,9 +2142,12 @@ static PyStructSequence_Field stat_result_fields[] = { #ifdef HAVE_STRUCT_STAT_ST_GEN {"st_gen", "generation number"}, #endif -#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME +#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) || defined(MS_WINDOWS) {"st_birthtime", "time of creation"}, #endif +#ifdef MS_WINDOWS + {"st_birthtime_ns", "time of creation in nanoseconds"}, +#endif #ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES {"st_file_attributes", "Windows file attribute bits"}, #endif @@ -2132,16 +2190,22 @@ static PyStructSequence_Field stat_result_fields[] = { #define ST_GEN_IDX ST_FLAGS_IDX #endif -#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME +#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) || defined(MS_WINDOWS) #define ST_BIRTHTIME_IDX (ST_GEN_IDX+1) #else #define ST_BIRTHTIME_IDX ST_GEN_IDX #endif -#ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES -#define ST_FILE_ATTRIBUTES_IDX (ST_BIRTHTIME_IDX+1) +#ifdef MS_WINDOWS +#define ST_BIRTHTIME_NS_IDX (ST_BIRTHTIME_IDX+1) #else -#define ST_FILE_ATTRIBUTES_IDX ST_BIRTHTIME_IDX +#define ST_BIRTHTIME_NS_IDX ST_BIRTHTIME_IDX +#endif + +#if defined(HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES) || defined(MS_WINDOWS) +#define ST_FILE_ATTRIBUTES_IDX (ST_BIRTHTIME_NS_IDX+1) +#else +#define ST_FILE_ATTRIBUTES_IDX ST_BIRTHTIME_NS_IDX #endif #ifdef HAVE_STRUCT_STAT_ST_FSTYPE @@ -2310,7 +2374,7 @@ _posix_free(void *module) } static void -fill_time(PyObject *module, PyObject *v, int index, time_t sec, unsigned long nsec) +fill_time(PyObject *module, PyObject *v, int s_index, int f_index, int ns_index, time_t sec, unsigned long nsec) { PyObject *s = _PyLong_FromTime_t(sec); PyObject *ns_fractional = PyLong_FromUnsignedLong(nsec); @@ -2334,12 +2398,18 @@ fill_time(PyObject *module, PyObject *v, int index, time_t sec, unsigned long ns goto exit; } - PyStructSequence_SET_ITEM(v, index, s); - PyStructSequence_SET_ITEM(v, index+3, float_s); - PyStructSequence_SET_ITEM(v, index+6, ns_total); - s = NULL; - float_s = NULL; - ns_total = NULL; + if (s_index >= 0) { + PyStructSequence_SET_ITEM(v, s_index, s); + s = NULL; + } + if (f_index >= 0) { + PyStructSequence_SET_ITEM(v, f_index, float_s); + float_s = NULL; + } + if (ns_index >= 0) { + PyStructSequence_SET_ITEM(v, ns_index, ns_total); + ns_total = NULL; + } exit: Py_XDECREF(s); Py_XDECREF(ns_fractional); @@ -2348,6 +2418,33 @@ fill_time(PyObject *module, PyObject *v, int index, time_t sec, unsigned long ns Py_XDECREF(float_s); } +#ifdef MS_WINDOWS +static PyObject* +_pystat_l128_from_l64_l64(uint64_t low, uint64_t high) +{ + PyObject *o_low = PyLong_FromUnsignedLongLong(low); + if (!o_low || !high) { + return o_low; + } + PyObject *o_high = PyLong_FromUnsignedLongLong(high); + PyObject *l64 = o_high ? PyLong_FromLong(64) : NULL; + if (!l64) { + Py_XDECREF(o_high); + Py_DECREF(o_low); + return NULL; + } + Py_SETREF(o_high, PyNumber_Lshift(o_high, l64)); + Py_DECREF(l64); + if (!o_high) { + Py_DECREF(o_low); + return NULL; + } + Py_SETREF(o_low, PyNumber_Add(o_low, o_high)); + Py_DECREF(o_high); + return o_low; +} +#endif + /* pack a system stat C structure into the Python stat tuple (used by posix_stat() and posix_fstat()) */ static PyObject* @@ -2360,12 +2457,13 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) return NULL; PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long)st->st_mode)); +#ifdef MS_WINDOWS + PyStructSequence_SET_ITEM(v, 1, _pystat_l128_from_l64_l64(st->st_ino, st->st_ino_high)); + PyStructSequence_SET_ITEM(v, 2, PyLong_FromUnsignedLongLong(st->st_dev)); +#else static_assert(sizeof(unsigned long long) >= sizeof(st->st_ino), "stat.st_ino is larger than unsigned long long"); PyStructSequence_SET_ITEM(v, 1, PyLong_FromUnsignedLongLong(st->st_ino)); -#ifdef MS_WINDOWS - PyStructSequence_SET_ITEM(v, 2, PyLong_FromUnsignedLong(st->st_dev)); -#else PyStructSequence_SET_ITEM(v, 2, _PyLong_FromDev(st->st_dev)); #endif PyStructSequence_SET_ITEM(v, 3, PyLong_FromLong((long)st->st_nlink)); @@ -2395,9 +2493,9 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) #else ansec = mnsec = cnsec = 0; #endif - fill_time(module, v, 7, st->st_atime, ansec); - fill_time(module, v, 8, st->st_mtime, mnsec); - fill_time(module, v, 9, st->st_ctime, cnsec); + fill_time(module, v, 7, 10, 13, st->st_atime, ansec); + fill_time(module, v, 8, 11, 14, st->st_mtime, mnsec); + fill_time(module, v, 9, 12, 15, st->st_ctime, cnsec); #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE PyStructSequence_SET_ITEM(v, ST_BLKSIZE_IDX, @@ -2415,7 +2513,7 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) PyStructSequence_SET_ITEM(v, ST_GEN_IDX, PyLong_FromLong((long)st->st_gen)); #endif -#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME +#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME) { PyObject *val; unsigned long bsec,bnsec; @@ -2429,6 +2527,9 @@ _pystat_fromstructstat(PyObject *module, STRUCT_STAT *st) PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX, val); } +#elif defined(MS_WINDOWS) + fill_time(module, v, -1, ST_BIRTHTIME_IDX, ST_BIRTHTIME_NS_IDX, + st->st_birthtime, st->st_birthtime_nsec); #endif #ifdef HAVE_STRUCT_STAT_ST_FLAGS PyStructSequence_SET_ITEM(v, ST_FLAGS_IDX, @@ -14639,7 +14740,7 @@ DirEntry_from_find_data(PyObject *module, path_t *path, WIN32_FIND_DATAW *dataW) } find_data_to_file_info(dataW, &file_info, &reparse_tag); - _Py_attribute_data_to_stat(&file_info, reparse_tag, &entry->win32_lstat); + _Py_attribute_data_to_stat(&file_info, reparse_tag, NULL, NULL, &entry->win32_lstat); return (PyObject *)entry; diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index ed1823faf80bd8..447a6787de8af7 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -216,6 +216,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 77a2b923d70027..b29c2dc62667a6 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -555,6 +555,9 @@ Include\internal + + Include\internal + Include\internal diff --git a/Python/fileutils.c b/Python/fileutils.c index f48b626b444016..969b7163b5ac18 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -8,6 +8,8 @@ #ifdef MS_WINDOWS # include # include +# include // FILE_DEVICE_* constants +# include "pycore_fileutils_windows.h" // FILE_STAT_BASIC_INFORMATION # if defined(MS_WINDOWS_GAMES) && !defined(MS_WINDOWS_DESKTOP) # define PATHCCH_ALLOW_LONG_PATHS 0x01 # else @@ -1056,6 +1058,13 @@ FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, time_t *time_out, int* nsec_out) *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, time_t); } +static void +LARGE_INTEGER_to_time_t_nsec(LARGE_INTEGER *in_ptr, time_t *time_out, int* nsec_out) +{ + *nsec_out = (int)(in_ptr->QuadPart % 10000000) * 100; /* FILETIME is in units of 100 nsec. */ + *time_out = Py_SAFE_DOWNCAST((in_ptr->QuadPart / 10000000) - secs_between_epochs, __int64, time_t); +} + void _Py_time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr) { @@ -1085,33 +1094,126 @@ attributes_to_mode(DWORD attr) return m; } + +typedef union { + FILE_ID_128 id; + struct { + uint64_t st_ino; + uint64_t st_ino_high; + }; +} id_128_to_ino; + + void _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, + FILE_BASIC_INFO *basic_info, FILE_ID_INFO *id_info, struct _Py_stat_struct *result) { memset(result, 0, sizeof(*result)); result->st_mode = attributes_to_mode(info->dwFileAttributes); result->st_size = (((__int64)info->nFileSizeHigh)<<32) + info->nFileSizeLow; - result->st_dev = info->dwVolumeSerialNumber; - result->st_rdev = result->st_dev; - FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_ctime, &result->st_ctime_nsec); - FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec); - FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec); + result->st_dev = id_info ? id_info->VolumeSerialNumber : info->dwVolumeSerialNumber; + result->st_rdev = 0; + /* st_ctime is deprecated, but we preserve the legacy value in our caller, not here */ + if (basic_info) { + LARGE_INTEGER_to_time_t_nsec(&basic_info->CreationTime, &result->st_birthtime, &result->st_birthtime_nsec); + LARGE_INTEGER_to_time_t_nsec(&basic_info->ChangeTime, &result->st_ctime, &result->st_ctime_nsec); + LARGE_INTEGER_to_time_t_nsec(&basic_info->LastWriteTime, &result->st_mtime, &result->st_mtime_nsec); + LARGE_INTEGER_to_time_t_nsec(&basic_info->LastAccessTime, &result->st_atime, &result->st_atime_nsec); + } else { + FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_birthtime, &result->st_birthtime_nsec); + FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec); + FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec); + } result->st_nlink = info->nNumberOfLinks; - result->st_ino = (((uint64_t)info->nFileIndexHigh) << 32) + info->nFileIndexLow; + + if (id_info) { + id_128_to_ino file_id; + file_id.id = id_info->FileId; + result->st_ino = file_id.st_ino; + result->st_ino_high = file_id.st_ino_high; + } else { + /* should only occur for DirEntry_from_find_data, in which case the + index is likely to be zero anyway. */ + result->st_ino = (((uint64_t)info->nFileIndexHigh) << 32) + info->nFileIndexLow; + } + /* bpo-37834: Only actual symlinks set the S_IFLNK flag. But lstat() will open other name surrogate reparse points without traversing them. To detect/handle these, check st_file_attributes and st_reparse_tag. */ result->st_reparse_tag = reparse_tag; if (info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && reparse_tag == IO_REPARSE_TAG_SYMLINK) { - /* first clear the S_IFMT bits */ - result->st_mode ^= (result->st_mode & S_IFMT); - /* now set the bits that make this a symlink */ - result->st_mode |= S_IFLNK; + /* set the bits that make this a symlink */ + result->st_mode = (result->st_mode & ~S_IFMT) | S_IFLNK; } result->st_file_attributes = info->dwFileAttributes; } + +void +_Py_stat_basic_info_to_stat(FILE_STAT_BASIC_INFORMATION *info, + struct _Py_stat_struct *result) +{ + memset(result, 0, sizeof(*result)); + result->st_mode = attributes_to_mode(info->FileAttributes); + result->st_size = info->EndOfFile.QuadPart; + LARGE_INTEGER_to_time_t_nsec(&info->CreationTime, &result->st_birthtime, &result->st_birthtime_nsec); + LARGE_INTEGER_to_time_t_nsec(&info->ChangeTime, &result->st_ctime, &result->st_ctime_nsec); + LARGE_INTEGER_to_time_t_nsec(&info->LastWriteTime, &result->st_mtime, &result->st_mtime_nsec); + LARGE_INTEGER_to_time_t_nsec(&info->LastAccessTime, &result->st_atime, &result->st_atime_nsec); + result->st_nlink = info->NumberOfLinks; + result->st_dev = info->VolumeSerialNumber.QuadPart; + /* File systems with less than 128-bits zero pad into this field */ + id_128_to_ino file_id; + file_id.id = info->FileId128; + result->st_ino = file_id.st_ino; + result->st_ino_high = file_id.st_ino_high; + /* bpo-37834: Only actual symlinks set the S_IFLNK flag. But lstat() will + open other name surrogate reparse points without traversing them. To + detect/handle these, check st_file_attributes and st_reparse_tag. */ + result->st_reparse_tag = info->ReparseTag; + if (info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && + info->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + /* set the bits that make this a symlink */ + result->st_mode = (result->st_mode & ~S_IFMT) | S_IFLNK; + } + result->st_file_attributes = info->FileAttributes; + switch (info->DeviceType) { + case FILE_DEVICE_DISK: + case FILE_DEVICE_VIRTUAL_DISK: + case FILE_DEVICE_DFS: + case FILE_DEVICE_CD_ROM: + case FILE_DEVICE_CONTROLLER: + case FILE_DEVICE_DATALINK: + break; + case FILE_DEVICE_DISK_FILE_SYSTEM: + case FILE_DEVICE_CD_ROM_FILE_SYSTEM: + case FILE_DEVICE_NETWORK_FILE_SYSTEM: + result->st_mode = (result->st_mode & ~S_IFMT) | 0x6000; /* _S_IFBLK */ + break; + case FILE_DEVICE_CONSOLE: + case FILE_DEVICE_NULL: + case FILE_DEVICE_KEYBOARD: + case FILE_DEVICE_MODEM: + case FILE_DEVICE_MOUSE: + case FILE_DEVICE_PARALLEL_PORT: + case FILE_DEVICE_PRINTER: + case FILE_DEVICE_SCREEN: + case FILE_DEVICE_SERIAL_PORT: + case FILE_DEVICE_SOUND: + result->st_mode = (result->st_mode & ~S_IFMT) | _S_IFCHR; + break; + case FILE_DEVICE_NAMED_PIPE: + result->st_mode = (result->st_mode & ~S_IFMT) | _S_IFIFO; + break; + default: + if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + result->st_mode = (result->st_mode & ~S_IFMT) | _S_IFDIR; + } + break; + } +} + #endif /* Return information about a file. @@ -1131,6 +1233,8 @@ _Py_fstat_noraise(int fd, struct _Py_stat_struct *status) { #ifdef MS_WINDOWS BY_HANDLE_FILE_INFORMATION info; + FILE_BASIC_INFO basicInfo; + FILE_ID_INFO idInfo; HANDLE h; int type; @@ -1162,14 +1266,16 @@ _Py_fstat_noraise(int fd, struct _Py_stat_struct *status) return 0; } - if (!GetFileInformationByHandle(h, &info)) { + if (!GetFileInformationByHandle(h, &info) || + !GetFileInformationByHandleEx(h, FileBasicInfo, &basicInfo, sizeof(basicInfo)) || + !GetFileInformationByHandleEx(h, FileIdInfo, &idInfo, sizeof(idInfo))) { /* The Win32 error is already set, but we also set errno for callers who expect it */ errno = winerror_to_errno(GetLastError()); return -1; } - _Py_attribute_data_to_stat(&info, 0, status); + _Py_attribute_data_to_stat(&info, 0, &basicInfo, &idInfo, status); return 0; #else return fstat(fd, status); From 93e32d6b9320088c844e39a311b3f4be32c9d011 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Thu, 16 Mar 2023 19:03:52 +0000 Subject: [PATCH 133/280] gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives (#102760) --- Python/traceback.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Python/traceback.c b/Python/traceback.c index 31b85e77575efa..097f69c76abfe1 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -11,7 +11,7 @@ #include "pycore_interp.h" // PyInterpreterState.gc #include "pycore_parser.h" // _PyParser_ASTFromString #include "pycore_pyarena.h" // _PyArena_Free() -#include "pycore_pyerrors.h" // _PyErr_Fetch() +#include "pycore_pyerrors.h" // _PyErr_GetRaisedException() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_traceback.h" // EXCEPTION_TB_HEADER @@ -242,17 +242,18 @@ _PyTraceBack_FromFrame(PyObject *tb_next, PyFrameObject *frame) int PyTraceBack_Here(PyFrameObject *frame) { - PyObject *exc, *val, *tb, *newtb; - PyErr_Fetch(&exc, &val, &tb); - newtb = _PyTraceBack_FromFrame(tb, frame); + PyObject *exc = PyErr_GetRaisedException(); + assert(PyExceptionInstance_Check(exc)); + PyObject *tb = PyException_GetTraceback(exc); + PyObject *newtb = _PyTraceBack_FromFrame(tb, frame); + Py_XDECREF(tb); if (newtb == NULL) { - _PyErr_ChainExceptions(exc, val, tb); + _PyErr_ChainExceptions1(exc); return -1; } - assert(PyExceptionInstance_Check(val)); - PyException_SetTraceback(val, newtb); - PyErr_Restore(exc, val, newtb); - Py_XDECREF(tb); + PyException_SetTraceback(exc, newtb); + Py_XDECREF(newtb); + PyErr_SetRaisedException(exc); return 0; } From 2c96fc0064cd3095ceaa6fa0f210f274a7021eae Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Thu, 16 Mar 2023 20:34:42 +0000 Subject: [PATCH 134/280] Fix outdated note about 'int' rounding or truncating (#102736) --- Doc/library/stdtypes.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 550f808a16dfaa..bcfc6e5cfce611 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -335,11 +335,10 @@ Notes: single: ceil() (in module math) single: trunc() (in module math) pair: numeric; conversions - pair: C; language - Conversion from floating point to integer may round or truncate - as in C; see functions :func:`math.floor` and :func:`math.ceil` for - well-defined conversions. + Conversion from :class:`float` to :class:`int` truncates, discarding the + fractional part. See functions :func:`math.floor` and :func:`math.ceil` for + alternative conversions. (4) float also accepts the strings "nan" and "inf" with an optional prefix "+" From dd639e70aa664251ce5d3803376f10c038ebb4b5 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Thu, 16 Mar 2023 22:18:04 +0000 Subject: [PATCH 135/280] gh-102755: Add PyErr_DisplayException(exc) (#102756) --- Doc/c-api/exceptions.rst | 6 ++ Doc/data/stable_abi.dat | 1 + Doc/whatsnew/3.12.rst | 7 ++ Include/internal/pycore_pylifecycle.h | 1 + Include/pythonrun.h | 1 + Lib/test/test_stable_abi_ctypes.py | 1 + ...-03-16-14-44-29.gh-issue-102755.j1GxlV.rst | 3 + Misc/stable_abi.toml | 2 + Modules/_testcapi/exceptions.c | 13 +-- PC/python3dll.c | 1 + Python/pylifecycle.c | 29 ++----- Python/pythonrun.c | 87 +++++++++---------- Python/sysmodule.c | 2 +- 13 files changed, 76 insertions(+), 78 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-03-16-14-44-29.gh-issue-102755.j1GxlV.rst diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 8836c973f1f579..ddf7dc780b2745 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -86,6 +86,12 @@ Printing and clearing An exception must be set when calling this function. +.. c:function: void PyErr_DisplayException(PyObject *exc) + + Print the standard traceback display of ``exc`` to ``sys.stderr``, including + chained exceptions and notes. + + .. versionadded:: 3.12 Raising exceptions ================== diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 68ab0b5061f434..4cc06d22baaa93 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -133,6 +133,7 @@ function,PyErr_BadInternalCall,3.2,, function,PyErr_CheckSignals,3.2,, function,PyErr_Clear,3.2,, function,PyErr_Display,3.2,, +function,PyErr_DisplayException,3.12,, function,PyErr_ExceptionMatches,3.2,, function,PyErr_Fetch,3.2,, function,PyErr_Format,3.2,, diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 03b1f975746787..a398cd93f73120 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -944,6 +944,10 @@ New Features the :attr:`~BaseException.args` passed to the exception's constructor. (Contributed by Mark Shannon in :gh:`101578`.) +* Add :c:func:`PyErr_DisplayException`, which takes an exception instance, + to replace the legacy-api :c:func:`PyErr_Display`. (Contributed by + Irit Katriel in :gh:`102755`). + Porting to Python 3.12 ---------------------- @@ -1077,6 +1081,9 @@ Deprecated :c:func:`PyErr_SetRaisedException` instead. (Contributed by Mark Shannon in :gh:`101578`.) +* :c:func:`PyErr_Display` is deprecated. Use :c:func:`PyErr_DisplayException` + instead. (Contributed by Irit Katriel in :gh:`102755`). + Removed ------- diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index e7a31807205254..a899e848bb8b3c 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -87,6 +87,7 @@ PyAPI_FUNC(PyObject*) _PyErr_WriteUnraisableDefaultHook(PyObject *unraisable); PyAPI_FUNC(void) _PyErr_Print(PyThreadState *tstate); PyAPI_FUNC(void) _PyErr_Display(PyObject *file, PyObject *exception, PyObject *value, PyObject *tb); +PyAPI_FUNC(void) _PyErr_DisplayException(PyObject *file, PyObject *exc); PyAPI_FUNC(void) _PyThreadState_DeleteCurrent(PyThreadState *tstate); diff --git a/Include/pythonrun.h b/Include/pythonrun.h index 1b208b734ab1bf..41d82e89f84876 100644 --- a/Include/pythonrun.h +++ b/Include/pythonrun.h @@ -12,6 +12,7 @@ PyAPI_FUNC(PyObject *) Py_CompileString(const char *, const char *, int); PyAPI_FUNC(void) PyErr_Print(void); PyAPI_FUNC(void) PyErr_PrintEx(int); PyAPI_FUNC(void) PyErr_Display(PyObject *, PyObject *, PyObject *); +PyAPI_FUNC(void) PyErr_DisplayException(PyObject *); /* Stuff with no proper home (yet) */ diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index e77c1c8409880d..2feaaf8603b831 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -166,6 +166,7 @@ def test_windows_feature_macros(self): "PyErr_CheckSignals", "PyErr_Clear", "PyErr_Display", + "PyErr_DisplayException", "PyErr_ExceptionMatches", "PyErr_Fetch", "PyErr_Format", diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-16-14-44-29.gh-issue-102755.j1GxlV.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-16-14-44-29.gh-issue-102755.j1GxlV.rst new file mode 100644 index 00000000000000..d09af8d060d405 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-16-14-44-29.gh-issue-102755.j1GxlV.rst @@ -0,0 +1,3 @@ +Add :c:func:`PyErr_DisplayException` which takes just an exception instance, +to replace the legacy :c:func:`PyErr_Display` which takes the ``(typ, exc, +tb)`` triplet. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 21ff9616133445..23baeeeae79193 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -609,6 +609,8 @@ added = '3.2' [function.PyErr_Display] added = '3.2' +[function.PyErr_DisplayException] + added = '3.12' [function.PyErr_ExceptionMatches] added = '3.2' [function.PyErr_Fetch] diff --git a/Modules/_testcapi/exceptions.c b/Modules/_testcapi/exceptions.c index c64b823663c32f..1922ca3beb7916 100644 --- a/Modules/_testcapi/exceptions.c +++ b/Modules/_testcapi/exceptions.c @@ -39,20 +39,13 @@ err_restore(PyObject *self, PyObject *args) { static PyObject * exception_print(PyObject *self, PyObject *args) { - PyObject *value; - PyObject *tb = NULL; + PyObject *exc; - if (!PyArg_ParseTuple(args, "O:exception_print", &value)) { + if (!PyArg_ParseTuple(args, "O:exception_print", &exc)) { return NULL; } - if (PyExceptionInstance_Check(value)) { - tb = PyException_GetTraceback(value); - } - - PyErr_Display((PyObject *) Py_TYPE(value), value, tb); - Py_XDECREF(tb); - + PyErr_DisplayException(exc); Py_RETURN_NONE; } diff --git a/PC/python3dll.c b/PC/python3dll.c index e300819365756e..706affa18351b3 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -192,6 +192,7 @@ EXPORT_FUNC(PyErr_BadInternalCall) EXPORT_FUNC(PyErr_CheckSignals) EXPORT_FUNC(PyErr_Clear) EXPORT_FUNC(PyErr_Display) +EXPORT_FUNC(PyErr_DisplayException) EXPORT_FUNC(PyErr_ExceptionMatches) EXPORT_FUNC(PyErr_Fetch) EXPORT_FUNC(PyErr_Format) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 82e94090a6027a..d0c65cc1f7fd44 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2537,41 +2537,28 @@ _Py_FatalError_DumpTracebacks(int fd, PyInterpreterState *interp, static int _Py_FatalError_PrintExc(PyThreadState *tstate) { - PyObject *ferr, *res; - PyObject *exception, *v, *tb; - int has_tb; - - _PyErr_Fetch(tstate, &exception, &v, &tb); - if (exception == NULL) { + PyObject *exc = _PyErr_GetRaisedException(tstate); + if (exc == NULL) { /* No current exception */ return 0; } - ferr = _PySys_GetAttr(tstate, &_Py_ID(stderr)); + PyObject *ferr = _PySys_GetAttr(tstate, &_Py_ID(stderr)); if (ferr == NULL || ferr == Py_None) { /* sys.stderr is not set yet or set to None, no need to try to display the exception */ return 0; } - _PyErr_NormalizeException(tstate, &exception, &v, &tb); - if (tb == NULL) { - tb = Py_NewRef(Py_None); - } - PyException_SetTraceback(v, tb); - if (exception == NULL) { - /* PyErr_NormalizeException() failed */ - return 0; - } + PyErr_DisplayException(exc); - has_tb = (tb != Py_None); - PyErr_Display(exception, v, tb); - Py_XDECREF(exception); - Py_XDECREF(v); + PyObject *tb = PyException_GetTraceback(exc); + int has_tb = (tb != NULL) && (tb != Py_None); Py_XDECREF(tb); + Py_XDECREF(exc); /* sys.stderr may be buffered: call sys.stderr.flush() */ - res = PyObject_CallMethodNoArgs(ferr, &_Py_ID(flush)); + PyObject *res = PyObject_CallMethodNoArgs(ferr, &_Py_ID(flush)); if (res == NULL) { _PyErr_Clear(tstate); } diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 5381b105a39fed..07d119a67847c6 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -761,39 +761,34 @@ handle_system_exit(void) static void _PyErr_PrintEx(PyThreadState *tstate, int set_sys_last_vars) { - PyObject *exception, *v, *tb, *hook; - + PyObject *typ = NULL, *tb = NULL; handle_system_exit(); - _PyErr_Fetch(tstate, &exception, &v, &tb); - if (exception == NULL) { + PyObject *exc = _PyErr_GetRaisedException(tstate); + if (exc == NULL) { goto done; } - - _PyErr_NormalizeException(tstate, &exception, &v, &tb); + assert(PyExceptionInstance_Check(exc)); + typ = Py_NewRef(Py_TYPE(exc)); + tb = PyException_GetTraceback(exc); if (tb == NULL) { tb = Py_NewRef(Py_None); } - PyException_SetTraceback(v, tb); - if (exception == NULL) { - goto done; - } - /* Now we know v != NULL too */ if (set_sys_last_vars) { - if (_PySys_SetAttr(&_Py_ID(last_type), exception) < 0) { + if (_PySys_SetAttr(&_Py_ID(last_type), typ) < 0) { _PyErr_Clear(tstate); } - if (_PySys_SetAttr(&_Py_ID(last_value), v) < 0) { + if (_PySys_SetAttr(&_Py_ID(last_value), exc) < 0) { _PyErr_Clear(tstate); } if (_PySys_SetAttr(&_Py_ID(last_traceback), tb) < 0) { _PyErr_Clear(tstate); } } - hook = _PySys_GetAttr(tstate, &_Py_ID(excepthook)); + PyObject *hook = _PySys_GetAttr(tstate, &_Py_ID(excepthook)); if (_PySys_Audit(tstate, "sys.excepthook", "OOOO", hook ? hook : Py_None, - exception, v, tb) < 0) { + typ, exc, tb) < 0) { if (PyErr_ExceptionMatches(PyExc_RuntimeError)) { PyErr_Clear(); goto done; @@ -802,46 +797,34 @@ _PyErr_PrintEx(PyThreadState *tstate, int set_sys_last_vars) } if (hook) { PyObject* stack[3]; - PyObject *result; - - stack[0] = exception; - stack[1] = v; + stack[0] = typ; + stack[1] = exc; stack[2] = tb; - result = _PyObject_FastCall(hook, stack, 3); + PyObject *result = _PyObject_FastCall(hook, stack, 3); if (result == NULL) { handle_system_exit(); - PyObject *exception2, *v2, *tb2; - _PyErr_Fetch(tstate, &exception2, &v2, &tb2); - _PyErr_NormalizeException(tstate, &exception2, &v2, &tb2); - /* It should not be possible for exception2 or v2 - to be NULL. However PyErr_Display() can't - tolerate NULLs, so just be safe. */ - if (exception2 == NULL) { - exception2 = Py_NewRef(Py_None); - } - if (v2 == NULL) { - v2 = Py_NewRef(Py_None); - } + PyObject *exc2 = _PyErr_GetRaisedException(tstate); + assert(exc2 && PyExceptionInstance_Check(exc2)); fflush(stdout); PySys_WriteStderr("Error in sys.excepthook:\n"); - PyErr_Display(exception2, v2, tb2); + PyErr_DisplayException(exc2); PySys_WriteStderr("\nOriginal exception was:\n"); - PyErr_Display(exception, v, tb); - Py_DECREF(exception2); - Py_DECREF(v2); - Py_XDECREF(tb2); + PyErr_DisplayException(exc); + Py_DECREF(exc2); + } + else { + Py_DECREF(result); } - Py_XDECREF(result); } else { PySys_WriteStderr("sys.excepthook is missing\n"); - PyErr_Display(exception, v, tb); + PyErr_DisplayException(exc); } done: - Py_XDECREF(exception); - Py_XDECREF(v); + Py_XDECREF(typ); + Py_XDECREF(exc); Py_XDECREF(tb); } @@ -1505,7 +1488,7 @@ print_exception_recursive(struct exception_print_context *ctx, PyObject *value) #define PyErr_MAX_GROUP_DEPTH 10 void -_PyErr_Display(PyObject *file, PyObject *exception, PyObject *value, PyObject *tb) +_PyErr_Display(PyObject *file, PyObject *unused, PyObject *value, PyObject *tb) { assert(file != NULL && file != Py_None); if (PyExceptionInstance_Check(value) @@ -1513,10 +1496,12 @@ _PyErr_Display(PyObject *file, PyObject *exception, PyObject *value, PyObject *t /* Put the traceback on the exception, otherwise it won't get displayed. See issue #18776. */ PyObject *cur_tb = PyException_GetTraceback(value); - if (cur_tb == NULL) + if (cur_tb == NULL) { PyException_SetTraceback(value, tb); - else + } + else { Py_DECREF(cur_tb); + } } struct exception_print_context ctx; @@ -1552,7 +1537,7 @@ _PyErr_Display(PyObject *file, PyObject *exception, PyObject *value, PyObject *t } void -PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb) +PyErr_Display(PyObject *unused, PyObject *value, PyObject *tb) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *file = _PySys_GetAttr(tstate, &_Py_ID(stderr)); @@ -1565,10 +1550,20 @@ PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb) return; } Py_INCREF(file); - _PyErr_Display(file, exception, value, tb); + _PyErr_Display(file, NULL, value, tb); Py_DECREF(file); } +void _PyErr_DisplayException(PyObject *file, PyObject *exc) +{ + _PyErr_Display(file, NULL, exc, NULL); +} + +void PyErr_DisplayException(PyObject *exc) +{ + PyErr_Display(NULL, exc, NULL); +} + PyObject * PyRun_StringFlags(const char *str, int start, PyObject *globals, PyObject *locals, PyCompilerFlags *flags) diff --git a/Python/sysmodule.c b/Python/sysmodule.c index d282104dcad414..cc5b9a6d418bfa 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -742,7 +742,7 @@ sys_excepthook_impl(PyObject *module, PyObject *exctype, PyObject *value, PyObject *traceback) /*[clinic end generated code: output=18d99fdda21b6b5e input=ecf606fa826f19d9]*/ { - PyErr_Display(exctype, value, traceback); + PyErr_Display(NULL, value, traceback); Py_RETURN_NONE; } From 0405b4505acfa57f4da38f1c2eb13f9fdf0cb1e7 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Fri, 17 Mar 2023 01:07:07 +0000 Subject: [PATCH 136/280] Increase stack reserve size for Windows debug builds to avoid test crashes (GH-102764) --- PCbuild/python.vcxproj | 2 +- PCbuild/pythonw.vcxproj | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/PCbuild/python.vcxproj b/PCbuild/python.vcxproj index d07db3a6815058..f4640454a73070 100644 --- a/PCbuild/python.vcxproj +++ b/PCbuild/python.vcxproj @@ -95,7 +95,7 @@ Console 2000000 - 4000000 + 8000000 diff --git a/PCbuild/pythonw.vcxproj b/PCbuild/pythonw.vcxproj index e7216dec3a1af0..e23635e5ea9411 100644 --- a/PCbuild/pythonw.vcxproj +++ b/PCbuild/pythonw.vcxproj @@ -89,7 +89,8 @@ - 2000000 + 2000000 + 8000000 From 8d2b6b563ad894dd5c92aad3535efb32e72ee0b7 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Fri, 17 Mar 2023 06:58:43 +0530 Subject: [PATCH 137/280] GH-78530: add support for generators in `asyncio.wait` (#102761) --- Doc/library/asyncio-task.rst | 4 ++++ Doc/whatsnew/3.12.rst | 3 +++ Lib/test/test_asyncio/test_tasks.py | 16 ++++++++++++++++ ...2023-03-16-16-43-04.gh-issue-78530.Lr8eq_.rst | 1 + 4 files changed, 24 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2023-03-16-16-43-04.gh-issue-78530.Lr8eq_.rst diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 5f1449e1b599ef..a0900cd25a7731 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -804,6 +804,10 @@ Waiting Primitives .. versionchanged:: 3.11 Passing coroutine objects to ``wait()`` directly is forbidden. + .. versionchanged:: 3.12 + Added support for generators yielding tasks. + + .. function:: as_completed(aws, *, timeout=None) Run :ref:`awaitable objects ` in the *aws* diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index a398cd93f73120..b55b9619fac226 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -241,6 +241,9 @@ asyncio :mod:`asyncio` does not support legacy generator-based coroutines. (Contributed by Kumar Aditya in :gh:`102748`.) +* :func:`asyncio.wait` now accepts generators yielding tasks. + (Contributed by Kumar Aditya in :gh:`78530`.) + inspect ------- diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 5b935b526541a1..731fa0c5a60b9b 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -1373,6 +1373,22 @@ async def foo(): self.assertEqual(res, 42) self.assertAlmostEqual(0.15, loop.time()) + + def test_wait_generator(self): + async def func(a): + return a + + loop = self.new_test_loop() + + async def main(): + tasks = (self.new_task(loop, func(i)) for i in range(10)) + done, pending = await asyncio.wait(tasks, return_when=asyncio.ALL_COMPLETED) + self.assertEqual(len(done), 10) + self.assertEqual(len(pending), 0) + + loop.run_until_complete(main()) + + def test_as_completed(self): def gen(): diff --git a/Misc/NEWS.d/next/Library/2023-03-16-16-43-04.gh-issue-78530.Lr8eq_.rst b/Misc/NEWS.d/next/Library/2023-03-16-16-43-04.gh-issue-78530.Lr8eq_.rst new file mode 100644 index 00000000000000..bdb46d08c5c4af --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-16-16-43-04.gh-issue-78530.Lr8eq_.rst @@ -0,0 +1 @@ +:func:`asyncio.wait` now accepts generators yielding tasks. Patch by Kumar Aditya. From b538145f86a58ffdb365400eaa2c7b82c52aeec2 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Fri, 17 Mar 2023 22:39:09 +0900 Subject: [PATCH 138/280] gh-102701: Fix overflow in dictobject.c (GH-102750) --- Lib/test/test_bigmem.py | 9 +++++++++ .../2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst | 1 + Objects/dictobject.c | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst diff --git a/Lib/test/test_bigmem.py b/Lib/test/test_bigmem.py index 859f1539e20b80..c9ab1c1de9e186 100644 --- a/Lib/test/test_bigmem.py +++ b/Lib/test/test_bigmem.py @@ -1248,6 +1248,15 @@ def test_sort(self, size): self.assertEqual(l[-10:], [5] * 10) +class DictTest(unittest.TestCase): + + @bigmemtest(size=357913941, memuse=160) + def test_dict(self, size): + # https://github.com/python/cpython/issues/102701 + d = dict.fromkeys(range(size)) + d[size] = 1 + + if __name__ == '__main__': if len(sys.argv) > 1: support.set_memlimit(sys.argv[1]) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst new file mode 100644 index 00000000000000..4e1f31893377ba --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-16-17-24-44.gh-issue-102701.iNGVaS.rst @@ -0,0 +1 @@ +Fix overflow when creating very large dict. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 227e438a8dfffc..53f9a380346a0d 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -596,7 +596,7 @@ new_keys_object(PyInterpreterState *interp, uint8_t log2_size, bool unicode) assert(log2_size >= PyDict_LOG_MINSIZE); - usable = USABLE_FRACTION(1< Date: Fri, 17 Mar 2023 11:01:10 -0600 Subject: [PATCH 139/280] gh-102781: fix cwd dependence in cases generator (#102782) --- Tools/cases_generator/generate_cases.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 31b6926f805485..f9369f1ede897e 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -176,8 +176,9 @@ def __init__( self.postfix = "" self.emit_line_directives = emit_line_directives self.lineno = 1 + filename = os.path.relpath(self.stream.name, ROOT) # Make filename more user-friendly and less platform-specific - filename = self.stream.name.replace("\\", "/") + filename = filename.replace("\\", "/") if filename.startswith("./"): filename = filename[2:] if filename.endswith(".new"): @@ -778,6 +779,7 @@ def parse_file(self, filename: str, instrs_idx: dict[str, int]) -> None: with open(filename) as file: src = file.read() + filename = os.path.relpath(filename, ROOT) # Make filename more user-friendly and less platform-specific filename = filename.replace("\\", "/") if filename.startswith("./"): From d451dd05e84894af4505902f0f36af5dd887544e Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Fri, 17 Mar 2023 14:06:52 -0500 Subject: [PATCH 140/280] Simplify and improve accuracy for subnormals in hypot() (GH-102785) --- Modules/mathmodule.c | 63 ++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index ae9e3211c072d8..48cd9a642de150 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -2498,7 +2498,7 @@ verified for 1 billion random inputs with n=5. [7] static inline double vector_norm(Py_ssize_t n, double *vec, double max, int found_nan) { - double x, h, scale, oldcsum, csum = 1.0, frac1 = 0.0, frac2 = 0.0; + double x, h, scale, csum = 1.0, frac1 = 0.0, frac2 = 0.0; DoubleLength pr, sm; int max_e; Py_ssize_t i; @@ -2513,49 +2513,42 @@ vector_norm(Py_ssize_t n, double *vec, double max, int found_nan) return max; } frexp(max, &max_e); - if (max_e >= -1023) { - scale = ldexp(1.0, -max_e); - assert(max * scale >= 0.5); - assert(max * scale < 1.0); + if (max_e < -1023) { + /* When max_e < -1023, ldexp(1.0, -max_e) would overflow. + So we first perform lossless scaling from subnormals back to normals, + then recurse back to vector_norm(), and then finally undo the scaling. + */ for (i=0 ; i < n ; i++) { - x = vec[i]; - assert(Py_IS_FINITE(x) && fabs(x) <= max); + vec[i] /= DBL_MIN; + } + return DBL_MIN * vector_norm(n, vec, max / DBL_MIN, found_nan); + } + scale = ldexp(1.0, -max_e); + assert(max * scale >= 0.5); + assert(max * scale < 1.0); + for (i=0 ; i < n ; i++) { + x = vec[i]; + assert(Py_IS_FINITE(x) && fabs(x) <= max); - x *= scale; - assert(fabs(x) < 1.0); + x *= scale; + assert(fabs(x) < 1.0); - pr = dl_mul(x, x); - assert(pr.hi <= 1.0); + pr = dl_mul(x, x); + assert(pr.hi <= 1.0); - sm = dl_fast_sum(csum, pr.hi); - csum = sm.hi; - frac1 += pr.lo; - frac2 += sm.lo; - } - h = sqrt(csum - 1.0 + (frac1 + frac2)); - pr = dl_mul(-h, h); sm = dl_fast_sum(csum, pr.hi); csum = sm.hi; frac1 += pr.lo; frac2 += sm.lo; - x = csum - 1.0 + (frac1 + frac2); - return (h + x / (2.0 * h)) / scale; } - /* When max_e < -1023, ldexp(1.0, -max_e) overflows. - So instead of multiplying by a scale, we just divide by *max*. - */ - for (i=0 ; i < n ; i++) { - x = vec[i]; - assert(Py_IS_FINITE(x) && fabs(x) <= max); - x /= max; - x = x*x; - assert(x <= 1.0); - assert(fabs(csum) >= fabs(x)); - oldcsum = csum; - csum += x; - frac1 += (oldcsum - csum) + x; - } - return max * sqrt(csum - 1.0 + frac1); + h = sqrt(csum - 1.0 + (frac1 + frac2)); + pr = dl_mul(-h, h); + sm = dl_fast_sum(csum, pr.hi); + csum = sm.hi; + frac1 += pr.lo; + frac2 += sm.lo; + x = csum - 1.0 + (frac1 + frac2); + return (h + x / (2.0 * h)) / scale; } #define NUM_STACK_ELEMS 16 From e2e5fa6e794d5fb4a7fda966698b8c21d049c8a5 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Sat, 18 Mar 2023 07:19:38 +0000 Subject: [PATCH 141/280] gh-102799: remove unnecessary calls to sys.exc_info() in tests (#102800) --- Lib/test/test_asyncio/test_unix_events.py | 4 +- Lib/test/test_exceptions.py | 18 +- Lib/test/test_socket.py | 4 +- Lib/test/test_sys.py | 4 +- Lib/test/test_traceback.py | 218 +++++++++++----------- 5 files changed, 124 insertions(+), 124 deletions(-) diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py index 33d0ea15c6de0e..96999470a7c69a 100644 --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py @@ -1889,8 +1889,8 @@ async def test_fork_not_share_event_loop(self): os.write(w, b'LOOP:' + str(id(loop)).encode()) except RuntimeError: os.write(w, b'NO LOOP') - except: - os.write(w, b'ERROR:' + ascii(sys.exc_info()).encode()) + except BaseException as e: + os.write(w, b'ERROR:' + ascii(e).encode()) finally: os._exit(0) else: diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 4ae71e431c56dc..284f26be717794 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -599,8 +599,8 @@ def test_notes(self): def testWithTraceback(self): try: raise IndexError(4) - except: - tb = sys.exc_info()[2] + except Exception as e: + tb = e.__traceback__ e = BaseException().with_traceback(tb) self.assertIsInstance(e, BaseException) @@ -653,8 +653,8 @@ def test_invalid_delattr(self): def testNoneClearsTracebackAttr(self): try: raise IndexError(4) - except: - tb = sys.exc_info()[2] + except Exception as e: + tb = e.__traceback__ e = Exception() e.__traceback__ = tb @@ -1337,11 +1337,11 @@ class MyException(Exception, metaclass=Meta): def g(): try: return g() - except RecursionError: - return sys.exc_info() - e, v, tb = g() - self.assertIsInstance(v, RecursionError, type(v)) - self.assertIn("maximum recursion depth exceeded", str(v)) + except RecursionError as e: + return e + exc = g() + self.assertIsInstance(exc, RecursionError, type(exc)) + self.assertIn("maximum recursion depth exceeded", str(exc)) @cpython_only diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index a313da29b4a4fd..60f106f2d1a1c2 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -5492,10 +5492,10 @@ def alarm_handler(signal, frame): self.fail("caught timeout instead of Alarm") except Alarm: pass - except: + except BaseException as e: self.fail("caught other exception instead of Alarm:" " %s(%s):\n%s" % - (sys.exc_info()[:2] + (traceback.format_exc(),))) + (type(e), e, traceback.format_exc())) else: self.fail("nothing caught") finally: diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index b839985def9a12..fb578c5ae6e5d5 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1649,8 +1649,8 @@ def test_pythontypes(self): check(_ast.AST(), size('P')) try: raise TypeError - except TypeError: - tb = sys.exc_info()[2] + except TypeError as e: + tb = e.__traceback__ # traceback if tb is not None: check(tb, size('2P2i')) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 7ef93b3f0ac332..1c5d1ab82c8e9c 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -296,15 +296,15 @@ class PrintExceptionAtExit(object): def __init__(self): try: x = 1 / 0 - except Exception: - self.exc_info = sys.exc_info() - # self.exc_info[1] (traceback) contains frames: + except Exception as e: + self.exc = e + # self.exc.__traceback__ contains frames: # explicitly clear the reference to self in the current # frame to break a reference cycle self = None def __del__(self): - traceback.print_exception(*self.exc_info) + traceback.print_exception(self.exc) # Keep a reference in the module namespace to call the destructor # when the module is unloaded @@ -923,8 +923,8 @@ def check_traceback_format(self, cleanup_func=None): from _testcapi import traceback_print try: self.some_exception() - except KeyError: - type_, value, tb = sys.exc_info() + except KeyError as e: + tb = e.__traceback__ if cleanup_func is not None: # Clear the inner frames, not this one cleanup_func(tb.tb_next) @@ -1228,8 +1228,8 @@ def __eq__(self, other): except UnhashableException: try: raise ex1 - except UnhashableException: - exc_type, exc_val, exc_tb = sys.exc_info() + except UnhashableException as e: + exc_val = e with captured_output("stderr") as stderr_f: exception_print(exc_val) @@ -2133,8 +2133,8 @@ def assertEqualExcept(actual, expected, ignore): def test_extract_tb(self): try: self.last_raises5() - except Exception: - exc_type, exc_value, tb = sys.exc_info() + except Exception as e: + tb = e.__traceback__ def extract(**kwargs): return traceback.extract_tb(tb, **kwargs) @@ -2160,12 +2160,12 @@ def extract(**kwargs): def test_format_exception(self): try: self.last_raises5() - except Exception: - exc_type, exc_value, tb = sys.exc_info() + except Exception as e: + exc = e # [1:-1] to exclude "Traceback (...)" header and # exception type and value def extract(**kwargs): - return traceback.format_exception(exc_type, exc_value, tb, **kwargs)[1:-1] + return traceback.format_exception(exc, **kwargs)[1:-1] with support.swap_attr(sys, 'tracebacklimit', 1000): nolim = extract() @@ -2203,8 +2203,8 @@ def inner(): try: outer() - except: - type_, value, tb = sys.exc_info() + except BaseException as e: + tb = e.__traceback__ # Initial assertion: there's one local in the inner frame. inner_frame = tb.tb_next.tb_next.tb_next.tb_frame @@ -2282,8 +2282,8 @@ def deeper(): def test_walk_tb(self): try: 1/0 - except Exception: - _, _, tb = sys.exc_info() + except Exception as e: + tb = e.__traceback__ s = list(traceback.walk_tb(tb)) self.assertEqual(len(s), 1) @@ -2386,10 +2386,10 @@ def f(): def g(): try: f() - except: - return sys.exc_info() + except Exception as e: + return e.__traceback__ - exc_info = g() + tb = g() class Skip_G(traceback.StackSummary): def format_frame_summary(self, frame_summary): @@ -2398,7 +2398,7 @@ def format_frame_summary(self, frame_summary): return super().format_frame_summary(frame_summary) stack = Skip_G.extract( - traceback.walk_tb(exc_info[2])).format() + traceback.walk_tb(tb)).format() self.assertEqual(len(stack), 1) lno = f.__code__.co_firstlineno + 1 @@ -2416,17 +2416,17 @@ class TestTracebackException(unittest.TestCase): def test_smoke(self): try: 1/0 - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info) + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(e) expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2])) + traceback.walk_tb(e.__traceback__)) self.assertEqual(None, exc.__cause__) self.assertEqual(None, exc.__context__) self.assertEqual(False, exc.__suppress_context__) self.assertEqual(expected_stack, exc.stack) - self.assertEqual(exc_info[0], exc.exc_type) - self.assertEqual(str(exc_info[1]), str(exc)) + self.assertEqual(type(exc_obj), exc.exc_type) + self.assertEqual(str(exc_obj), str(exc)) def test_from_exception(self): # Check all the parameters are accepted. @@ -2435,9 +2435,10 @@ def foo(): try: foo() except Exception as e: - exc_info = sys.exc_info() + exc_obj = e + tb = e.__traceback__ self.expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2]), limit=1, lookup_lines=False, + traceback.walk_tb(tb), limit=1, lookup_lines=False, capture_locals=True) self.exc = traceback.TracebackException.from_exception( e, limit=1, lookup_lines=False, capture_locals=True) @@ -2447,8 +2448,8 @@ def foo(): self.assertEqual(None, exc.__context__) self.assertEqual(False, exc.__suppress_context__) self.assertEqual(expected_stack, exc.stack) - self.assertEqual(exc_info[0], exc.exc_type) - self.assertEqual(str(exc_info[1]), str(exc)) + self.assertEqual(type(exc_obj), exc.exc_type) + self.assertEqual(str(exc_obj), str(exc)) def test_cause(self): try: @@ -2459,18 +2460,18 @@ def test_cause(self): exc_context = traceback.TracebackException(*exc_info_context) cause = Exception("cause") raise Exception("uh oh") from cause - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info) + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(e) expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2])) + traceback.walk_tb(e.__traceback__)) exc_cause = traceback.TracebackException(Exception, cause, None) self.assertEqual(exc_cause, exc.__cause__) self.assertEqual(exc_context, exc.__context__) self.assertEqual(True, exc.__suppress_context__) self.assertEqual(expected_stack, exc.stack) - self.assertEqual(exc_info[0], exc.exc_type) - self.assertEqual(str(exc_info[1]), str(exc)) + self.assertEqual(type(exc_obj), exc.exc_type) + self.assertEqual(str(exc_obj), str(exc)) def test_context(self): try: @@ -2480,17 +2481,17 @@ def test_context(self): exc_info_context = sys.exc_info() exc_context = traceback.TracebackException(*exc_info_context) raise Exception("uh oh") - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info) + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(e) expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2])) + traceback.walk_tb(e.__traceback__)) self.assertEqual(None, exc.__cause__) self.assertEqual(exc_context, exc.__context__) self.assertEqual(False, exc.__suppress_context__) self.assertEqual(expected_stack, exc.stack) - self.assertEqual(exc_info[0], exc.exc_type) - self.assertEqual(str(exc_info[1]), str(exc)) + self.assertEqual(type(exc_obj), exc.exc_type) + self.assertEqual(str(exc_obj), str(exc)) def test_long_context_chain(self): def f(): @@ -2501,12 +2502,12 @@ def f(): try: f() - except RecursionError: - exc_info = sys.exc_info() + except RecursionError as e: + exc_obj = e else: self.fail("Exception not raised") - te = traceback.TracebackException(*exc_info) + te = traceback.TracebackException.from_exception(exc_obj) res = list(te.format()) # many ZeroDiv errors followed by the RecursionError @@ -2524,18 +2525,18 @@ def test_compact_with_cause(self): finally: cause = Exception("cause") raise Exception("uh oh") from cause - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info, compact=True) + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(exc_obj, compact=True) expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2])) + traceback.walk_tb(exc_obj.__traceback__)) exc_cause = traceback.TracebackException(Exception, cause, None) self.assertEqual(exc_cause, exc.__cause__) self.assertEqual(None, exc.__context__) self.assertEqual(True, exc.__suppress_context__) self.assertEqual(expected_stack, exc.stack) - self.assertEqual(exc_info[0], exc.exc_type) - self.assertEqual(str(exc_info[1]), str(exc)) + self.assertEqual(type(exc_obj), exc.exc_type) + self.assertEqual(str(exc_obj), str(exc)) def test_compact_no_cause(self): try: @@ -2545,37 +2546,37 @@ def test_compact_no_cause(self): exc_info_context = sys.exc_info() exc_context = traceback.TracebackException(*exc_info_context) raise Exception("uh oh") - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info, compact=True) + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(e, compact=True) expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2])) + traceback.walk_tb(exc_obj.__traceback__)) self.assertEqual(None, exc.__cause__) self.assertEqual(exc_context, exc.__context__) self.assertEqual(False, exc.__suppress_context__) self.assertEqual(expected_stack, exc.stack) - self.assertEqual(exc_info[0], exc.exc_type) - self.assertEqual(str(exc_info[1]), str(exc)) + self.assertEqual(type(exc_obj), exc.exc_type) + self.assertEqual(str(exc_obj), str(exc)) def test_no_refs_to_exception_and_traceback_objects(self): try: 1/0 - except Exception: - exc_info = sys.exc_info() + except Exception as e: + exc_obj = e - refcnt1 = sys.getrefcount(exc_info[1]) - refcnt2 = sys.getrefcount(exc_info[2]) - exc = traceback.TracebackException(*exc_info) - self.assertEqual(sys.getrefcount(exc_info[1]), refcnt1) - self.assertEqual(sys.getrefcount(exc_info[2]), refcnt2) + refcnt1 = sys.getrefcount(exc_obj) + refcnt2 = sys.getrefcount(exc_obj.__traceback__) + exc = traceback.TracebackException.from_exception(exc_obj) + self.assertEqual(sys.getrefcount(exc_obj), refcnt1) + self.assertEqual(sys.getrefcount(exc_obj.__traceback__), refcnt2) def test_comparison_basic(self): try: 1/0 - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info) - exc2 = traceback.TracebackException(*exc_info) + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(exc_obj) + exc2 = traceback.TracebackException.from_exception(exc_obj) self.assertIsNot(exc, exc2) self.assertEqual(exc, exc2) self.assertNotEqual(exc, object()) @@ -2594,28 +2595,28 @@ def raise_with_locals(): try: raise_with_locals() - except Exception: - exc_info = sys.exc_info() + except Exception as e: + exc_obj = e - exc = traceback.TracebackException(*exc_info) - exc1 = traceback.TracebackException(*exc_info, limit=10) - exc2 = traceback.TracebackException(*exc_info, limit=2) + exc = traceback.TracebackException.from_exception(exc_obj) + exc1 = traceback.TracebackException.from_exception(exc_obj, limit=10) + exc2 = traceback.TracebackException.from_exception(exc_obj, limit=2) self.assertEqual(exc, exc1) # limit=10 gets all frames self.assertNotEqual(exc, exc2) # limit=2 truncates the output # locals change the output - exc3 = traceback.TracebackException(*exc_info, capture_locals=True) + exc3 = traceback.TracebackException.from_exception(exc_obj, capture_locals=True) self.assertNotEqual(exc, exc3) # there are no locals in the innermost frame - exc4 = traceback.TracebackException(*exc_info, limit=-1) - exc5 = traceback.TracebackException(*exc_info, limit=-1, capture_locals=True) + exc4 = traceback.TracebackException.from_exception(exc_obj, limit=-1) + exc5 = traceback.TracebackException.from_exception(exc_obj, limit=-1, capture_locals=True) self.assertEqual(exc4, exc5) # there are locals in the next-to-innermost frame - exc6 = traceback.TracebackException(*exc_info, limit=-2) - exc7 = traceback.TracebackException(*exc_info, limit=-2, capture_locals=True) + exc6 = traceback.TracebackException.from_exception(exc_obj, limit=-2) + exc7 = traceback.TracebackException.from_exception(exc_obj, limit=-2, capture_locals=True) self.assertNotEqual(exc6, exc7) def test_comparison_equivalent_exceptions_are_equal(self): @@ -2623,8 +2624,8 @@ def test_comparison_equivalent_exceptions_are_equal(self): for _ in range(2): try: 1/0 - except: - excs.append(traceback.TracebackException(*sys.exc_info())) + except Exception as e: + excs.append(traceback.TracebackException.from_exception(e)) self.assertEqual(excs[0], excs[1]) self.assertEqual(list(excs[0].format()), list(excs[1].format())) @@ -2640,9 +2641,9 @@ def __eq__(self, other): except UnhashableException: try: raise ex1 - except UnhashableException: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info) + except UnhashableException as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(exc_obj) formatted = list(exc.format()) self.assertIn('UnhashableException: ex2\n', formatted[2]) self.assertIn('UnhashableException: ex1\n', formatted[6]) @@ -2655,11 +2656,10 @@ def recurse(n): 1/0 try: recurse(10) - except Exception: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info, limit=5) + except Exception as e: + exc = traceback.TracebackException.from_exception(e, limit=5) expected_stack = traceback.StackSummary.extract( - traceback.walk_tb(exc_info[2]), limit=5) + traceback.walk_tb(e.__traceback__), limit=5) self.assertEqual(expected_stack, exc.stack) def test_lookup_lines(self): @@ -2706,9 +2706,9 @@ def f(): x = 12 try: x/0 - except Exception: - return sys.exc_info() - exc = traceback.TracebackException(*f(), capture_locals=True) + except Exception as e: + return e + exc = traceback.TracebackException.from_exception(f(), capture_locals=True) output = StringIO() exc.print(file=output) self.assertEqual( @@ -2723,7 +2723,7 @@ def f(): class TestTracebackException_ExceptionGroups(unittest.TestCase): def setUp(self): super().setUp() - self.eg_info = self._get_exception_group() + self.eg = self._get_exception_group() def _get_exception_group(self): def f(): @@ -2753,26 +2753,26 @@ def g(v): except Exception as e: exc4 = e raise ExceptionGroup("eg2", [exc3, exc4]) - except ExceptionGroup: - return sys.exc_info() + except ExceptionGroup as eg: + return eg self.fail('Exception Not Raised') def test_exception_group_construction(self): - eg_info = self.eg_info - teg1 = traceback.TracebackException(*eg_info) - teg2 = traceback.TracebackException.from_exception(eg_info[1]) + eg = self.eg + teg1 = traceback.TracebackException(type(eg), eg, eg.__traceback__) + teg2 = traceback.TracebackException.from_exception(eg) self.assertIsNot(teg1, teg2) self.assertEqual(teg1, teg2) def test_exception_group_format_exception_only(self): - teg = traceback.TracebackException(*self.eg_info) + teg = traceback.TracebackException.from_exception(self.eg) formatted = ''.join(teg.format_exception_only()).split('\n') expected = "ExceptionGroup: eg2 (2 sub-exceptions)\n".split('\n') self.assertEqual(formatted, expected) def test_exception_group_format(self): - teg = traceback.TracebackException(*self.eg_info) + teg = traceback.TracebackException.from_exception(self.eg) formatted = ''.join(teg.format()).split('\n') lno_f = self.lno_f @@ -2884,18 +2884,18 @@ def test_max_group_depth(self): def test_comparison(self): try: - raise self.eg_info[1] - except ExceptionGroup: - exc_info = sys.exc_info() + raise self.eg + except ExceptionGroup as e: + exc = e for _ in range(5): try: - raise exc_info[1] - except: - exc_info = sys.exc_info() - exc = traceback.TracebackException(*exc_info) - exc2 = traceback.TracebackException(*exc_info) - exc3 = traceback.TracebackException(*exc_info, limit=300) - ne = traceback.TracebackException(*exc_info, limit=3) + raise exc + except Exception as e: + exc_obj = e + exc = traceback.TracebackException.from_exception(exc_obj) + exc2 = traceback.TracebackException.from_exception(exc_obj) + exc3 = traceback.TracebackException.from_exception(exc_obj, limit=300) + ne = traceback.TracebackException.from_exception(exc_obj, limit=3) self.assertIsNot(exc, exc2) self.assertEqual(exc, exc2) self.assertEqual(exc, exc3) From b019008c9ac5d9c97fdff6094dc979e03504143a Mon Sep 17 00:00:00 2001 From: gaogaotiantian Date: Sat, 18 Mar 2023 03:59:21 -0700 Subject: [PATCH 142/280] gh-101975: Fixed a potential SegFault on garbage collection (GH-102803) --- .../2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst | 1 + Python/ceval_macros.h | 1 + 2 files changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst new file mode 100644 index 00000000000000..28c9a8465180db --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-18-02-36-39.gh-issue-101975.HwMR1d.rst @@ -0,0 +1 @@ +Fixed ``stacktop`` value on tracing entries to avoid corruption on garbage collection. diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 9fbec87988e4ae..2a7f35e8e43ece 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -314,6 +314,7 @@ GETITEM(PyObject *v, Py_ssize_t i) { _PyFrame_SetStackPointer(frame, stack_pointer); \ int err = trace_function_entry(tstate, frame); \ stack_pointer = _PyFrame_GetStackPointer(frame); \ + frame->stacktop = -1; \ if (err) { \ goto error; \ } \ From 0d8548871823ee94e781c9a671da667c8cddd031 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Sat, 18 Mar 2023 11:47:11 +0000 Subject: [PATCH 143/280] gh-102778: Add sys.last_exc, deprecate sys.last_type, sys.last_value,sys.last_traceback (#102779) --- Doc/library/sys.rst | 25 +++++++++++-------- Doc/whatsnew/3.12.rst | 10 ++++++++ Lib/code.py | 4 ++- Lib/dis.py | 5 +++- Lib/idlelib/idle_test/test_stackviewer.py | 3 ++- Lib/idlelib/pyshell.py | 7 ++++-- Lib/idlelib/run.py | 2 ++ Lib/idlelib/stackviewer.py | 21 +++++++++++----- Lib/pdb.py | 6 ++++- Lib/pydoc_data/topics.py | 4 +-- Lib/test/test_dis.py | 10 +++++++- Lib/test/test_ttk/test_extensions.py | 4 ++- Lib/tkinter/__init__.py | 1 + Lib/traceback.py | 16 +++++++----- ...-03-17-13-43-34.gh-issue-102778.ANDv8I.rst | 3 +++ Python/pylifecycle.c | 2 +- Python/pythonrun.c | 4 +++ Python/sysmodule.c | 6 +++-- 18 files changed, 97 insertions(+), 36 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index a53d4908783e15..b3b9b5e74ac068 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1102,22 +1102,25 @@ always available. .. versionadded:: 3.5 +.. data:: last_exc + + This variable is not always defined; it is set to the exception instance + when an exception is not handled and the interpreter prints an error message + and a stack traceback. Its intended use is to allow an interactive user to + import a debugger module and engage in post-mortem debugging without having + to re-execute the command that caused the error. (Typical use is + ``import pdb; pdb.pm()`` to enter the post-mortem debugger; see :mod:`pdb` + module for more information.) + + .. versionadded:: 3.12 .. data:: last_type last_value last_traceback - These three variables are not always defined; they are set when an exception is - not handled and the interpreter prints an error message and a stack traceback. - Their intended use is to allow an interactive user to import a debugger module - and engage in post-mortem debugging without having to re-execute the command - that caused the error. (Typical use is ``import pdb; pdb.pm()`` to enter the - post-mortem debugger; see :mod:`pdb` module for - more information.) - - The meaning of the variables is the same as that of the return values from - :func:`exc_info` above. - + These three variables are deprecated; use :data:`sys.last_exc` instead. + They hold the legacy representation of ``sys.last_exc``, as returned + from :func:`exc_info` above. .. data:: maxsize diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index b55b9619fac226..32fec962560ae1 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -397,6 +397,12 @@ sys with contributions from Gregory P. Smith [Google] and Mark Shannon in :gh:`96123`.) +* Add :data:`sys.last_exc` which holds the last unhandled exception that + was raised (for post-mortem debugging use cases). Deprecate the + three fields that have the same information in its legacy form: + :data:`sys.last_type`, :data:`sys.last_value` and :data:`sys.last_traceback`. + (Contributed by Irit Katriel in :gh:`102778`.) + Optimizations ============= @@ -488,6 +494,10 @@ Deprecated contain the creation time, which is also available in the new ``st_birthtime`` field. (Contributed by Steve Dower in :gh:`99726`.) +* The :data:`sys.last_type`, :data:`sys.last_value` and :data:`sys.last_traceback` + fields are deprecated. Use :data:`sys.last_exc` instead. + (Contributed by Irit Katriel in :gh:`102778`.) + Pending Removal in Python 3.13 ------------------------------ diff --git a/Lib/code.py b/Lib/code.py index 76000f8c8b2c1e..2bd5fa3e795a61 100644 --- a/Lib/code.py +++ b/Lib/code.py @@ -106,6 +106,7 @@ def showsyntaxerror(self, filename=None): """ type, value, tb = sys.exc_info() + sys.last_exc = value sys.last_type = type sys.last_value = value sys.last_traceback = tb @@ -119,7 +120,7 @@ def showsyntaxerror(self, filename=None): else: # Stuff in the right filename value = SyntaxError(msg, (filename, lineno, offset, line)) - sys.last_value = value + sys.last_exc = sys.last_value = value if sys.excepthook is sys.__excepthook__: lines = traceback.format_exception_only(type, value) self.write(''.join(lines)) @@ -138,6 +139,7 @@ def showtraceback(self): """ sys.last_type, sys.last_value, last_tb = ei = sys.exc_info() sys.last_traceback = last_tb + sys.last_exc = ei[1] try: lines = traceback.format_exception(ei[0], ei[1], last_tb.tb_next) if sys.excepthook is sys.__excepthook__: diff --git a/Lib/dis.py b/Lib/dis.py index 9d3cc60e7f57f7..844acd56f84ff0 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -132,7 +132,10 @@ def distb(tb=None, *, file=None, show_caches=False, adaptive=False): """Disassemble a traceback (default: last traceback).""" if tb is None: try: - tb = sys.last_traceback + if hasattr(sys, 'last_exc'): + tb = sys.last_exc.__traceback__ + else: + tb = sys.last_traceback except AttributeError: raise RuntimeError("no last traceback to disassemble") from None while tb.tb_next: tb = tb.tb_next diff --git a/Lib/idlelib/idle_test/test_stackviewer.py b/Lib/idlelib/idle_test/test_stackviewer.py index 98f53f9537bb25..f4626bb1702a30 100644 --- a/Lib/idlelib/idle_test/test_stackviewer.py +++ b/Lib/idlelib/idle_test/test_stackviewer.py @@ -19,6 +19,7 @@ def setUpClass(cls): except NameError: svs.last_type, svs.last_value, svs.last_traceback = ( sys.exc_info()) + svs.last_exc = svs.last_value requires('gui') cls.root = Tk() @@ -27,7 +28,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): svs = stackviewer.sys - del svs.last_traceback, svs.last_type, svs.last_value + del svs.last_exc, svs.last_traceback, svs.last_type, svs.last_value cls.root.update_idletasks() ## for id in cls.root.tk.call('after', 'info'): diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index e68233a5a4131e..edc77ff26f62f7 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -1367,11 +1367,14 @@ def open_stack_viewer(self, event=None): if self.interp.rpcclt: return self.interp.remote_stack_viewer() try: - sys.last_traceback + if hasattr(sys, 'last_exc'): + sys.last_exc.__traceback__ + else: + sys.last_traceback except: messagebox.showerror("No stack trace", "There is no stack trace yet.\n" - "(sys.last_traceback is not defined)", + "(sys.last_exc and sys.last_traceback are not defined)", parent=self.text) return from idlelib.stackviewer import StackBrowser diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 577c49eb67b20d..6a7b50cf5cfb27 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -239,6 +239,7 @@ def print_exception(): efile = sys.stderr typ, val, tb = excinfo = sys.exc_info() sys.last_type, sys.last_value, sys.last_traceback = excinfo + sys.last_exc = val seen = set() def print_exc(typ, exc, tb): @@ -629,6 +630,7 @@ def stackviewer(self, flist_oid=None): flist = self.rpchandler.get_remote_proxy(flist_oid) while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]: tb = tb.tb_next + sys.last_exc = val sys.last_type = typ sys.last_value = val item = stackviewer.StackTreeItem(flist, tb) diff --git a/Lib/idlelib/stackviewer.py b/Lib/idlelib/stackviewer.py index 94ffb4eff4dd26..702fd32ca5d1bd 100644 --- a/Lib/idlelib/stackviewer.py +++ b/Lib/idlelib/stackviewer.py @@ -27,7 +27,10 @@ def __init__(self, flist=None, tb=None): def get_stack(self, tb): if tb is None: - tb = sys.last_traceback + if hasattr(sys, 'last_exc'): + tb = sys.last_exc.__traceback__ + else: + tb = sys.last_traceback stack = [] if tb and tb.tb_frame is None: tb = tb.tb_next @@ -37,11 +40,15 @@ def get_stack(self, tb): return stack def get_exception(self): - type = sys.last_type - value = sys.last_value - if hasattr(type, "__name__"): - type = type.__name__ - s = str(type) + if hasattr(sys, 'last_exc'): + typ = type(sys.last_exc) + value = sys.last_exc + else: + typ = sys.last_type + value = sys.last_value + if hasattr(typ, "__name__"): + typ = typ.__name__ + s = str(typ) if value is not None: s = s + ": " + str(value) return s @@ -136,6 +143,7 @@ def _stack_viewer(parent): # htest # except NameError: exc_type, exc_value, exc_tb = sys.exc_info() # inject stack trace to sys + sys.last_exc = exc_value sys.last_type = exc_type sys.last_value = exc_value sys.last_traceback = exc_tb @@ -143,6 +151,7 @@ def _stack_viewer(parent): # htest # StackBrowser(top, flist=flist, top=top, tb=exc_tb) # restore sys to original state + del sys.last_exc del sys.last_type del sys.last_value del sys.last_traceback diff --git a/Lib/pdb.py b/Lib/pdb.py index f11fc55536810f..3543f53282db15 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1739,7 +1739,11 @@ def post_mortem(t=None): def pm(): """Enter post-mortem debugging of the traceback found in sys.last_traceback.""" - post_mortem(sys.last_traceback) + if hasattr(sys, 'last_exc'): + tb = sys.last_exc.__traceback__ + else: + tb = sys.last_traceback + post_mortem(tb) # Main program for testing diff --git a/Lib/pydoc_data/topics.py b/Lib/pydoc_data/topics.py index 573065b4b714d9..ad1b6aca6b95bc 100644 --- a/Lib/pydoc_data/topics.py +++ b/Lib/pydoc_data/topics.py @@ -4799,7 +4799,7 @@ 'pdb.pm()\n' '\n' ' Enter post-mortem debugging of the traceback found in\n' - ' "sys.last_traceback".\n' + ' "sys.last_exc".\n' '\n' 'The "run*" functions and "set_trace()" are aliases for ' 'instantiating\n' @@ -13858,7 +13858,7 @@ 'if\n' ' the interpreter is interactive, it is also made available to ' 'the\n' - ' user as "sys.last_traceback".\n' + ' user as "sys.last_exc".\n' '\n' ' For explicitly created tracebacks, it is up to the creator ' 'of\n' diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index b77e3b06d0c1f1..fa1de1c7ded1b3 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1026,6 +1026,10 @@ def test_disassemble_try_finally(self): self.do_disassembly_test(_tryfinallyconst, dis_tryfinallyconst) def test_dis_none(self): + try: + del sys.last_exc + except AttributeError: + pass try: del sys.last_traceback except AttributeError: @@ -1043,7 +1047,7 @@ def test_dis_traceback(self): 1/0 except Exception as e: tb = e.__traceback__ - sys.last_traceback = tb + sys.last_exc = e tb_dis = self.get_disassemble_as_string(tb.tb_frame.f_code, tb.tb_lasti) self.do_disassembly_test(None, tb_dis, True) @@ -1900,6 +1904,10 @@ def test_findlabels(self): class TestDisTraceback(DisTestBase): def setUp(self) -> None: + try: # We need to clean up existing tracebacks + del sys.last_exc + except AttributeError: + pass try: # We need to clean up existing tracebacks del sys.last_traceback except AttributeError: diff --git a/Lib/test/test_ttk/test_extensions.py b/Lib/test/test_ttk/test_extensions.py index 6135c49701f08e..d5e069716971fe 100644 --- a/Lib/test/test_ttk/test_extensions.py +++ b/Lib/test/test_ttk/test_extensions.py @@ -45,7 +45,9 @@ def test_widget_destroy(self): # value which causes the tracing callback to be called and then # it tries calling instance attributes not yet defined. ttk.LabeledScale(self.root, variable=myvar) - if hasattr(sys, 'last_type'): + if hasattr(sys, 'last_exc'): + self.assertNotEqual(type(sys.last_exc), tkinter.TclError) + elif hasattr(sys, 'last_type'): self.assertNotEqual(sys.last_type, tkinter.TclError) def test_initialization(self): diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 7565e0f7e46073..479daf0e5abfc3 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -2400,6 +2400,7 @@ def report_callback_exception(self, exc, val, tb): should when sys.stderr is None.""" import traceback print("Exception in Tkinter callback", file=sys.stderr) + sys.last_exc = val sys.last_type = exc sys.last_value = val sys.last_traceback = tb diff --git a/Lib/traceback.py b/Lib/traceback.py index c43c4720ae5a15..9e720ac9948fce 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -179,7 +179,7 @@ def _safe_string(value, what, func=str): # -- def print_exc(limit=None, file=None, chain=True): - """Shorthand for 'print_exception(*sys.exc_info(), limit, file)'.""" + """Shorthand for 'print_exception(*sys.exc_info(), limit, file, chain)'.""" print_exception(*sys.exc_info(), limit=limit, file=file, chain=chain) def format_exc(limit=None, chain=True): @@ -187,12 +187,16 @@ def format_exc(limit=None, chain=True): return "".join(format_exception(*sys.exc_info(), limit=limit, chain=chain)) def print_last(limit=None, file=None, chain=True): - """This is a shorthand for 'print_exception(sys.last_type, - sys.last_value, sys.last_traceback, limit, file)'.""" - if not hasattr(sys, "last_type"): + """This is a shorthand for 'print_exception(sys.last_exc, limit, file, chain)'.""" + if not hasattr(sys, "last_exc") and not hasattr(sys, "last_type"): raise ValueError("no last exception") - print_exception(sys.last_type, sys.last_value, sys.last_traceback, - limit, file, chain) + + if hasattr(sys, "last_exc"): + print_exception(sys.last_exc, limit, file, chain) + else: + print_exception(sys.last_type, sys.last_value, sys.last_traceback, + limit, file, chain) + # # Printing and Extracting Stacks. diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst new file mode 100644 index 00000000000000..b5da227afa5a69 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-13-43-34.gh-issue-102778.ANDv8I.rst @@ -0,0 +1,3 @@ +Add :data:`sys.last_exc` and deprecate :data:`sys.last_type`, :data:`sys.last_value` +and :data:`sys.last_traceback`, +which hold the same information in its legacy form. diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index d0c65cc1f7fd44..7bf12271db2323 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1304,7 +1304,7 @@ finalize_modules_delete_special(PyThreadState *tstate, int verbose) { // List of names to clear in sys static const char * const sys_deletes[] = { - "path", "argv", "ps1", "ps2", + "path", "argv", "ps1", "ps2", "last_exc", "last_type", "last_value", "last_traceback", "__interactivehook__", // path_hooks and path_importer_cache are cleared diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 07d119a67847c6..6ea185a1b75bc9 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -776,6 +776,10 @@ _PyErr_PrintEx(PyThreadState *tstate, int set_sys_last_vars) } if (set_sys_last_vars) { + if (_PySys_SetAttr(&_Py_ID(last_exc), exc) < 0) { + _PyErr_Clear(tstate); + } + /* Legacy version: */ if (_PySys_SetAttr(&_Py_ID(last_type), typ) < 0) { _PyErr_Clear(tstate); } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index cc5b9a6d418bfa..126b7d422e0009 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2670,11 +2670,13 @@ stderr -- standard error object; used for error messages\n\ By assigning other file objects (or objects that behave like files)\n\ to these, it is possible to redirect all of the interpreter's I/O.\n\ \n\ +last_exc - the last uncaught exception\n\ + Only available in an interactive session after a\n\ + traceback has been printed.\n\ last_type -- type of last uncaught exception\n\ last_value -- value of last uncaught exception\n\ last_traceback -- traceback of last uncaught exception\n\ - These three are only available in an interactive session after a\n\ - traceback has been printed.\n\ + These three are the (deprecated) legacy representation of last_exc.\n\ " ) /* concatenating string here */ From 863f705cf90f5f040bb9e8574210c920e4953a82 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Sat, 18 Mar 2023 13:44:47 +0000 Subject: [PATCH 144/280] gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives (#102769) --- Python/errors.c | 67 +++++++++++++++++++------------------------------ 1 file changed, 26 insertions(+), 41 deletions(-) diff --git a/Python/errors.c b/Python/errors.c index bdcbac317eb9ee..ab14770c6e810c 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -666,17 +666,15 @@ _PyErr_ChainExceptions(PyObject *typ, PyObject *val, PyObject *tb) } if (_PyErr_Occurred(tstate)) { - PyObject *typ2, *val2, *tb2; - _PyErr_Fetch(tstate, &typ2, &val2, &tb2); _PyErr_NormalizeException(tstate, &typ, &val, &tb); if (tb != NULL) { PyException_SetTraceback(val, tb); Py_DECREF(tb); } Py_DECREF(typ); - _PyErr_NormalizeException(tstate, &typ2, &val2, &tb2); - PyException_SetContext(val2, val); - _PyErr_Restore(tstate, typ2, val2, tb2); + PyObject *exc2 = _PyErr_GetRaisedException(tstate); + PyException_SetContext(exc2, val); + _PyErr_SetRaisedException(tstate, exc2); } else { _PyErr_Restore(tstate, typ, val, tb); @@ -757,27 +755,15 @@ static PyObject * _PyErr_FormatVFromCause(PyThreadState *tstate, PyObject *exception, const char *format, va_list vargs) { - PyObject *exc, *val, *val2, *tb; - assert(_PyErr_Occurred(tstate)); - _PyErr_Fetch(tstate, &exc, &val, &tb); - _PyErr_NormalizeException(tstate, &exc, &val, &tb); - if (tb != NULL) { - PyException_SetTraceback(val, tb); - Py_DECREF(tb); - } - Py_DECREF(exc); + PyObject *exc = _PyErr_GetRaisedException(tstate); assert(!_PyErr_Occurred(tstate)); - _PyErr_FormatV(tstate, exception, format, vargs); - - _PyErr_Fetch(tstate, &exc, &val2, &tb); - _PyErr_NormalizeException(tstate, &exc, &val2, &tb); - PyException_SetCause(val2, Py_NewRef(val)); - PyException_SetContext(val2, Py_NewRef(val)); - Py_DECREF(val); - _PyErr_Restore(tstate, exc, val2, tb); - + PyObject *exc2 = _PyErr_GetRaisedException(tstate); + PyException_SetCause(exc2, Py_NewRef(exc)); + PyException_SetContext(exc2, Py_NewRef(exc)); + Py_DECREF(exc); + _PyErr_SetRaisedException(tstate, exc2); return NULL; } @@ -1698,19 +1684,18 @@ static void PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, int end_lineno, int end_col_offset) { - PyObject *exc, *v, *tb, *tmp; PyThreadState *tstate = _PyThreadState_GET(); /* add attributes for the line number and filename for the error */ - _PyErr_Fetch(tstate, &exc, &v, &tb); - _PyErr_NormalizeException(tstate, &exc, &v, &tb); + PyObject *exc = _PyErr_GetRaisedException(tstate); /* XXX check that it is, indeed, a syntax error. It might not * be, though. */ - tmp = PyLong_FromLong(lineno); - if (tmp == NULL) + PyObject *tmp = PyLong_FromLong(lineno); + if (tmp == NULL) { _PyErr_Clear(tstate); + } else { - if (PyObject_SetAttr(v, &_Py_ID(lineno), tmp)) { + if (PyObject_SetAttr(exc, &_Py_ID(lineno), tmp)) { _PyErr_Clear(tstate); } Py_DECREF(tmp); @@ -1722,7 +1707,7 @@ PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, _PyErr_Clear(tstate); } } - if (PyObject_SetAttr(v, &_Py_ID(offset), tmp ? tmp : Py_None)) { + if (PyObject_SetAttr(exc, &_Py_ID(offset), tmp ? tmp : Py_None)) { _PyErr_Clear(tstate); } Py_XDECREF(tmp); @@ -1734,7 +1719,7 @@ PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, _PyErr_Clear(tstate); } } - if (PyObject_SetAttr(v, &_Py_ID(end_lineno), tmp ? tmp : Py_None)) { + if (PyObject_SetAttr(exc, &_Py_ID(end_lineno), tmp ? tmp : Py_None)) { _PyErr_Clear(tstate); } Py_XDECREF(tmp); @@ -1746,20 +1731,20 @@ PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, _PyErr_Clear(tstate); } } - if (PyObject_SetAttr(v, &_Py_ID(end_offset), tmp ? tmp : Py_None)) { + if (PyObject_SetAttr(exc, &_Py_ID(end_offset), tmp ? tmp : Py_None)) { _PyErr_Clear(tstate); } Py_XDECREF(tmp); tmp = NULL; if (filename != NULL) { - if (PyObject_SetAttr(v, &_Py_ID(filename), filename)) { + if (PyObject_SetAttr(exc, &_Py_ID(filename), filename)) { _PyErr_Clear(tstate); } tmp = PyErr_ProgramTextObject(filename, lineno); if (tmp) { - if (PyObject_SetAttr(v, &_Py_ID(text), tmp)) { + if (PyObject_SetAttr(exc, &_Py_ID(text), tmp)) { _PyErr_Clear(tstate); } Py_DECREF(tmp); @@ -1768,17 +1753,17 @@ PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, _PyErr_Clear(tstate); } } - if (exc != PyExc_SyntaxError) { - if (_PyObject_LookupAttr(v, &_Py_ID(msg), &tmp) < 0) { + if ((PyObject *)Py_TYPE(exc) != PyExc_SyntaxError) { + if (_PyObject_LookupAttr(exc, &_Py_ID(msg), &tmp) < 0) { _PyErr_Clear(tstate); } else if (tmp) { Py_DECREF(tmp); } else { - tmp = PyObject_Str(v); + tmp = PyObject_Str(exc); if (tmp) { - if (PyObject_SetAttr(v, &_Py_ID(msg), tmp)) { + if (PyObject_SetAttr(exc, &_Py_ID(msg), tmp)) { _PyErr_Clear(tstate); } Py_DECREF(tmp); @@ -1788,19 +1773,19 @@ PyErr_SyntaxLocationObjectEx(PyObject *filename, int lineno, int col_offset, } } - if (_PyObject_LookupAttr(v, &_Py_ID(print_file_and_line), &tmp) < 0) { + if (_PyObject_LookupAttr(exc, &_Py_ID(print_file_and_line), &tmp) < 0) { _PyErr_Clear(tstate); } else if (tmp) { Py_DECREF(tmp); } else { - if (PyObject_SetAttr(v, &_Py_ID(print_file_and_line), Py_None)) { + if (PyObject_SetAttr(exc, &_Py_ID(print_file_and_line), Py_None)) { _PyErr_Clear(tstate); } } } - _PyErr_Restore(tstate, exc, v, tb); + _PyErr_SetRaisedException(tstate, exc); } void From 1820891bc4a9a95a7d80bfb30bfabef4c89e98b2 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sat, 18 Mar 2023 12:21:48 -0500 Subject: [PATCH 145/280] Add more comments to hypot() (GH-102817) --- Modules/mathmodule.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 48cd9a642de150..c9a2be66863993 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -2447,9 +2447,8 @@ Since lo**2 is less than 1/2 ulp(csum), we have csum+lo*lo == csum. To minimize loss of information during the accumulation of fractional values, each term has a separate accumulator. This also breaks up sequential dependencies in the inner loop so the CPU can maximize -floating point throughput. [4] On a 2.6 GHz Haswell, adding one -dimension has an incremental cost of only 5ns -- for example when -moving from hypot(x,y) to hypot(x,y,z). +floating point throughput. [4] On an Apple M1 Max, hypot(*vec) +takes only 3.33 µsec when len(vec) == 1000. The square root differential correction is needed because a correctly rounded square root of a correctly rounded sum of @@ -2473,7 +2472,7 @@ step is exact. The Neumaier summation computes as if in doubled precision (106 bits) and has the advantage that its input squares are non-negative so that the condition number of the sum is one. The square root with a differential correction is likewise computed -as if in double precision. +as if in doubled precision. For n <= 1000, prior to the final addition that rounds the overall result, the internal accuracy of "h" together with its correction of @@ -2514,12 +2513,9 @@ vector_norm(Py_ssize_t n, double *vec, double max, int found_nan) } frexp(max, &max_e); if (max_e < -1023) { - /* When max_e < -1023, ldexp(1.0, -max_e) would overflow. - So we first perform lossless scaling from subnormals back to normals, - then recurse back to vector_norm(), and then finally undo the scaling. - */ + /* When max_e < -1023, ldexp(1.0, -max_e) would overflow. */ for (i=0 ; i < n ; i++) { - vec[i] /= DBL_MIN; + vec[i] /= DBL_MIN; // convert subnormals to normals } return DBL_MIN * vector_norm(n, vec, max / DBL_MIN, found_nan); } @@ -2529,17 +2525,14 @@ vector_norm(Py_ssize_t n, double *vec, double max, int found_nan) for (i=0 ; i < n ; i++) { x = vec[i]; assert(Py_IS_FINITE(x) && fabs(x) <= max); - - x *= scale; + x *= scale; // lossless scaling assert(fabs(x) < 1.0); - - pr = dl_mul(x, x); + pr = dl_mul(x, x); // lossless squaring assert(pr.hi <= 1.0); - - sm = dl_fast_sum(csum, pr.hi); + sm = dl_fast_sum(csum, pr.hi); // lossless addition csum = sm.hi; - frac1 += pr.lo; - frac2 += sm.lo; + frac1 += pr.lo; // lossy addition + frac2 += sm.lo; // lossy addition } h = sqrt(csum - 1.0 + (frac1 + frac2)); pr = dl_mul(-h, h); @@ -2548,7 +2541,8 @@ vector_norm(Py_ssize_t n, double *vec, double max, int found_nan) frac1 += pr.lo; frac2 += sm.lo; x = csum - 1.0 + (frac1 + frac2); - return (h + x / (2.0 * h)) / scale; + h += x / (2.0 * h); // differential correction + return h / scale; } #define NUM_STACK_ELEMS 16 From ba86d352c032ef01743cf451edb56a70e346fbbe Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Sun, 19 Mar 2023 15:17:59 +0000 Subject: [PATCH 146/280] gh-102192: Replace PyErr_Fetch/Restore etc by more efficient alternatives (#102816) --- Python/bytecodes.c | 8 ++------ Python/generated_cases.c.h | 8 ++------ Python/import.c | 28 ++++++++++++++-------------- Python/pythonrun.c | 2 +- 4 files changed, 19 insertions(+), 27 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 4cac5857a2cf42..c8ffd89c51a22c 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -851,9 +851,7 @@ dummy_func( } assert(exc && PyExceptionInstance_Check(exc)); Py_INCREF(exc); - PyObject *typ = Py_NewRef(PyExceptionInstance_Class(exc)); - PyObject *tb = PyException_GetTraceback(exc); - _PyErr_Restore(tstate, typ, exc, tb); + _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } @@ -864,9 +862,7 @@ dummy_func( } else { Py_INCREF(exc); - PyObject *typ = Py_NewRef(PyExceptionInstance_Class(exc)); - PyObject *tb = PyException_GetTraceback(exc); - _PyErr_Restore(tstate, typ, exc, tb); + _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 9fb532209041ce..2c6388390b51ad 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1122,9 +1122,7 @@ } assert(exc && PyExceptionInstance_Check(exc)); Py_INCREF(exc); - PyObject *typ = Py_NewRef(PyExceptionInstance_Class(exc)); - PyObject *tb = PyException_GetTraceback(exc); - _PyErr_Restore(tstate, typ, exc, tb); + _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } @@ -1138,9 +1136,7 @@ } else { Py_INCREF(exc); - PyObject *typ = Py_NewRef(PyExceptionInstance_Class(exc)); - PyObject *tb = PyException_GetTraceback(exc); - _PyErr_Restore(tstate, typ, exc, tb); + _PyErr_SetRaisedException(tstate, exc); goto exception_unwind; } STACK_SHRINK(2); diff --git a/Python/import.c b/Python/import.c index 9f80c6d8dd49a8..c68bd1f7db420d 100644 --- a/Python/import.c +++ b/Python/import.c @@ -389,8 +389,7 @@ PyImport_AddModule(const char *name) static void remove_module(PyThreadState *tstate, PyObject *name) { - PyObject *type, *value, *traceback; - _PyErr_Fetch(tstate, &type, &value, &traceback); + PyObject *exc = _PyErr_GetRaisedException(tstate); PyObject *modules = MODULES(tstate->interp); if (PyDict_CheckExact(modules)) { @@ -403,7 +402,7 @@ remove_module(PyThreadState *tstate, PyObject *name) } } - _PyErr_ChainExceptions(type, value, traceback); + _PyErr_ChainExceptions1(exc); } @@ -2324,32 +2323,34 @@ remove_importlib_frames(PyThreadState *tstate) const char *remove_frames = "_call_with_frames_removed"; int always_trim = 0; int in_importlib = 0; - PyObject *exception, *value, *base_tb, *tb; PyObject **prev_link, **outer_link = NULL; + PyObject *base_tb = NULL; /* Synopsis: if it's an ImportError, we trim all importlib chunks from the traceback. We always trim chunks which end with a call to "_call_with_frames_removed". */ - _PyErr_Fetch(tstate, &exception, &value, &base_tb); - if (!exception || _PyInterpreterState_GetConfig(tstate->interp)->verbose) { + PyObject *exc = _PyErr_GetRaisedException(tstate); + if (exc == NULL || _PyInterpreterState_GetConfig(tstate->interp)->verbose) { goto done; } - if (PyType_IsSubtype((PyTypeObject *) exception, - (PyTypeObject *) PyExc_ImportError)) + if (PyType_IsSubtype(Py_TYPE(exc), (PyTypeObject *) PyExc_ImportError)) { always_trim = 1; + } + assert(PyExceptionInstance_Check(exc)); + base_tb = PyException_GetTraceback(exc); prev_link = &base_tb; - tb = base_tb; + PyObject *tb = base_tb; while (tb != NULL) { + assert(PyTraceBack_Check(tb)); PyTracebackObject *traceback = (PyTracebackObject *)tb; PyObject *next = (PyObject *) traceback->tb_next; PyFrameObject *frame = traceback->tb_frame; PyCodeObject *code = PyFrame_GetCode(frame); int now_in_importlib; - assert(PyTraceBack_Check(tb)); now_in_importlib = _PyUnicode_EqualToASCIIString(code->co_filename, importlib_filename) || _PyUnicode_EqualToASCIIString(code->co_filename, external_filename); if (now_in_importlib && !in_importlib) { @@ -2370,15 +2371,14 @@ remove_importlib_frames(PyThreadState *tstate) Py_DECREF(code); tb = next; } - assert(PyExceptionInstance_Check(value)); - assert((PyObject *)Py_TYPE(value) == exception); if (base_tb == NULL) { base_tb = Py_None; Py_INCREF(Py_None); } - PyException_SetTraceback(value, base_tb); + PyException_SetTraceback(exc, base_tb); done: - _PyErr_Restore(tstate, exception, value, base_tb); + Py_XDECREF(base_tb); + _PyErr_SetRaisedException(tstate, exc); } diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 6ea185a1b75bc9..b16d3f53f89fb9 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -18,7 +18,7 @@ #include "pycore_interp.h" // PyInterpreterState.importlib #include "pycore_object.h" // _PyDebug_PrintTotalRefs() #include "pycore_parser.h" // _PyParser_ASTFromString() -#include "pycore_pyerrors.h" // _PyErr_Fetch, _Py_Offer_Suggestions +#include "pycore_pyerrors.h" // _PyErr_GetRaisedException, _Py_Offer_Suggestions #include "pycore_pylifecycle.h" // _Py_UnhandledKeyboardInterrupt #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_sysmodule.h" // _PySys_Audit() From 2cfaac1fb0747e8e8fe869c0656809eb5ef960de Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Sun, 19 Mar 2023 15:18:24 +0000 Subject: [PATCH 147/280] gh-102755: fix refleak (#102826) --- Python/pylifecycle.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 7bf12271db2323..317d6966d034fa 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2547,6 +2547,7 @@ _Py_FatalError_PrintExc(PyThreadState *tstate) if (ferr == NULL || ferr == Py_None) { /* sys.stderr is not set yet or set to None, no need to try to display the exception */ + Py_DECREF(exc); return 0; } @@ -2555,7 +2556,7 @@ _Py_FatalError_PrintExc(PyThreadState *tstate) PyObject *tb = PyException_GetTraceback(exc); int has_tb = (tb != NULL) && (tb != Py_None); Py_XDECREF(tb); - Py_XDECREF(exc); + Py_DECREF(exc); /* sys.stderr may be buffered: call sys.stderr.flush() */ PyObject *res = PyObject_CallMethodNoArgs(ferr, &_Py_ID(flush)); From 47460943fcb63abd140534b41d15313077ec3f1d Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Sun, 19 Mar 2023 16:19:59 +0000 Subject: [PATCH 148/280] gh-102778: revert changes to idlelib (#102825) --- Lib/idlelib/idle_test/test_stackviewer.py | 3 +-- Lib/idlelib/pyshell.py | 7 ++----- Lib/idlelib/run.py | 2 -- Lib/idlelib/stackviewer.py | 21 ++++++--------------- 4 files changed, 9 insertions(+), 24 deletions(-) diff --git a/Lib/idlelib/idle_test/test_stackviewer.py b/Lib/idlelib/idle_test/test_stackviewer.py index f4626bb1702a30..98f53f9537bb25 100644 --- a/Lib/idlelib/idle_test/test_stackviewer.py +++ b/Lib/idlelib/idle_test/test_stackviewer.py @@ -19,7 +19,6 @@ def setUpClass(cls): except NameError: svs.last_type, svs.last_value, svs.last_traceback = ( sys.exc_info()) - svs.last_exc = svs.last_value requires('gui') cls.root = Tk() @@ -28,7 +27,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): svs = stackviewer.sys - del svs.last_exc, svs.last_traceback, svs.last_type, svs.last_value + del svs.last_traceback, svs.last_type, svs.last_value cls.root.update_idletasks() ## for id in cls.root.tk.call('after', 'info'): diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py index edc77ff26f62f7..e68233a5a4131e 100755 --- a/Lib/idlelib/pyshell.py +++ b/Lib/idlelib/pyshell.py @@ -1367,14 +1367,11 @@ def open_stack_viewer(self, event=None): if self.interp.rpcclt: return self.interp.remote_stack_viewer() try: - if hasattr(sys, 'last_exc'): - sys.last_exc.__traceback__ - else: - sys.last_traceback + sys.last_traceback except: messagebox.showerror("No stack trace", "There is no stack trace yet.\n" - "(sys.last_exc and sys.last_traceback are not defined)", + "(sys.last_traceback is not defined)", parent=self.text) return from idlelib.stackviewer import StackBrowser diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py index 6a7b50cf5cfb27..577c49eb67b20d 100644 --- a/Lib/idlelib/run.py +++ b/Lib/idlelib/run.py @@ -239,7 +239,6 @@ def print_exception(): efile = sys.stderr typ, val, tb = excinfo = sys.exc_info() sys.last_type, sys.last_value, sys.last_traceback = excinfo - sys.last_exc = val seen = set() def print_exc(typ, exc, tb): @@ -630,7 +629,6 @@ def stackviewer(self, flist_oid=None): flist = self.rpchandler.get_remote_proxy(flist_oid) while tb and tb.tb_frame.f_globals["__name__"] in ["rpc", "run"]: tb = tb.tb_next - sys.last_exc = val sys.last_type = typ sys.last_value = val item = stackviewer.StackTreeItem(flist, tb) diff --git a/Lib/idlelib/stackviewer.py b/Lib/idlelib/stackviewer.py index 702fd32ca5d1bd..94ffb4eff4dd26 100644 --- a/Lib/idlelib/stackviewer.py +++ b/Lib/idlelib/stackviewer.py @@ -27,10 +27,7 @@ def __init__(self, flist=None, tb=None): def get_stack(self, tb): if tb is None: - if hasattr(sys, 'last_exc'): - tb = sys.last_exc.__traceback__ - else: - tb = sys.last_traceback + tb = sys.last_traceback stack = [] if tb and tb.tb_frame is None: tb = tb.tb_next @@ -40,15 +37,11 @@ def get_stack(self, tb): return stack def get_exception(self): - if hasattr(sys, 'last_exc'): - typ = type(sys.last_exc) - value = sys.last_exc - else: - typ = sys.last_type - value = sys.last_value - if hasattr(typ, "__name__"): - typ = typ.__name__ - s = str(typ) + type = sys.last_type + value = sys.last_value + if hasattr(type, "__name__"): + type = type.__name__ + s = str(type) if value is not None: s = s + ": " + str(value) return s @@ -143,7 +136,6 @@ def _stack_viewer(parent): # htest # except NameError: exc_type, exc_value, exc_tb = sys.exc_info() # inject stack trace to sys - sys.last_exc = exc_value sys.last_type = exc_type sys.last_value = exc_value sys.last_traceback = exc_tb @@ -151,7 +143,6 @@ def _stack_viewer(parent): # htest # StackBrowser(top, flist=flist, top=top, tb=exc_tb) # restore sys to original state - del sys.last_exc del sys.last_type del sys.last_value del sys.last_traceback From c8e62e71dadd9e76512f494096065dcdc2e34568 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Sun, 19 Mar 2023 18:33:51 +0000 Subject: [PATCH 149/280] gh-102828: add onexc arg to shutil.rmtree. Deprecate onerror. (#102829) --- Doc/library/shutil.rst | 24 ++- Doc/whatsnew/3.12.rst | 9 + Lib/shutil.py | 106 ++++++----- Lib/test/test_shutil.py | 170 +++++++++++++++++- ...-03-19-15-30-59.gh-issue-102828.NKClXg.rst | 3 + 5 files changed, 256 insertions(+), 56 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-03-19-15-30-59.gh-issue-102828.NKClXg.rst diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index b33dbe21b1fa19..acba66258fe8f0 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -292,15 +292,15 @@ Directory and files operations .. versionadded:: 3.8 The *dirs_exist_ok* parameter. -.. function:: rmtree(path, ignore_errors=False, onerror=None, *, dir_fd=None) +.. function:: rmtree(path, ignore_errors=False, onerror=None, *, onexc=None, dir_fd=None) .. index:: single: directory; deleting Delete an entire directory tree; *path* must point to a directory (but not a symbolic link to a directory). If *ignore_errors* is true, errors resulting from failed removals will be ignored; if false or omitted, such errors are - handled by calling a handler specified by *onerror* or, if that is omitted, - they raise an exception. + handled by calling a handler specified by *onexc* or *onerror* or, if both + are omitted, exceptions are propagated to the caller. This function can support :ref:`paths relative to directory descriptors `. @@ -315,14 +315,17 @@ Directory and files operations otherwise. Applications can use the :data:`rmtree.avoids_symlink_attacks` function attribute to determine which case applies. - If *onerror* is provided, it must be a callable that accepts three - parameters: *function*, *path*, and *excinfo*. + If *onexc* is provided, it must be a callable that accepts three parameters: + *function*, *path*, and *excinfo*. The first parameter, *function*, is the function which raised the exception; it depends on the platform and implementation. The second parameter, *path*, will be the path name passed to *function*. The third parameter, - *excinfo*, will be the exception information returned by - :func:`sys.exc_info`. Exceptions raised by *onerror* will not be caught. + *excinfo*, is the exception that was raised. Exceptions raised by *onexc* + will not be caught. + + The deprecated *onerror* is similar to *onexc*, except that the third + parameter it receives is the tuple returned from :func:`sys.exc_info`. .. audit-event:: shutil.rmtree path,dir_fd shutil.rmtree @@ -337,6 +340,9 @@ Directory and files operations .. versionchanged:: 3.11 The *dir_fd* parameter. + .. versionchanged:: 3.12 + Added the *onexc* parameter, deprecated *onerror*. + .. attribute:: rmtree.avoids_symlink_attacks Indicates whether the current platform and implementation provides a @@ -509,7 +515,7 @@ rmtree example ~~~~~~~~~~~~~~ This example shows how to remove a directory tree on Windows where some -of the files have their read-only bit set. It uses the onerror callback +of the files have their read-only bit set. It uses the onexc callback to clear the readonly bit and reattempt the remove. Any subsequent failure will propagate. :: @@ -521,7 +527,7 @@ will propagate. :: os.chmod(path, stat.S_IWRITE) func(path) - shutil.rmtree(directory, onerror=remove_readonly) + shutil.rmtree(directory, onexc=remove_readonly) .. _archiving-operations: diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 32fec962560ae1..a36e68528c4f74 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -337,6 +337,11 @@ shutil of the process to *root_dir* to perform archiving. (Contributed by Serhiy Storchaka in :gh:`74696`.) +* :func:`shutil.rmtree` now accepts a new argument *onexc* which is an + error handler like *onerror* but which expects an exception instance + rather than a *(typ, val, tb)* triplet. *onerror* is deprecated. + (Contributed by Irit Katriel in :gh:`102828`.) + sqlite3 ------- @@ -498,6 +503,10 @@ Deprecated fields are deprecated. Use :data:`sys.last_exc` instead. (Contributed by Irit Katriel in :gh:`102778`.) +* The *onerror* argument of :func:`shutil.rmtree` is deprecated. Use *onexc* + instead. (Contributed by Irit Katriel in :gh:`102828`.) + + Pending Removal in Python 3.13 ------------------------------ diff --git a/Lib/shutil.py b/Lib/shutil.py index 867925aa10cc04..89a7ac72d98357 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -575,12 +575,12 @@ def _rmtree_islink(path): return os.path.islink(path) # version vulnerable to race conditions -def _rmtree_unsafe(path, onerror): +def _rmtree_unsafe(path, onexc): try: with os.scandir(path) as scandir_it: entries = list(scandir_it) - except OSError: - onerror(os.scandir, path, sys.exc_info()) + except OSError as err: + onexc(os.scandir, path, err) entries = [] for entry in entries: fullname = entry.path @@ -596,28 +596,28 @@ def _rmtree_unsafe(path, onerror): # a directory with a symlink after the call to # os.scandir or entry.is_dir above. raise OSError("Cannot call rmtree on a symbolic link") - except OSError: - onerror(os.path.islink, fullname, sys.exc_info()) + except OSError as err: + onexc(os.path.islink, fullname, err) continue - _rmtree_unsafe(fullname, onerror) + _rmtree_unsafe(fullname, onexc) else: try: os.unlink(fullname) - except OSError: - onerror(os.unlink, fullname, sys.exc_info()) + except OSError as err: + onexc(os.unlink, fullname, err) try: os.rmdir(path) - except OSError: - onerror(os.rmdir, path, sys.exc_info()) + except OSError as err: + onexc(os.rmdir, path, err) # Version using fd-based APIs to protect against races -def _rmtree_safe_fd(topfd, path, onerror): +def _rmtree_safe_fd(topfd, path, onexc): try: with os.scandir(topfd) as scandir_it: entries = list(scandir_it) except OSError as err: err.filename = path - onerror(os.scandir, path, sys.exc_info()) + onexc(os.scandir, path, err) return for entry in entries: fullname = os.path.join(path, entry.name) @@ -630,25 +630,25 @@ def _rmtree_safe_fd(topfd, path, onerror): try: orig_st = entry.stat(follow_symlinks=False) is_dir = stat.S_ISDIR(orig_st.st_mode) - except OSError: - onerror(os.lstat, fullname, sys.exc_info()) + except OSError as err: + onexc(os.lstat, fullname, err) continue if is_dir: try: dirfd = os.open(entry.name, os.O_RDONLY, dir_fd=topfd) dirfd_closed = False - except OSError: - onerror(os.open, fullname, sys.exc_info()) + except OSError as err: + onexc(os.open, fullname, err) else: try: if os.path.samestat(orig_st, os.fstat(dirfd)): - _rmtree_safe_fd(dirfd, fullname, onerror) + _rmtree_safe_fd(dirfd, fullname, onexc) try: os.close(dirfd) dirfd_closed = True os.rmdir(entry.name, dir_fd=topfd) - except OSError: - onerror(os.rmdir, fullname, sys.exc_info()) + except OSError as err: + onexc(os.rmdir, fullname, err) else: try: # This can only happen if someone replaces @@ -656,23 +656,23 @@ def _rmtree_safe_fd(topfd, path, onerror): # os.scandir or stat.S_ISDIR above. raise OSError("Cannot call rmtree on a symbolic " "link") - except OSError: - onerror(os.path.islink, fullname, sys.exc_info()) + except OSError as err: + onexc(os.path.islink, fullname, err) finally: if not dirfd_closed: os.close(dirfd) else: try: os.unlink(entry.name, dir_fd=topfd) - except OSError: - onerror(os.unlink, fullname, sys.exc_info()) + except OSError as err: + onexc(os.unlink, fullname, err) _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <= os.supports_dir_fd and os.scandir in os.supports_fd and os.stat in os.supports_follow_symlinks) -def rmtree(path, ignore_errors=False, onerror=None, *, dir_fd=None): +def rmtree(path, ignore_errors=False, onerror=None, *, onexc=None, dir_fd=None): """Recursively delete a directory tree. If dir_fd is not None, it should be a file descriptor open to a directory; @@ -680,21 +680,39 @@ def rmtree(path, ignore_errors=False, onerror=None, *, dir_fd=None): dir_fd may not be implemented on your platform. If it is unavailable, using it will raise a NotImplementedError. - If ignore_errors is set, errors are ignored; otherwise, if onerror - is set, it is called to handle the error with arguments (func, + If ignore_errors is set, errors are ignored; otherwise, if onexc or + onerror is set, it is called to handle the error with arguments (func, path, exc_info) where func is platform and implementation dependent; path is the argument to that function that caused it to fail; and - exc_info is a tuple returned by sys.exc_info(). If ignore_errors - is false and onerror is None, an exception is raised. + the value of exc_info describes the exception. For onexc it is the + exception instance, and for onerror it is a tuple as returned by + sys.exc_info(). If ignore_errors is false and both onexc and + onerror are None, the exception is reraised. + onerror is deprecated and only remains for backwards compatibility. + If both onerror and onexc are set, onerror is ignored and onexc is used. """ sys.audit("shutil.rmtree", path, dir_fd) if ignore_errors: - def onerror(*args): + def onexc(*args): pass - elif onerror is None: - def onerror(*args): + elif onerror is None and onexc is None: + def onexc(*args): raise + elif onexc is None: + if onerror is None: + def onexc(*args): + raise + else: + # delegate to onerror + def onexc(*args): + func, path, exc = args + if exc is None: + exc_info = None, None, None + else: + exc_info = type(exc), exc, exc.__traceback__ + return onerror(func, path, exc_info) + if _use_fd_functions: # While the unsafe rmtree works fine on bytes, the fd based does not. if isinstance(path, bytes): @@ -703,30 +721,30 @@ def onerror(*args): # lstat()/open()/fstat() trick. try: orig_st = os.lstat(path, dir_fd=dir_fd) - except Exception: - onerror(os.lstat, path, sys.exc_info()) + except Exception as err: + onexc(os.lstat, path, err) return try: fd = os.open(path, os.O_RDONLY, dir_fd=dir_fd) fd_closed = False - except Exception: - onerror(os.open, path, sys.exc_info()) + except Exception as err: + onexc(os.open, path, err) return try: if os.path.samestat(orig_st, os.fstat(fd)): - _rmtree_safe_fd(fd, path, onerror) + _rmtree_safe_fd(fd, path, onexc) try: os.close(fd) fd_closed = True os.rmdir(path, dir_fd=dir_fd) - except OSError: - onerror(os.rmdir, path, sys.exc_info()) + except OSError as err: + onexc(os.rmdir, path, err) else: try: # symlinks to directories are forbidden, see bug #1669 raise OSError("Cannot call rmtree on a symbolic link") - except OSError: - onerror(os.path.islink, path, sys.exc_info()) + except OSError as err: + onexc(os.path.islink, path, err) finally: if not fd_closed: os.close(fd) @@ -737,11 +755,11 @@ def onerror(*args): if _rmtree_islink(path): # symlinks to directories are forbidden, see bug #1669 raise OSError("Cannot call rmtree on a symbolic link") - except OSError: - onerror(os.path.islink, path, sys.exc_info()) - # can't continue even if onerror hook returns + except OSError as err: + onexc(os.path.islink, path, err) + # can't continue even if onexc hook returns return - return _rmtree_unsafe(path, onerror) + return _rmtree_unsafe(path, onexc) # Allow introspection of whether or not the hardening against symlink # attacks is supported on the current platform diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 8fe62216ecdca0..fee3e7f765639a 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -195,7 +195,7 @@ def test_rmtree_works_on_bytes(self): shutil.rmtree(victim) @os_helper.skip_unless_symlink - def test_rmtree_fails_on_symlink(self): + def test_rmtree_fails_on_symlink_onerror(self): tmp = self.mkdtemp() dir_ = os.path.join(tmp, 'dir') os.mkdir(dir_) @@ -213,6 +213,25 @@ def onerror(*args): self.assertEqual(errors[0][1], link) self.assertIsInstance(errors[0][2][1], OSError) + @os_helper.skip_unless_symlink + def test_rmtree_fails_on_symlink_onexc(self): + tmp = self.mkdtemp() + dir_ = os.path.join(tmp, 'dir') + os.mkdir(dir_) + link = os.path.join(tmp, 'link') + os.symlink(dir_, link) + self.assertRaises(OSError, shutil.rmtree, link) + self.assertTrue(os.path.exists(dir_)) + self.assertTrue(os.path.lexists(link)) + errors = [] + def onexc(*args): + errors.append(args) + shutil.rmtree(link, onexc=onexc) + self.assertEqual(len(errors), 1) + self.assertIs(errors[0][0], os.path.islink) + self.assertEqual(errors[0][1], link) + self.assertIsInstance(errors[0][2], OSError) + @os_helper.skip_unless_symlink def test_rmtree_works_on_symlinks(self): tmp = self.mkdtemp() @@ -236,7 +255,7 @@ def test_rmtree_works_on_symlinks(self): self.assertTrue(os.path.exists(file1)) @unittest.skipUnless(_winapi, 'only relevant on Windows') - def test_rmtree_fails_on_junctions(self): + def test_rmtree_fails_on_junctions_onerror(self): tmp = self.mkdtemp() dir_ = os.path.join(tmp, 'dir') os.mkdir(dir_) @@ -255,6 +274,26 @@ def onerror(*args): self.assertEqual(errors[0][1], link) self.assertIsInstance(errors[0][2][1], OSError) + @unittest.skipUnless(_winapi, 'only relevant on Windows') + def test_rmtree_fails_on_junctions_onexc(self): + tmp = self.mkdtemp() + dir_ = os.path.join(tmp, 'dir') + os.mkdir(dir_) + link = os.path.join(tmp, 'link') + _winapi.CreateJunction(dir_, link) + self.addCleanup(os_helper.unlink, link) + self.assertRaises(OSError, shutil.rmtree, link) + self.assertTrue(os.path.exists(dir_)) + self.assertTrue(os.path.lexists(link)) + errors = [] + def onexc(*args): + errors.append(args) + shutil.rmtree(link, onexc=onexc) + self.assertEqual(len(errors), 1) + self.assertIs(errors[0][0], os.path.islink) + self.assertEqual(errors[0][1], link) + self.assertIsInstance(errors[0][2], OSError) + @unittest.skipUnless(_winapi, 'only relevant on Windows') def test_rmtree_works_on_junctions(self): tmp = self.mkdtemp() @@ -277,7 +316,7 @@ def test_rmtree_works_on_junctions(self): self.assertTrue(os.path.exists(dir3)) self.assertTrue(os.path.exists(file1)) - def test_rmtree_errors(self): + def test_rmtree_errors_onerror(self): # filename is guaranteed not to exist filename = tempfile.mktemp(dir=self.mkdtemp()) self.assertRaises(FileNotFoundError, shutil.rmtree, filename) @@ -309,6 +348,37 @@ def onerror(*args): self.assertIsInstance(errors[1][2][1], NotADirectoryError) self.assertEqual(errors[1][2][1].filename, filename) + def test_rmtree_errors_onexc(self): + # filename is guaranteed not to exist + filename = tempfile.mktemp(dir=self.mkdtemp()) + self.assertRaises(FileNotFoundError, shutil.rmtree, filename) + # test that ignore_errors option is honored + shutil.rmtree(filename, ignore_errors=True) + + # existing file + tmpdir = self.mkdtemp() + write_file((tmpdir, "tstfile"), "") + filename = os.path.join(tmpdir, "tstfile") + with self.assertRaises(NotADirectoryError) as cm: + shutil.rmtree(filename) + self.assertEqual(cm.exception.filename, filename) + self.assertTrue(os.path.exists(filename)) + # test that ignore_errors option is honored + shutil.rmtree(filename, ignore_errors=True) + self.assertTrue(os.path.exists(filename)) + errors = [] + def onexc(*args): + errors.append(args) + shutil.rmtree(filename, onexc=onexc) + self.assertEqual(len(errors), 2) + self.assertIs(errors[0][0], os.scandir) + self.assertEqual(errors[0][1], filename) + self.assertIsInstance(errors[0][2], NotADirectoryError) + self.assertEqual(errors[0][2].filename, filename) + self.assertIs(errors[1][0], os.rmdir) + self.assertEqual(errors[1][1], filename) + self.assertIsInstance(errors[1][2], NotADirectoryError) + self.assertEqual(errors[1][2].filename, filename) @unittest.skipIf(sys.platform[:6] == 'cygwin', "This test can't be run on Cygwin (issue #1071513).") @@ -368,6 +438,100 @@ def check_args_to_onerror(self, func, arg, exc): self.assertTrue(issubclass(exc[0], OSError)) self.errorState = 3 + @unittest.skipIf(sys.platform[:6] == 'cygwin', + "This test can't be run on Cygwin (issue #1071513).") + @os_helper.skip_if_dac_override + @os_helper.skip_unless_working_chmod + def test_on_exc(self): + self.errorState = 0 + os.mkdir(TESTFN) + self.addCleanup(shutil.rmtree, TESTFN) + + self.child_file_path = os.path.join(TESTFN, 'a') + self.child_dir_path = os.path.join(TESTFN, 'b') + os_helper.create_empty_file(self.child_file_path) + os.mkdir(self.child_dir_path) + old_dir_mode = os.stat(TESTFN).st_mode + old_child_file_mode = os.stat(self.child_file_path).st_mode + old_child_dir_mode = os.stat(self.child_dir_path).st_mode + # Make unwritable. + new_mode = stat.S_IREAD|stat.S_IEXEC + os.chmod(self.child_file_path, new_mode) + os.chmod(self.child_dir_path, new_mode) + os.chmod(TESTFN, new_mode) + + self.addCleanup(os.chmod, TESTFN, old_dir_mode) + self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode) + self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode) + + shutil.rmtree(TESTFN, onexc=self.check_args_to_onexc) + # Test whether onexc has actually been called. + self.assertEqual(self.errorState, 3, + "Expected call to onexc function did not happen.") + + def check_args_to_onexc(self, func, arg, exc): + # test_rmtree_errors deliberately runs rmtree + # on a directory that is chmod 500, which will fail. + # This function is run when shutil.rmtree fails. + # 99.9% of the time it initially fails to remove + # a file in the directory, so the first time through + # func is os.remove. + # However, some Linux machines running ZFS on + # FUSE experienced a failure earlier in the process + # at os.listdir. The first failure may legally + # be either. + if self.errorState < 2: + if func is os.unlink: + self.assertEqual(arg, self.child_file_path) + elif func is os.rmdir: + self.assertEqual(arg, self.child_dir_path) + else: + self.assertIs(func, os.listdir) + self.assertIn(arg, [TESTFN, self.child_dir_path]) + self.assertTrue(isinstance(exc, OSError)) + self.errorState += 1 + else: + self.assertEqual(func, os.rmdir) + self.assertEqual(arg, TESTFN) + self.assertTrue(isinstance(exc, OSError)) + self.errorState = 3 + + def test_both_onerror_and_onexc(self): + onerror_called = False + onexc_called = False + + def onerror(*args): + nonlocal onerror_called + onerror_called = True + + def onexc(*args): + nonlocal onexc_called + onexc_called = True + + os.mkdir(TESTFN) + self.addCleanup(shutil.rmtree, TESTFN) + + self.child_file_path = os.path.join(TESTFN, 'a') + self.child_dir_path = os.path.join(TESTFN, 'b') + os_helper.create_empty_file(self.child_file_path) + os.mkdir(self.child_dir_path) + old_dir_mode = os.stat(TESTFN).st_mode + old_child_file_mode = os.stat(self.child_file_path).st_mode + old_child_dir_mode = os.stat(self.child_dir_path).st_mode + # Make unwritable. + new_mode = stat.S_IREAD|stat.S_IEXEC + os.chmod(self.child_file_path, new_mode) + os.chmod(self.child_dir_path, new_mode) + os.chmod(TESTFN, new_mode) + + self.addCleanup(os.chmod, TESTFN, old_dir_mode) + self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode) + self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode) + + shutil.rmtree(TESTFN, onerror=onerror, onexc=onexc) + self.assertTrue(onexc_called) + self.assertFalse(onerror_called) + def test_rmtree_does_not_choke_on_failing_lstat(self): try: orig_lstat = os.lstat diff --git a/Misc/NEWS.d/next/Library/2023-03-19-15-30-59.gh-issue-102828.NKClXg.rst b/Misc/NEWS.d/next/Library/2023-03-19-15-30-59.gh-issue-102828.NKClXg.rst new file mode 100644 index 00000000000000..be9b2bab24a381 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-19-15-30-59.gh-issue-102828.NKClXg.rst @@ -0,0 +1,3 @@ +Add the ``onexc`` arg to :func:`shutil.rmtree`, which is like ``onerror`` +but expects an exception instance rather than an exc_info tuple. Deprecate +``onerror``. From d66b16bb86f446b5bc10703fa7a7129a702289cb Mon Sep 17 00:00:00 2001 From: JosephSBoyle <48555120+JosephSBoyle@users.noreply.github.com> Date: Sun, 19 Mar 2023 20:06:09 +0000 Subject: [PATCH 150/280] gh-102810: Add docstrings to the public-facing methods of `asyncio.Timeout` (#102811) Co-authored-by: Guido van Rossum Co-authored-by: Alex Waygood --- Lib/asyncio/timeouts.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Lib/asyncio/timeouts.py b/Lib/asyncio/timeouts.py index 94d25535fbc059..d07b291005e8f9 100644 --- a/Lib/asyncio/timeouts.py +++ b/Lib/asyncio/timeouts.py @@ -25,8 +25,18 @@ class _State(enum.Enum): @final class Timeout: + """Asynchronous context manager for cancelling overdue coroutines. + + Use `timeout()` or `timeout_at()` rather than instantiating this class directly. + """ def __init__(self, when: Optional[float]) -> None: + """Schedule a timeout that will trigger at a given loop time. + + - If `when` is `None`, the timeout will never trigger. + - If `when < loop.time()`, the timeout will trigger on the next + iteration of the event loop. + """ self._state = _State.CREATED self._timeout_handler: Optional[events.TimerHandle] = None @@ -34,9 +44,11 @@ def __init__(self, when: Optional[float]) -> None: self._when = when def when(self) -> Optional[float]: + """Return the current deadline.""" return self._when def reschedule(self, when: Optional[float]) -> None: + """Reschedule the timeout.""" assert self._state is not _State.CREATED if self._state is not _State.ENTERED: raise RuntimeError( From 49de99b65b551ff302e270ea477658e18e0488eb Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Sun, 19 Mar 2023 23:52:47 +0100 Subject: [PATCH 151/280] gh-102491: Remove IronPython version check in sys_version (#102492) --- Lib/platform.py | 35 +------------------ Lib/test/test_platform.py | 24 ++++--------- ...-03-08-08-37-36.gh-issue-102491.SFvvsC.rst | 2 ++ 3 files changed, 10 insertions(+), 51 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-03-08-08-37-36.gh-issue-102491.SFvvsC.rst diff --git a/Lib/platform.py b/Lib/platform.py index f2b0d1d1bd3f5d..790ef860bf106e 100755 --- a/Lib/platform.py +++ b/Lib/platform.py @@ -1040,20 +1040,6 @@ def processor(): r'(?:,\s*([\w :]*))?)?\)\s*' # ", buildtime)" r'\[([^\]]+)\]?', re.ASCII) # "[compiler]" -_ironpython_sys_version_parser = re.compile( - r'IronPython\s*' - r'([\d\.]+)' - r'(?: \(([\d\.]+)\))?' - r' on (.NET [\d\.]+)', re.ASCII) - -# IronPython covering 2.6 and 2.7 -_ironpython26_sys_version_parser = re.compile( - r'([\d.]+)\s*' - r'\(IronPython\s*' - r'[\d.]+\s*' - r'\(([\d.]+)\) on ([\w.]+ [\d.]+(?: \(\d+-bit\))?)\)' -) - _pypy_sys_version_parser = re.compile( r'([\w.+]+)\s*' r'\(#?([^,]+),\s*([\w ]+),\s*([\w :]+)\)\s*' @@ -1090,25 +1076,7 @@ def _sys_version(sys_version=None): if result is not None: return result - # Parse it - if 'IronPython' in sys_version: - # IronPython - name = 'IronPython' - if sys_version.startswith('IronPython'): - match = _ironpython_sys_version_parser.match(sys_version) - else: - match = _ironpython26_sys_version_parser.match(sys_version) - - if match is None: - raise ValueError( - 'failed to parse IronPython sys.version: %s' % - repr(sys_version)) - - version, alt_version, compiler = match.groups() - buildno = '' - builddate = '' - - elif sys.platform.startswith('java'): + if sys.platform.startswith('java'): # Jython name = 'Jython' match = _sys_version_parser.match(sys_version) @@ -1171,7 +1139,6 @@ def python_implementation(): Currently, the following implementations are identified: 'CPython' (C implementation of Python), - 'IronPython' (.NET implementation of Python), 'Jython' (Java implementation of Python), 'PyPy' (Python implementation of Python). diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index 72942dda342418..216973350319fe 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -123,10 +123,6 @@ def test_sys_version(self): for input, output in ( ('2.4.3 (#1, Jun 21 2006, 13:54:21) \n[GCC 3.3.4 (pre 3.3.5 20040809)]', ('CPython', '2.4.3', '', '', '1', 'Jun 21 2006 13:54:21', 'GCC 3.3.4 (pre 3.3.5 20040809)')), - ('IronPython 1.0.60816 on .NET 2.0.50727.42', - ('IronPython', '1.0.60816', '', '', '', '', '.NET 2.0.50727.42')), - ('IronPython 1.0 (1.0.61005.1977) on .NET 2.0.50727.42', - ('IronPython', '1.0.0', '', '', '', '', '.NET 2.0.50727.42')), ('2.4.3 (truncation, date, t) \n[GCC]', ('CPython', '2.4.3', '', '', 'truncation', 'date t', 'GCC')), ('2.4.3 (truncation, date, ) \n[GCC]', @@ -161,20 +157,11 @@ def test_sys_version(self): ('r261:67515', 'Dec 6 2008 15:26:00'), 'GCC 4.0.1 (Apple Computer, Inc. build 5370)'), - ("IronPython 2.0 (2.0.0.0) on .NET 2.0.50727.3053", None, "cli") + ("3.10.8 (tags/v3.10.8:aaaf517424, Feb 14 2023, 16:28:12) [GCC 9.4.0]", + None, "linux") : - ("IronPython", "2.0.0", "", "", ("", ""), - ".NET 2.0.50727.3053"), - - ("2.6.1 (IronPython 2.6.1 (2.6.10920.0) on .NET 2.0.50727.1433)", None, "cli") - : - ("IronPython", "2.6.1", "", "", ("", ""), - ".NET 2.0.50727.1433"), - - ("2.7.4 (IronPython 2.7.4 (2.7.0.40) on Mono 4.0.30319.1 (32-bit))", None, "cli") - : - ("IronPython", "2.7.4", "", "", ("", ""), - "Mono 4.0.30319.1 (32-bit)"), + ('CPython', '3.10.8', '', '', + ('tags/v3.10.8:aaaf517424', 'Feb 14 2023 16:28:12'), 'GCC 9.4.0'), ("2.5 (trunk:6107, Mar 26 2009, 13:02:18) \n[Java HotSpot(TM) Client VM (\"Apple Computer, Inc.\")]", ('Jython', 'trunk', '6107'), "java1.5.0_16") @@ -205,6 +192,9 @@ def test_sys_version(self): self.assertEqual(platform.python_build(), info[4]) self.assertEqual(platform.python_compiler(), info[5]) + with self.assertRaises(ValueError): + platform._sys_version('2. 4.3 (truncation) \n[GCC]') + def test_system_alias(self): res = platform.system_alias( platform.system(), diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-08-08-37-36.gh-issue-102491.SFvvsC.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-08-08-37-36.gh-issue-102491.SFvvsC.rst new file mode 100644 index 00000000000000..5bdc9ed2f37adc --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-08-08-37-36.gh-issue-102491.SFvvsC.rst @@ -0,0 +1,2 @@ +Improve import time of ``platform`` by removing IronPython version parsing. The IronPython version parsing +was not functional (see https://github.com/IronLanguages/ironpython3/issues/1667). From 5699276ed0455e840dcf2fce7035ffd9daf553b4 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Mon, 20 Mar 2023 00:03:55 +0000 Subject: [PATCH 152/280] gh-102828: fix test failure (add missing skip instructions) (#102835) --- Lib/test/test_shutil.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index fee3e7f765639a..89d65af3bc5b2b 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -496,6 +496,10 @@ def check_args_to_onexc(self, func, arg, exc): self.assertTrue(isinstance(exc, OSError)) self.errorState = 3 + @unittest.skipIf(sys.platform[:6] == 'cygwin', + "This test can't be run on Cygwin (issue #1071513).") + @os_helper.skip_if_dac_override + @os_helper.skip_unless_working_chmod def test_both_onerror_and_onexc(self): onerror_called = False onexc_called = False From 7dab35937e5c97fa8f3713b023bbdea4671b572e Mon Sep 17 00:00:00 2001 From: Alan Williams Date: Sun, 19 Mar 2023 19:20:20 -0500 Subject: [PATCH 153/280] gh-72346: Added isdst deprecation warning to email.utils.localtime (GH-91450) --- Doc/library/email.utils.rst | 22 +++++----- Doc/whatsnew/3.12.rst | 3 ++ Lib/email/utils.py | 40 +++++-------------- Lib/test/test_email/test_utils.py | 13 ++++-- ...2-04-11-18-34-33.gh-issue-72346.pC7gnM.rst | 1 + 5 files changed, 34 insertions(+), 45 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-72346.pC7gnM.rst diff --git a/Doc/library/email.utils.rst b/Doc/library/email.utils.rst index 0e266b6a45782a..345b64001c1ace 100644 --- a/Doc/library/email.utils.rst +++ b/Doc/library/email.utils.rst @@ -13,19 +13,17 @@ module: .. function:: localtime(dt=None) - Return local time as an aware datetime object. If called without - arguments, return current time. Otherwise *dt* argument should be a - :class:`~datetime.datetime` instance, and it is converted to the local time - zone according to the system time zone database. If *dt* is naive (that - is, ``dt.tzinfo`` is ``None``), it is assumed to be in local time. In this - case, a positive or zero value for *isdst* causes ``localtime`` to presume - initially that summer time (for example, Daylight Saving Time) is or is not - (respectively) in effect for the specified time. A negative value for - *isdst* causes the ``localtime`` to attempt to divine whether summer time - is in effect for the specified time. - - .. versionadded:: 3.3 + Return local time as an aware datetime object. If called without + arguments, return current time. Otherwise *dt* argument should be a + :class:`~datetime.datetime` instance, and it is converted to the local time + zone according to the system time zone database. If *dt* is naive (that + is, ``dt.tzinfo`` is ``None``), it is assumed to be in local time. The + *isdst* parameter is ignored. + .. versionadded:: 3.3 + + .. deprecated-removed:: 3.12 3.14 + The *isdst* parameter. .. function:: make_msgid(idstring=None, domain=None) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index a36e68528c4f74..cdd26cd19e720b 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -565,6 +565,9 @@ Pending Removal in Python 3.14 * Creating :c:data:`immutable types ` with mutable bases using the C API. +* Deprecated the *isdst* parameter in :func:`email.utils.localtime`. + (Contributed by Alan Williams in :gh:`72346`.) + * ``__package__`` and ``__cached__`` will cease to be set or taken into consideration by the import system (:gh:`97879`). diff --git a/Lib/email/utils.py b/Lib/email/utils.py index cfdfeb3f1a86e4..4d014bacd6182e 100644 --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -331,41 +331,23 @@ def collapse_rfc2231_value(value, errors='replace', # better than not having it. # -def localtime(dt=None, isdst=-1): +def localtime(dt=None, isdst=None): """Return local time as an aware datetime object. If called without arguments, return current time. Otherwise *dt* argument should be a datetime instance, and it is converted to the local time zone according to the system time zone database. If *dt* is naive (that is, dt.tzinfo is None), it is assumed to be in local time. - In this case, a positive or zero value for *isdst* causes localtime to - presume initially that summer time (for example, Daylight Saving Time) - is or is not (respectively) in effect for the specified time. A - negative value for *isdst* causes the localtime() function to attempt - to divine whether summer time is in effect for the specified time. + The isdst parameter is ignored. """ + if isdst is not None: + import warnings + warnings._deprecated( + "The 'isdst' parameter to 'localtime'", + message='{name} is deprecated and slated for removal in Python {remove}', + remove=(3, 14), + ) if dt is None: - return datetime.datetime.now(datetime.timezone.utc).astimezone() - if dt.tzinfo is not None: - return dt.astimezone() - # We have a naive datetime. Convert to a (localtime) timetuple and pass to - # system mktime together with the isdst hint. System mktime will return - # seconds since epoch. - tm = dt.timetuple()[:-1] + (isdst,) - seconds = time.mktime(tm) - localtm = time.localtime(seconds) - try: - delta = datetime.timedelta(seconds=localtm.tm_gmtoff) - tz = datetime.timezone(delta, localtm.tm_zone) - except AttributeError: - # Compute UTC offset and compare with the value implied by tm_isdst. - # If the values match, use the zone name implied by tm_isdst. - delta = dt - datetime.datetime(*time.gmtime(seconds)[:6]) - dst = time.daylight and localtm.tm_isdst > 0 - gmtoff = -(time.altzone if dst else time.timezone) - if delta == datetime.timedelta(seconds=gmtoff): - tz = datetime.timezone(delta, time.tzname[dst]) - else: - tz = datetime.timezone(delta) - return dt.replace(tzinfo=tz) + dt = datetime.datetime.now() + return dt.astimezone() diff --git a/Lib/test/test_email/test_utils.py b/Lib/test/test_email/test_utils.py index 78afb358035e81..25fa48c5ee217b 100644 --- a/Lib/test/test_email/test_utils.py +++ b/Lib/test/test_email/test_utils.py @@ -83,14 +83,14 @@ def test_localtime_is_tz_aware_daylight_false(self): def test_localtime_daylight_true_dst_false(self): test.support.patch(self, time, 'daylight', True) t0 = datetime.datetime(2012, 3, 12, 1, 1) - t1 = utils.localtime(t0, isdst=-1) + t1 = utils.localtime(t0) t2 = utils.localtime(t1) self.assertEqual(t1, t2) def test_localtime_daylight_false_dst_false(self): test.support.patch(self, time, 'daylight', False) t0 = datetime.datetime(2012, 3, 12, 1, 1) - t1 = utils.localtime(t0, isdst=-1) + t1 = utils.localtime(t0) t2 = utils.localtime(t1) self.assertEqual(t1, t2) @@ -98,7 +98,7 @@ def test_localtime_daylight_false_dst_false(self): def test_localtime_daylight_true_dst_true(self): test.support.patch(self, time, 'daylight', True) t0 = datetime.datetime(2012, 3, 12, 1, 1) - t1 = utils.localtime(t0, isdst=1) + t1 = utils.localtime(t0) t2 = utils.localtime(t1) self.assertEqual(t1, t2) @@ -106,7 +106,7 @@ def test_localtime_daylight_true_dst_true(self): def test_localtime_daylight_false_dst_true(self): test.support.patch(self, time, 'daylight', False) t0 = datetime.datetime(2012, 3, 12, 1, 1) - t1 = utils.localtime(t0, isdst=1) + t1 = utils.localtime(t0) t2 = utils.localtime(t1) self.assertEqual(t1, t2) @@ -157,6 +157,11 @@ def test_variable_tzname(self): t1 = utils.localtime(t0) self.assertEqual(t1.tzname(), 'EET') + def test_isdst_deprecation(self): + with self.assertWarns(DeprecationWarning): + t0 = datetime.datetime(1990, 1, 1) + t1 = utils.localtime(t0, isdst=True) + # Issue #24836: The timezone files are out of date (pre 2011k) # on Mac OS X Snow Leopard. @test.support.requires_mac_ver(10, 7) diff --git a/Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-72346.pC7gnM.rst b/Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-72346.pC7gnM.rst new file mode 100644 index 00000000000000..149ddd706c358f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-04-11-18-34-33.gh-issue-72346.pC7gnM.rst @@ -0,0 +1 @@ +Added deprecation warning to *isdst* parameter of :func:`email.utils.localtime`. From 6e01113b05b88fef73d9b7c9c28892df3ca9e3b4 Mon Sep 17 00:00:00 2001 From: Max Bachmann Date: Mon, 20 Mar 2023 16:47:17 +0100 Subject: [PATCH 154/280] gh-102255: Use GetVersionEx instead of GetVersionExW to match argument type (GH-102583) Since we pass a structure of type `OSVERSIONINFOEX`, we need to call `GetVersionEx` instead of `GetVersionExW`. --- Modules/socketmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index b7927750e334b7..6a6f8cf7392e1c 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -353,7 +353,7 @@ remove_unusable_flags(PyObject *m) } #ifndef MS_WINDOWS_DESKTOP info.dwOSVersionInfoSize = sizeof(info); - if (!GetVersionExW((OSVERSIONINFOW*) &info)) { + if (!GetVersionEx((OSVERSIONINFO*) &info)) { PyErr_SetFromWindowsErr(0); return -1; } From 2b10a8d5ca94144cd4fd9f4242ebc4070a0553ab Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 20 Mar 2023 10:03:04 -0600 Subject: [PATCH 155/280] gh-102304: Move _Py_RefTotal to _PyRuntimeState (gh-102543) The essentially eliminates the global variable, with the associated benefits. This is also a precursor to isolating this bit of state to PyInterpreterState. Folks that currently read _Py_RefTotal directly would have to start using _Py_GetGlobalRefTotal() instead. https://github.com/python/cpython/issues/102304 --- Include/cpython/object.h | 5 +- Include/internal/pycore_object.h | 4 +- Include/internal/pycore_object_state.h | 23 ++++++ Include/internal/pycore_runtime.h | 2 + Include/object.h | 9 +-- Makefile.pre.in | 1 + Objects/object.c | 101 +++++++++++++++++++------ PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 3 + Python/pylifecycle.c | 1 + Python/pystate.c | 3 + Python/sysmodule.c | 2 +- Tools/c-analyzer/cpython/ignored.tsv | 2 +- 13 files changed, 121 insertions(+), 36 deletions(-) create mode 100644 Include/internal/pycore_object_state.h diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 7b687d311359c3..0438612edd1dfe 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -11,7 +11,10 @@ PyAPI_FUNC(void) _Py_ForgetReference(PyObject *); #endif #ifdef Py_REF_DEBUG -PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void); +/* These are useful as debugging aids when chasing down refleaks. */ +PyAPI_FUNC(Py_ssize_t) _Py_GetGlobalRefTotal(void); +# define _Py_GetRefTotal() _Py_GetGlobalRefTotal() +PyAPI_FUNC(Py_ssize_t) _Py_GetLegacyRefTotal(void); #endif diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 318e6f3371c0c3..b985eff8a8a08b 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -46,7 +46,8 @@ PyAPI_DATA(Py_ssize_t) _Py_RefTotal; extern void _Py_AddRefTotal(Py_ssize_t); extern void _Py_IncRefTotal(void); extern void _Py_DecRefTotal(void); -# define _Py_DEC_REFTOTAL() _Py_RefTotal-- + +# define _Py_DEC_REFTOTAL() _PyRuntime.object_state.reftotal-- #endif // Increment reference count by n @@ -225,6 +226,7 @@ static inline void _PyObject_GC_UNTRACK( #endif #ifdef Py_REF_DEBUG +extern void _Py_FinalizeRefTotal(_PyRuntimeState *); extern void _PyDebug_PrintTotalRefs(void); #endif diff --git a/Include/internal/pycore_object_state.h b/Include/internal/pycore_object_state.h new file mode 100644 index 00000000000000..4e5862a11eddc5 --- /dev/null +++ b/Include/internal/pycore_object_state.h @@ -0,0 +1,23 @@ +#ifndef Py_INTERNAL_OBJECT_STATE_H +#define Py_INTERNAL_OBJECT_STATE_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +struct _py_object_runtime_state { +#ifdef Py_REF_DEBUG + Py_ssize_t reftotal; +#else + int _not_used; +#endif +}; + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_OBJECT_STATE_H */ diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index 520109ca440444..de757dfa93bc26 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -15,6 +15,7 @@ extern "C" { #include "pycore_global_objects.h" // struct _Py_global_objects #include "pycore_import.h" // struct _import_runtime_state #include "pycore_interp.h" // PyInterpreterState +#include "pycore_object_state.h" // struct _py_object_runtime_state #include "pycore_parser.h" // struct _parser_runtime_state #include "pycore_pymem.h" // struct _pymem_allocators #include "pycore_pyhash.h" // struct pyhash_runtime_state @@ -150,6 +151,7 @@ typedef struct pyruntimestate { void *open_code_userdata; _Py_AuditHookEntry *audit_hook_head; + struct _py_object_runtime_state object_state; struct _Py_float_runtime_state float_state; struct _Py_unicode_runtime_state unicode_state; diff --git a/Include/object.h b/Include/object.h index 844b9c4a51c3e4..fc577353c1cc13 100644 --- a/Include/object.h +++ b/Include/object.h @@ -494,14 +494,9 @@ you can count such references to the type object.) extern Py_ssize_t _Py_RefTotal; # define _Py_INC_REFTOTAL() _Py_RefTotal++ # define _Py_DEC_REFTOTAL() _Py_RefTotal-- -# elif defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) -extern void _Py_IncRefTotal(void); -extern void _Py_DecRefTotal(void); -# define _Py_INC_REFTOTAL() _Py_IncRefTotal() -# define _Py_DEC_REFTOTAL() _Py_DecRefTotal() # elif !defined(Py_LIMITED_API) || Py_LIMITED_API+0 > 0x030C0000 -extern void _Py_IncRefTotal_DO_NOT_USE_THIS(void); -extern void _Py_DecRefTotal_DO_NOT_USE_THIS(void); +PyAPI_FUNC(void) _Py_IncRefTotal_DO_NOT_USE_THIS(void); +PyAPI_FUNC(void) _Py_DecRefTotal_DO_NOT_USE_THIS(void); # define _Py_INC_REFTOTAL() _Py_IncRefTotal_DO_NOT_USE_THIS() # define _Py_DEC_REFTOTAL() _Py_DecRefTotal_DO_NOT_USE_THIS() # endif diff --git a/Makefile.pre.in b/Makefile.pre.in index 8f13198e7e34b3..74e4171b010d0f 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1699,6 +1699,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_moduleobject.h \ $(srcdir)/Include/internal/pycore_namespace.h \ $(srcdir)/Include/internal/pycore_object.h \ + $(srcdir)/Include/internal/pycore_object_state.h \ $(srcdir)/Include/internal/pycore_obmalloc.h \ $(srcdir)/Include/internal/pycore_obmalloc_init.h \ $(srcdir)/Include/internal/pycore_pathconfig.h \ diff --git a/Objects/object.c b/Objects/object.c index dff5e2afa16ab8..95f7c966a414de 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -54,37 +54,71 @@ _PyObject_CheckConsistency(PyObject *op, int check_content) #ifdef Py_REF_DEBUG +/* We keep the legacy symbol around for backward compatibility. */ Py_ssize_t _Py_RefTotal; +static inline Py_ssize_t +get_legacy_reftotal(void) +{ + return _Py_RefTotal; +} +#endif + +#ifdef Py_REF_DEBUG + +# define REFTOTAL(runtime) \ + (runtime)->object_state.reftotal + +static inline void +reftotal_increment(_PyRuntimeState *runtime) +{ + REFTOTAL(runtime)++; +} + static inline void -reftotal_increment(void) +reftotal_decrement(_PyRuntimeState *runtime) { - _Py_RefTotal++; + REFTOTAL(runtime)--; } static inline void -reftotal_decrement(void) +reftotal_add(_PyRuntimeState *runtime, Py_ssize_t n) { - _Py_RefTotal--; + REFTOTAL(runtime) += n; } +static inline Py_ssize_t get_global_reftotal(_PyRuntimeState *); + +/* We preserve the number of refs leaked during runtime finalization, + so they can be reported if the runtime is initialized again. */ +// XXX We don't lose any information by dropping this, +// so we should consider doing so. +static Py_ssize_t last_final_reftotal = 0; + void -_Py_AddRefTotal(Py_ssize_t n) +_Py_FinalizeRefTotal(_PyRuntimeState *runtime) { - _Py_RefTotal += n; + last_final_reftotal = get_global_reftotal(runtime); + REFTOTAL(runtime) = 0; } -Py_ssize_t -_Py_GetRefTotal(void) +static inline Py_ssize_t +get_global_reftotal(_PyRuntimeState *runtime) { - return _Py_RefTotal; + /* For an update from _Py_RefTotal first. */ + Py_ssize_t legacy = get_legacy_reftotal(); + return REFTOTAL(runtime) + legacy + last_final_reftotal; } +#undef REFTOTAL + void _PyDebug_PrintTotalRefs(void) { + _PyRuntimeState *runtime = &_PyRuntime; fprintf(stderr, "[%zd refs, %zd blocks]\n", - _Py_GetRefTotal(), _Py_GetAllocatedBlocks()); + get_global_reftotal(runtime), _Py_GetAllocatedBlocks()); + /* It may be helpful to also print the "legacy" reftotal separately. */ } #endif /* Py_REF_DEBUG */ @@ -139,30 +173,50 @@ _Py_NegativeRefcount(const char *filename, int lineno, PyObject *op) filename, lineno, __func__); } -/* This is exposed strictly for use in Py_INCREF(). */ -PyAPI_FUNC(void) +/* This is used strictly by Py_INCREF(). */ +void _Py_IncRefTotal_DO_NOT_USE_THIS(void) { - reftotal_increment(); + reftotal_increment(&_PyRuntime); } -/* This is exposed strictly for use in Py_DECREF(). */ -PyAPI_FUNC(void) +/* This is used strictly by Py_DECREF(). */ +void _Py_DecRefTotal_DO_NOT_USE_THIS(void) { - reftotal_decrement(); + reftotal_decrement(&_PyRuntime); } void _Py_IncRefTotal(void) { - reftotal_increment(); + reftotal_increment(&_PyRuntime); } void _Py_DecRefTotal(void) { - reftotal_decrement(); + reftotal_decrement(&_PyRuntime); +} + +void +_Py_AddRefTotal(Py_ssize_t n) +{ + reftotal_add(&_PyRuntime, n); +} + +/* This includes the legacy total + and any carried over from the last runtime init/fini cycle. */ +Py_ssize_t +_Py_GetGlobalRefTotal(void) +{ + return get_global_reftotal(&_PyRuntime); +} + +Py_ssize_t +_Py_GetLegacyRefTotal(void) +{ + return get_legacy_reftotal(); } #endif /* Py_REF_DEBUG */ @@ -182,21 +236,18 @@ Py_DecRef(PyObject *o) void _Py_IncRef(PyObject *o) { -#ifdef Py_REF_DEBUG - reftotal_increment(); -#endif Py_INCREF(o); } void _Py_DecRef(PyObject *o) { -#ifdef Py_REF_DEBUG - reftotal_decrement(); -#endif Py_DECREF(o); } + +/**************************************/ + PyObject * PyObject_Init(PyObject *op, PyTypeObject *tp) { @@ -2077,7 +2128,7 @@ void _Py_NewReference(PyObject *op) { #ifdef Py_REF_DEBUG - reftotal_increment(); + reftotal_increment(&_PyRuntime); #endif new_reference(op); } diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 447a6787de8af7..03d70e711c32bf 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -239,6 +239,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index b29c2dc62667a6..cf03edff4e10d1 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -621,6 +621,9 @@ Include\internal + + Include\internal + Include\internal diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 317d6966d034fa..731f340001b4e0 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1930,6 +1930,7 @@ Py_FinalizeEx(void) if (show_ref_count) { _PyDebug_PrintTotalRefs(); } + _Py_FinalizeRefTotal(runtime); #endif #ifdef Py_TRACE_REFS diff --git a/Python/pystate.c b/Python/pystate.c index 3a2966c54a4c3b..4d4213551a8b1c 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -482,6 +482,9 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime) void _PyRuntimeState_Fini(_PyRuntimeState *runtime) { + /* The reftotal is cleared by _Py_FinalizeRefTotal(). */ + assert(runtime->object_state.reftotal == 0); + if (gilstate_tss_initialized(runtime)) { gilstate_tss_fini(runtime); } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 126b7d422e0009..20761738b527cb 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1854,7 +1854,7 @@ static Py_ssize_t sys_gettotalrefcount_impl(PyObject *module) /*[clinic end generated code: output=4103886cf17c25bc input=53b744faa5d2e4f6]*/ { - return _Py_GetRefTotal(); + return _Py_GetGlobalRefTotal(); } #endif /* Py_REF_DEBUG */ diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 048112dd992555..14fc32a07b4309 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -141,7 +141,6 @@ Modules/syslogmodule.c - S_log_open - ##----------------------- ## kept for stable ABI compatibility -# XXX should be per-interpreter, without impacting stable ABI extensions Objects/object.c - _Py_RefTotal - ##----------------------- @@ -301,6 +300,7 @@ Objects/genobject.c - NON_INIT_CORO_MSG - Objects/longobject.c - _PyLong_DigitValue - Objects/object.c - _Py_SwappedOp - Objects/object.c - _Py_abstract_hack - +Objects/object.c - last_final_reftotal - Objects/object.c - static_types - Objects/obmalloc.c - _PyMem - Objects/obmalloc.c - _PyMem_Debug - From 457391d4753da3288fb382d312165c905d46310c Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 20 Mar 2023 10:35:49 -0600 Subject: [PATCH 156/280] gh-102304: Add a What's New Entry About _Py_RefTotal (gh-102845) https://github.com/python/cpython/issues/102304 --- Doc/whatsnew/3.12.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index cdd26cd19e720b..af52c7cb670c61 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1036,6 +1036,11 @@ Porting to Python 3.12 functions that set the error indicator now normalize the exception before storing it. (Contributed by Mark Shannon in :gh:`101578`.) +* ``_Py_RefTotal`` is no longer authoritative and only kept around + for ABI compabitility. Note that it is an internal global and only + available on debug builds. If you happen to be using it then you'll + need to start using ``_Py_GetGlobalRefTotal()``. + Deprecated ---------- From 76fb37b43b179cc8e11fe2b3c200f128c7ee1e8f Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 20 Mar 2023 11:28:13 -0600 Subject: [PATCH 157/280] gh-102304: Fix Non-Debug Builds (gh-102846) Some debug-only code slipped in with gh-102543. https://github.com/python/cpython/issues/102304 --- Python/pystate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Python/pystate.c b/Python/pystate.c index 4d4213551a8b1c..60adb54685ce68 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -482,8 +482,10 @@ _PyRuntimeState_Init(_PyRuntimeState *runtime) void _PyRuntimeState_Fini(_PyRuntimeState *runtime) { +#ifdef Py_REF_DEBUG /* The reftotal is cleared by _Py_FinalizeRefTotal(). */ assert(runtime->object_state.reftotal == 0); +#endif if (gilstate_tss_initialized(runtime)) { gilstate_tss_fini(runtime); From a003e0ff5ee4d3020574e7a9c0418531bfa664d9 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Mon, 20 Mar 2023 17:14:29 -0500 Subject: [PATCH 158/280] Add itertool recipe for polynomial evaluation. (GH-102852) --- Doc/library/itertools.rst | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index d85a17effb04a2..9364f72ca45610 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -866,6 +866,15 @@ which incur interpreter overhead. window.append(x) yield math.sumprod(kernel, window) + def polynomial_eval(coefficients, x): + "Evaluate a polynomial at a specific value." + # polynomial_eval([1, -4, -17, 60], x=2.5) --> 8.125 x³ -4x² -17x + 60 + n = len(coefficients) + if n == 0: + return x * 0 # coerce zero to the type of x + powers = list(accumulate(repeat(x, n - 1), operator.mul, initial=1)) + return math.sumprod(coefficients, reversed(powers)) + def polynomial_from_roots(roots): """Compute a polynomial's coefficients from its roots. @@ -1245,6 +1254,37 @@ which incur interpreter overhead. >>> list(convolve(data, [1, -2, 1])) [20, 0, -36, 24, -20, 20, -20, -4, 16] + >>> from fractions import Fraction + >>> from decimal import Decimal + >>> polynomial_eval([1, -4, -17, 60], x=2) + 18 + >>> x = 2; x**3 - 4*x**2 -17*x + 60 + 18 + >>> polynomial_eval([1, -4, -17, 60], x=2.5) + 8.125 + >>> x = 2.5; x**3 - 4*x**2 -17*x + 60 + 8.125 + >>> polynomial_eval([1, -4, -17, 60], x=Fraction(2, 3)) + Fraction(1274, 27) + >>> x = Fraction(2, 3); x**3 - 4*x**2 -17*x + 60 + Fraction(1274, 27) + >>> polynomial_eval([1, -4, -17, 60], x=Decimal('1.75')) + Decimal('23.359375') + >>> x = Decimal('1.75'); x**3 - 4*x**2 -17*x + 60 + Decimal('23.359375') + >>> polynomial_eval([], 2) + 0 + >>> polynomial_eval([], 2.5) + 0.0 + >>> polynomial_eval([], Fraction(2, 3)) + Fraction(0, 1) + >>> polynomial_eval([], Decimal('1.75')) + Decimal('0.00') + >>> polynomial_eval([11], 7) == 11 + True + >>> polynomial_eval([11, 2], 7) == 11 * 7 + 2 + True + >>> polynomial_from_roots([5, -4, 3]) [1, -4, -17, 60] >>> factored = lambda x: (x - 5) * (x + 4) * (x - 3) From 1886084724a9f885cc448e2ef4f793c88630774f Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Tue, 21 Mar 2023 02:30:46 +0300 Subject: [PATCH 159/280] gh-102809: Remove `Misc/gdbinit` (#102854) Looks like the consensus is that we don't need this file anymore. Old version can be always found here: https://github.com/python/cpython/blob/094cf392f49d3c16fe798863717f6c8e0f3734bb/Misc/gdbinit --- ...-03-21-01-27-07.gh-issue-102809.2F1Byz.rst | 1 + Misc/gdbinit | 176 ------------------ 2 files changed, 1 insertion(+), 176 deletions(-) create mode 100644 Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-102809.2F1Byz.rst delete mode 100644 Misc/gdbinit diff --git a/Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-102809.2F1Byz.rst b/Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-102809.2F1Byz.rst new file mode 100644 index 00000000000000..5c282769878563 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2023-03-21-01-27-07.gh-issue-102809.2F1Byz.rst @@ -0,0 +1 @@ +``Misc/gdbinit`` was removed. diff --git a/Misc/gdbinit b/Misc/gdbinit deleted file mode 100644 index e8f62ba6476423..00000000000000 --- a/Misc/gdbinit +++ /dev/null @@ -1,176 +0,0 @@ -# If you use the GNU debugger gdb to debug the Python C runtime, you -# might find some of the following commands useful. Copy this to your -# ~/.gdbinit file and it'll get loaded into gdb automatically when you -# start it up. Then, at the gdb prompt you can do things like: -# -# (gdb) pyo apyobjectptr -# -# refcounts: 1 -# address : 84a7a2c -# $1 = void -# (gdb) -# -# NOTE: If you have gdb 7 or later, it supports debugging of Python directly -# with embedded macros that you may find superior to what is in here. -# See Tools/gdb/libpython.py and http://bugs.python.org/issue8032. - -define pyo - # side effect of calling _PyObject_Dump is to dump the object's - # info - assigning just prevents gdb from printing the - # NULL return value - set $_unused_void = _PyObject_Dump($arg0) -end -document pyo - Prints a representation of the object to stderr, along with the - number of reference counts it currently has and the hex address the - object is allocated at. The argument must be a PyObject* -end - -define pyg - print _PyGC_Dump($arg0) -end -document pyg - Prints a representation of the object to stderr, along with the - number of reference counts it currently has and the hex address the - object is allocated at. The argument must be a PyGC_Head* -end - -define pylocals - set $_i = 0 - while $_i < f->f_code->co_nlocals - if f->f_localsplus + $_i != 0 - set $_names = f->f_code->co_varnames - set $_name = PyUnicode_AsUTF8(PyTuple_GetItem($_names, $_i)) - printf "%s:\n", $_name - pyo f->f_localsplus[$_i] - end - set $_i = $_i + 1 - end -end -document pylocals - Print the local variables of the current frame. -end - -# A rewrite of the Python interpreter's line number calculator in GDB's -# command language -define lineno - set $__continue = 1 - set $__co = f->f_code - set $__lasti = f->f_lasti - set $__sz = ((PyVarObject *)$__co->co_lnotab)->ob_size/2 - set $__p = (unsigned char *)((PyBytesObject *)$__co->co_lnotab)->ob_sval - set $__li = $__co->co_firstlineno - set $__ad = 0 - while ($__sz-1 >= 0 && $__continue) - set $__sz = $__sz - 1 - set $__ad = $__ad + *$__p - set $__p = $__p + 1 - if ($__ad > $__lasti) - set $__continue = 0 - else - set $__li = $__li + *$__p - set $__p = $__p + 1 - end - end - printf "%d", $__li -end - -define pyframev - pyframe - pylocals -end -document pyframev - Print the current frame - verbose -end - -define pyframe - set $__fn = PyUnicode_AsUTF8(f->f_code->co_filename) - set $__n = PyUnicode_AsUTF8(f->f_code->co_name) - printf "%s (", $__fn - lineno - printf "): %s\n", $__n -### Uncomment these lines when using from within Emacs/XEmacs so it will -### automatically track/display the current Python source line -# printf "%c%c%s:", 032, 032, $__fn -# lineno -# printf ":1\n" -end - -### Use these at your own risk. It appears that a bug in gdb causes it -### to crash in certain circumstances. - -#define up -# up-silently 1 -# printframe -#end - -#define down -# down-silently 1 -# printframe -#end - -define printframe - if $pc > PyEval_EvalFrameEx && $pc < _PyEval_EvalFrameDefault - pyframe - else - frame - end -end - -# Here's a somewhat fragile way to print the entire Python stack from gdb. -# It's fragile because the tests for the value of $pc depend on the layout -# of specific functions in the C source code. - -# Explanation of while and if tests: We want to pop up the stack until we -# land in Py_Main (this is probably an incorrect assumption in an embedded -# interpreter, but the test can be extended by an interested party). If -# Py_Main <= $pc <= Py_GetArgcArv is true, $pc is in Py_Main(), so the while -# tests succeeds as long as it's not true. In a similar fashion the if -# statement tests to see if we are in PyEval_EvalFrameEx(). - -# Note: The name of the main interpreter function and the function which -# follow it has changed over time. This version of pystack works with this -# version of Python. If you try using it with older or newer versions of -# the interpreter you may will have to change the functions you compare with -# $pc. - -define pystack - while $pc < Py_Main || $pc > Py_GetArgcArgv - if $pc > PyEval_EvalFrameEx && $pc < _PyEval_EvalFrameDefault - pyframe - end - up-silently 1 - end - select-frame 0 -end -document pystack - Print the entire Python call stack -end - -define pystackv - while $pc < Py_Main || $pc > Py_GetArgcArgv - if $pc > PyEval_EvalFrameEx && $pc < _PyEval_EvalFrameDefault - pyframev - end - up-silently 1 - end - select-frame 0 -end -document pystackv - Print the entire Python call stack - verbose mode -end - -define pu - set $uni = $arg0 - set $i = 0 - while (*$uni && $i++<100) - if (*$uni < 0x80) - print *(char*)$uni++ - else - print /x *(short*)$uni++ - end - end -end -document pu - Generally useful macro to print a Unicode string -end From 5226688568cd476959b7c58375dff387058d6546 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Mon, 20 Mar 2023 20:40:04 -0500 Subject: [PATCH 160/280] Remove itermediate list. Expand docstring. (GH-102862) --- Doc/library/itertools.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 9364f72ca45610..2427a8d85f841c 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -867,13 +867,17 @@ which incur interpreter overhead. yield math.sumprod(kernel, window) def polynomial_eval(coefficients, x): - "Evaluate a polynomial at a specific value." - # polynomial_eval([1, -4, -17, 60], x=2.5) --> 8.125 x³ -4x² -17x + 60 + """Evaluate a polynomial at a specific value. + + Computes with better numeric stability than Horner's method. + """ + # Evaluate x³ -4x² -17x + 60 at x = 2.5 + # polynomial_eval([1, -4, -17, 60], x=2.5) --> 8.125 n = len(coefficients) if n == 0: return x * 0 # coerce zero to the type of x - powers = list(accumulate(repeat(x, n - 1), operator.mul, initial=1)) - return math.sumprod(coefficients, reversed(powers)) + powers = accumulate(repeat(x, n - 1), operator.mul, initial=1) + return math.sumprod(reversed(coefficients), powers) def polynomial_from_roots(roots): """Compute a polynomial's coefficients from its roots. From f357fc76caa2d9d781e57679907eea8fe7d32ccd Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 21 Mar 2023 00:02:14 -0500 Subject: [PATCH 161/280] The pow() variant further improves accuracy (GH-102866) --- Doc/library/itertools.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 2427a8d85f841c..78f64ea67e2542 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -876,7 +876,7 @@ which incur interpreter overhead. n = len(coefficients) if n == 0: return x * 0 # coerce zero to the type of x - powers = accumulate(repeat(x, n - 1), operator.mul, initial=1) + powers = map(pow, repeat(x), range(n)) return math.sumprod(reversed(coefficients), powers) def polynomial_from_roots(roots): From af512cc383bb32a6ec815ba43e8d9a63cdfd1641 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Tue, 21 Mar 2023 10:47:15 +0300 Subject: [PATCH 162/280] gh-102598: Remove obsolete optimization from `FORMAT_VALUE` opcode (#102599) --- Python/bytecodes.c | 18 ++++-------------- Python/generated_cases.c.h | 19 ++++--------------- 2 files changed, 8 insertions(+), 29 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index c8ffd89c51a22c..92fa7664e00452 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3254,20 +3254,10 @@ dummy_func( value = result; } - /* If value is a unicode object, and there's no fmt_spec, - then we know the result of format(value) is value - itself. In that case, skip calling format(). I plan to - move this optimization in to PyObject_Format() - itself. */ - if (PyUnicode_CheckExact(value) && fmt_spec == NULL) { - /* Do nothing, just transfer ownership to result. */ - result = value; - } else { - /* Actually call format(). */ - result = PyObject_Format(value, fmt_spec); - DECREF_INPUTS(); - ERROR_IF(result == NULL, error); - } + result = PyObject_Format(value, fmt_spec); + Py_DECREF(value); + Py_XDECREF(fmt_spec); + ERROR_IF(result == NULL, error); } inst(COPY, (bottom, unused[oparg-1] -- bottom, unused[oparg-1], top: *bottom)) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 2c6388390b51ad..9df173f843f806 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -4118,21 +4118,10 @@ value = result; } - /* If value is a unicode object, and there's no fmt_spec, - then we know the result of format(value) is value - itself. In that case, skip calling format(). I plan to - move this optimization in to PyObject_Format() - itself. */ - if (PyUnicode_CheckExact(value) && fmt_spec == NULL) { - /* Do nothing, just transfer ownership to result. */ - result = value; - } else { - /* Actually call format(). */ - result = PyObject_Format(value, fmt_spec); - Py_DECREF(value); - Py_XDECREF(fmt_spec); - if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } - } + result = PyObject_Format(value, fmt_spec); + Py_DECREF(value); + Py_XDECREF(fmt_spec); + if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; } STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); stack_pointer[-1] = result; DISPATCH(); From 45e8c3e8b6401d498f8bf91503235c6184913c3d Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Tue, 21 Mar 2023 09:36:18 +0000 Subject: [PATCH 163/280] gh-102755: PyErr_DisplayException only in ABI >= 3.12. Tests cover PyErr_Display as well (GH-102849) --- Include/pythonrun.h | 3 +++ Lib/test/test_traceback.py | 16 +++++++++++++++- Modules/_testcapi/exceptions.c | 16 +++++++++++++--- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/Include/pythonrun.h b/Include/pythonrun.h index 41d82e89f84876..154c7450cb934f 100644 --- a/Include/pythonrun.h +++ b/Include/pythonrun.h @@ -12,7 +12,10 @@ PyAPI_FUNC(PyObject *) Py_CompileString(const char *, const char *, int); PyAPI_FUNC(void) PyErr_Print(void); PyAPI_FUNC(void) PyErr_PrintEx(int); PyAPI_FUNC(void) PyErr_Display(PyObject *, PyObject *, PyObject *); + +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030C0000 PyAPI_FUNC(void) PyErr_DisplayException(PyObject *); +#endif /* Stuff with no proper home (yet) */ diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 1c5d1ab82c8e9c..399c59f8780d8e 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -394,6 +394,8 @@ def get_exception(self, callable, slice_start=0, slice_end=-1): class CAPIExceptionFormattingMixin: + LEGACY = 0 + def get_exception(self, callable, slice_start=0, slice_end=-1): from _testcapi import exception_print try: @@ -401,11 +403,13 @@ def get_exception(self, callable, slice_start=0, slice_end=-1): self.fail("No exception thrown.") except Exception as e: with captured_output("stderr") as tbstderr: - exception_print(e) + exception_print(e, self.LEGACY) return tbstderr.getvalue().splitlines()[slice_start:slice_end] callable_line = get_exception.__code__.co_firstlineno + 3 +class CAPIExceptionFormattingLegacyMixin(CAPIExceptionFormattingMixin): + LEGACY = 1 @requires_debug_ranges() class TracebackErrorLocationCaretTestBase: @@ -912,6 +916,16 @@ class CPythonTracebackErrorCaretTests( Same set of tests as above but with Python's internal traceback printing. """ +@cpython_only +@requires_debug_ranges() +class CPythonTracebackErrorCaretTests( + CAPIExceptionFormattingLegacyMixin, + TracebackErrorLocationCaretTestBase, + unittest.TestCase, +): + """ + Same set of tests as above but with Python's legacy internal traceback printing. + """ class TracebackFormatTests(unittest.TestCase): diff --git a/Modules/_testcapi/exceptions.c b/Modules/_testcapi/exceptions.c index 1922ca3beb7916..6099f7d20eb56a 100644 --- a/Modules/_testcapi/exceptions.c +++ b/Modules/_testcapi/exceptions.c @@ -40,12 +40,22 @@ static PyObject * exception_print(PyObject *self, PyObject *args) { PyObject *exc; + int legacy = 0; - if (!PyArg_ParseTuple(args, "O:exception_print", &exc)) { + if (!PyArg_ParseTuple(args, "O|i:exception_print", &exc, &legacy)) { return NULL; } - - PyErr_DisplayException(exc); + if (legacy) { + PyObject *tb = NULL; + if (PyExceptionInstance_Check(exc)) { + tb = PyException_GetTraceback(exc); + } + PyErr_Display((PyObject *) Py_TYPE(exc), exc, tb); + Py_XDECREF(tb); + } + else { + PyErr_DisplayException(exc); + } Py_RETURN_NONE; } From 52172d3f9b7ee8c2c2e6a4c58a5c39762d7e0212 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Tue, 21 Mar 2023 11:07:03 +0000 Subject: [PATCH 164/280] gh-102799: Let pydoc use the exception instead of sys.exc_info (#102830) --- Lib/pydoc.py | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 0a693f45230c93..78d8fd5357f72a 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -389,8 +389,17 @@ def synopsis(filename, cache={}): class ErrorDuringImport(Exception): """Errors that occurred while trying to import something to document it.""" def __init__(self, filename, exc_info): + if not isinstance(exc_info, tuple): + assert isinstance(exc_info, BaseException) + self.exc = type(exc_info) + self.value = exc_info + self.tb = exc_info.__traceback__ + else: + warnings.warn("A tuple value for exc_info is deprecated, use an exception instance", + DeprecationWarning) + + self.exc, self.value, self.tb = exc_info self.filename = filename - self.exc, self.value, self.tb = exc_info def __str__(self): exc = self.exc.__name__ @@ -411,8 +420,8 @@ def importfile(path): spec = importlib.util.spec_from_file_location(name, path, loader=loader) try: return importlib._bootstrap._load(spec) - except: - raise ErrorDuringImport(path, sys.exc_info()) + except BaseException as err: + raise ErrorDuringImport(path, err) def safeimport(path, forceload=0, cache={}): """Import a module; handle errors; return None if the module isn't found. @@ -440,21 +449,20 @@ def safeimport(path, forceload=0, cache={}): cache[key] = sys.modules[key] del sys.modules[key] module = __import__(path) - except: + except BaseException as err: # Did the error occur before or after the module was found? - (exc, value, tb) = info = sys.exc_info() if path in sys.modules: # An error occurred while executing the imported module. - raise ErrorDuringImport(sys.modules[path].__file__, info) - elif exc is SyntaxError: + raise ErrorDuringImport(sys.modules[path].__file__, err) + elif type(err) is SyntaxError: # A SyntaxError occurred before we could execute the module. - raise ErrorDuringImport(value.filename, info) - elif issubclass(exc, ImportError) and value.name == path: + raise ErrorDuringImport(err.filename, err) + elif isinstance(err, ImportError) and err.name == path: # No such module in the path. return None else: # Some other error occurred during the importing process. - raise ErrorDuringImport(path, sys.exc_info()) + raise ErrorDuringImport(path, err) for part in path.split('.')[1:]: try: module = getattr(module, part) except AttributeError: return None @@ -1997,8 +2005,8 @@ def __call__(self, request=_GoInteractive): if request is not self._GoInteractive: try: self.help(request) - except ImportError as e: - self.output.write(f'{e}\n') + except ImportError as err: + self.output.write(f'{err}\n') else: self.intro() self.interact() @@ -2405,8 +2413,8 @@ def run(self): docsvr = DocServer(self.host, self.port, self.ready) self.docserver = docsvr docsvr.serve_until_quit() - except Exception as e: - self.error = e + except Exception as err: + self.error = err def ready(self, server): self.serving = True From 6776fb14bf93cb7302b1a12e639d94cb17edd471 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Tue, 21 Mar 2023 11:08:46 +0000 Subject: [PATCH 165/280] gh-102828: emit deprecation warning for onerror arg to shutil.rmtree (#102850) --- Doc/whatsnew/3.12.rst | 10 +++++++--- Lib/shutil.py | 6 ++++++ Lib/tempfile.py | 8 ++++---- Lib/test/test_shutil.py | 16 +++++++++++----- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index af52c7cb670c61..b7c956d7f78456 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -339,7 +339,8 @@ shutil * :func:`shutil.rmtree` now accepts a new argument *onexc* which is an error handler like *onerror* but which expects an exception instance - rather than a *(typ, val, tb)* triplet. *onerror* is deprecated. + rather than a *(typ, val, tb)* triplet. *onerror* is deprecated and + will be removed in Python 3.14. (Contributed by Irit Katriel in :gh:`102828`.) @@ -503,8 +504,8 @@ Deprecated fields are deprecated. Use :data:`sys.last_exc` instead. (Contributed by Irit Katriel in :gh:`102778`.) -* The *onerror* argument of :func:`shutil.rmtree` is deprecated. Use *onexc* - instead. (Contributed by Irit Katriel in :gh:`102828`.) +* The *onerror* argument of :func:`shutil.rmtree` is deprecated as will be removed + in Python 3.14. Use *onexc* instead. (Contributed by Irit Katriel in :gh:`102828`.) Pending Removal in Python 3.13 @@ -586,6 +587,9 @@ Pending Removal in Python 3.14 functions that have been deprecated since Python 2 but only gained a proper :exc:`DeprecationWarning` in 3.12. Remove them in 3.14. +* The *onerror* argument of :func:`shutil.rmtree` is deprecated in 3.12, + and will be removed in 3.14. + Pending Removal in Future Versions ---------------------------------- diff --git a/Lib/shutil.py b/Lib/shutil.py index 89a7ac72d98357..b0576407e02ffb 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -10,6 +10,7 @@ import fnmatch import collections import errno +import warnings try: import zlib @@ -692,6 +693,11 @@ def rmtree(path, ignore_errors=False, onerror=None, *, onexc=None, dir_fd=None): onerror is deprecated and only remains for backwards compatibility. If both onerror and onexc are set, onerror is ignored and onexc is used. """ + + if onerror is not None: + warnings.warn("onerror argument is deprecated, use onexc instead", + DeprecationWarning) + sys.audit("shutil.rmtree", path, dir_fd) if ignore_errors: def onexc(*args): diff --git a/Lib/tempfile.py b/Lib/tempfile.py index bb18d60db0d919..cf06092f826bcc 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -864,8 +864,8 @@ def __init__(self, suffix=None, prefix=None, dir=None, @classmethod def _rmtree(cls, name, ignore_errors=False): - def onerror(func, path, exc_info): - if issubclass(exc_info[0], PermissionError): + def onexc(func, path, exc): + if isinstance(exc, PermissionError): def resetperms(path): try: _os.chflags(path, 0) @@ -885,13 +885,13 @@ def resetperms(path): cls._rmtree(path, ignore_errors=ignore_errors) except FileNotFoundError: pass - elif issubclass(exc_info[0], FileNotFoundError): + elif isinstance(exc, FileNotFoundError): pass else: if not ignore_errors: raise - _shutil.rmtree(name, onerror=onerror) + _shutil.rmtree(name, onexc=onexc) @classmethod def _cleanup(cls, name, warn_message, ignore_errors=False): diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 89d65af3bc5b2b..1c0589ced9ea89 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -23,6 +23,7 @@ unregister_unpack_format, get_unpack_formats, SameFileError, _GiveupOnFastCopy) import tarfile +import warnings import zipfile try: import posix @@ -207,7 +208,8 @@ def test_rmtree_fails_on_symlink_onerror(self): errors = [] def onerror(*args): errors.append(args) - shutil.rmtree(link, onerror=onerror) + with self.assertWarns(DeprecationWarning): + shutil.rmtree(link, onerror=onerror) self.assertEqual(len(errors), 1) self.assertIs(errors[0][0], os.path.islink) self.assertEqual(errors[0][1], link) @@ -268,7 +270,8 @@ def test_rmtree_fails_on_junctions_onerror(self): errors = [] def onerror(*args): errors.append(args) - shutil.rmtree(link, onerror=onerror) + with self.assertWarns(DeprecationWarning): + shutil.rmtree(link, onerror=onerror) self.assertEqual(len(errors), 1) self.assertIs(errors[0][0], os.path.islink) self.assertEqual(errors[0][1], link) @@ -337,7 +340,8 @@ def test_rmtree_errors_onerror(self): errors = [] def onerror(*args): errors.append(args) - shutil.rmtree(filename, onerror=onerror) + with self.assertWarns(DeprecationWarning): + shutil.rmtree(filename, onerror=onerror) self.assertEqual(len(errors), 2) self.assertIs(errors[0][0], os.scandir) self.assertEqual(errors[0][1], filename) @@ -406,7 +410,8 @@ def test_on_error(self): self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode) self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode) - shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror) + with self.assertWarns(DeprecationWarning): + shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror) # Test whether onerror has actually been called. self.assertEqual(self.errorState, 3, "Expected call to onerror function did not happen.") @@ -532,7 +537,8 @@ def onexc(*args): self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode) self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode) - shutil.rmtree(TESTFN, onerror=onerror, onexc=onexc) + with self.assertWarns(DeprecationWarning): + shutil.rmtree(TESTFN, onerror=onerror, onexc=onexc) self.assertTrue(onexc_called) self.assertFalse(onerror_called) From 05078fdbe35ce2f3e6a808a12919ed9688633be6 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Tue, 21 Mar 2023 19:46:24 +0300 Subject: [PATCH 166/280] gh-102595: Document `PyObject_Format` c-api function (GH-102596) Def: https://github.com/python/cpython/blame/5ffdaf748d98da6065158534720f1996a45a0072/Include/abstract.h#L389 --- Doc/c-api/object.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index 84c72e7e108b64..0a12bb9e8c54f0 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -179,6 +179,15 @@ Object Protocol If *o1* and *o2* are the same object, :c:func:`PyObject_RichCompareBool` will always return ``1`` for :const:`Py_EQ` and ``0`` for :const:`Py_NE`. +.. c:function:: PyObject* PyObject_Format(PyObject *obj, PyObject *format_spec) + + Format *obj* using *format_spec*. This is equivalent to the Python + expression ``format(obj, format_spec)``. + + *format_spec* may be ``NULL``. In this case the call is equivalent + to ``format(obj)``. + Returns the formatted string on success, ``NULL`` on failure. + .. c:function:: PyObject* PyObject_Repr(PyObject *o) .. index:: builtin: repr From 8eb9d2ff6bb77f8455ca8585888d0e187fb66afd Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 21 Mar 2023 10:49:12 -0600 Subject: [PATCH 167/280] gh-98608: Stop Treating All Errors from _Py_NewInterpreterFromConfig() as Fatal (gh-102657) Prior to this change, errors in _Py_NewInterpreterFromConfig() were always fatal. Instead, callers should be able to handle such errors and keep going. That's what this change supports. (This was an oversight in the original implementation of _Py_NewInterpreterFromConfig().) Note that the existing [fatal] behavior of the public Py_NewInterpreter() is preserved. https://github.com/python/cpython/issues/98608 --- Include/cpython/initconfig.h | 1 + Include/cpython/pylifecycle.h | 5 +++-- Include/internal/pycore_initconfig.h | 2 -- Modules/_testcapimodule.c | 8 ++++++-- Modules/_xxsubinterpretersmodule.c | 9 +++++++-- Python/pylifecycle.c | 19 ++++++++++--------- 6 files changed, 27 insertions(+), 17 deletions(-) diff --git a/Include/cpython/initconfig.h b/Include/cpython/initconfig.h index a070fa9ff3a038..8bc681b1a93f5c 100644 --- a/Include/cpython/initconfig.h +++ b/Include/cpython/initconfig.h @@ -25,6 +25,7 @@ PyAPI_FUNC(PyStatus) PyStatus_Exit(int exitcode); PyAPI_FUNC(int) PyStatus_IsError(PyStatus err); PyAPI_FUNC(int) PyStatus_IsExit(PyStatus err); PyAPI_FUNC(int) PyStatus_Exception(PyStatus err); +PyAPI_FUNC(PyObject *) _PyErr_SetFromPyStatus(PyStatus status); /* --- PyWideStringList ------------------------------------------------ */ diff --git a/Include/cpython/pylifecycle.h b/Include/cpython/pylifecycle.h index e1f83acbffc360..821b169d7a1759 100644 --- a/Include/cpython/pylifecycle.h +++ b/Include/cpython/pylifecycle.h @@ -62,5 +62,6 @@ PyAPI_FUNC(int) _Py_CoerceLegacyLocale(int warn); PyAPI_FUNC(int) _Py_LegacyLocaleDetected(int warn); PyAPI_FUNC(char *) _Py_SetLocaleFromEnv(int category); -PyAPI_FUNC(PyThreadState *) _Py_NewInterpreterFromConfig( - const _PyInterpreterConfig *); +PyAPI_FUNC(PyStatus) _Py_NewInterpreterFromConfig( + PyThreadState **tstate_p, + const _PyInterpreterConfig *config); diff --git a/Include/internal/pycore_initconfig.h b/Include/internal/pycore_initconfig.h index 69f88d7d1d46b8..4cbd14a61d4545 100644 --- a/Include/internal/pycore_initconfig.h +++ b/Include/internal/pycore_initconfig.h @@ -44,8 +44,6 @@ struct pyruntimestate; #define _PyStatus_UPDATE_FUNC(err) \ do { (err).func = _PyStatus_GET_FUNC(); } while (0) -PyObject* _PyErr_SetFromPyStatus(PyStatus status); - /* --- PyWideStringList ------------------------------------------------ */ #define _PyWideStringList_INIT (PyWideStringList){.length = 0, .items = NULL} diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index f45d0312e94411..e2ebab5c5b4849 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1538,15 +1538,19 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs) .allow_daemon_threads = allow_daemon_threads, .check_multi_interp_extensions = check_multi_interp_extensions, }; - substate = _Py_NewInterpreterFromConfig(&config); - if (substate == NULL) { + PyStatus status = _Py_NewInterpreterFromConfig(&substate, &config); + if (PyStatus_Exception(status)) { /* Since no new thread state was created, there is no exception to propagate; raise a fresh one after swapping in the old thread state. */ PyThreadState_Swap(mainstate); + _PyErr_SetFromPyStatus(status); + PyObject *exc = PyErr_GetRaisedException(); PyErr_SetString(PyExc_RuntimeError, "sub-interpreter creation failed"); + _PyErr_ChainExceptions1(exc); return NULL; } + assert(substate != NULL); r = PyRun_SimpleStringFlags(code, &cflags); Py_EndInterpreter(substate); diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 76fb87fa3a34e1..9648f080cd756c 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -526,15 +526,20 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds) ? (_PyInterpreterConfig)_PyInterpreterConfig_INIT : (_PyInterpreterConfig)_PyInterpreterConfig_LEGACY_INIT; // XXX Possible GILState issues? - PyThreadState *tstate = _Py_NewInterpreterFromConfig(&config); + PyThreadState *tstate = NULL; + PyStatus status = _Py_NewInterpreterFromConfig(&tstate, &config); PyThreadState_Swap(save_tstate); - if (tstate == NULL) { + if (PyStatus_Exception(status)) { /* Since no new thread state was created, there is no exception to propagate; raise a fresh one after swapping in the old thread state. */ + _PyErr_SetFromPyStatus(status); + PyObject *exc = PyErr_GetRaisedException(); PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed"); + _PyErr_ChainExceptions1(exc); return NULL; } + assert(tstate != NULL); PyInterpreterState *interp = PyThreadState_GetInterpreter(tstate); PyObject *idobj = _PyInterpreterState_GetIDObject(interp); if (idobj == NULL) { diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 731f340001b4e0..8b58a14c693f22 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2065,22 +2065,23 @@ new_interpreter(PyThreadState **tstate_p, const _PyInterpreterConfig *config) return status; } -PyThreadState * -_Py_NewInterpreterFromConfig(const _PyInterpreterConfig *config) +PyStatus +_Py_NewInterpreterFromConfig(PyThreadState **tstate_p, + const _PyInterpreterConfig *config) { - PyThreadState *tstate = NULL; - PyStatus status = new_interpreter(&tstate, config); - if (_PyStatus_EXCEPTION(status)) { - Py_ExitStatusException(status); - } - return tstate; + return new_interpreter(tstate_p, config); } PyThreadState * Py_NewInterpreter(void) { + PyThreadState *tstate = NULL; const _PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT; - return _Py_NewInterpreterFromConfig(&config); + PyStatus status = _Py_NewInterpreterFromConfig(&tstate, &config); + if (_PyStatus_EXCEPTION(status)) { + Py_ExitStatusException(status); + } + return tstate; } /* Delete an interpreter and its last thread. This requires that the From 70e542b3f0136046e6e4bc31cf777555e85db858 Mon Sep 17 00:00:00 2001 From: wim glenn Date: Tue, 21 Mar 2023 12:06:18 -0500 Subject: [PATCH 168/280] gh-102876: remove superfluous parens from itertools.batched recipe (GH-102877) remove superfluous parens from itertools.batched recipe --- Doc/library/itertools.rst | 2 +- Lib/test/test_itertools.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 78f64ea67e2542..38bc369d410dda 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -195,7 +195,7 @@ loops that truncate the stream. if n < 1: raise ValueError('n must be at least one') it = iter(iterable) - while (batch := tuple(islice(it, n))): + while batch := tuple(islice(it, n)): yield batch .. versionadded:: 3.12 diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py index 7014bc97100cb4..9fe559d4b7eed5 100644 --- a/Lib/test/test_itertools.py +++ b/Lib/test/test_itertools.py @@ -1846,7 +1846,7 @@ def batched_recipe(iterable, n): if n < 1: raise ValueError('n must be at least one') it = iter(iterable) - while (batch := tuple(islice(it, n))): + while batch := tuple(islice(it, n)): yield batch for iterable, n in product( From 4ae6f699179082e632732a038a0e23a9122597d8 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 21 Mar 2023 11:46:09 -0600 Subject: [PATCH 169/280] gh-102304: Move the Total Refcount to PyInterpreterState (gh-102545) Moving it valuable with a per-interpreter GIL. However, it is also useful without one, since it allows us to identify refleaks within a single interpreter or where references are escaping an interpreter. This becomes more important as we move the obmalloc state to PyInterpreterState. https://github.com/python/cpython/issues/102304 --- Include/cpython/object.h | 1 + Include/internal/pycore_interp.h | 2 + Include/internal/pycore_object.h | 16 +++--- Include/internal/pycore_object_state.h | 8 +++ Objects/bytesobject.c | 2 +- Objects/dictobject.c | 10 ++-- Objects/object.c | 79 +++++++++++++++++++------- Objects/structseq.c | 2 +- Objects/tupleobject.c | 2 +- Objects/typeobject.c | 18 +++++- Python/pylifecycle.c | 5 ++ Python/pystate.c | 10 +++- Python/sysmodule.c | 2 + 13 files changed, 117 insertions(+), 40 deletions(-) diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 0438612edd1dfe..859ffb91e223dc 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -15,6 +15,7 @@ PyAPI_FUNC(void) _Py_ForgetReference(PyObject *); PyAPI_FUNC(Py_ssize_t) _Py_GetGlobalRefTotal(void); # define _Py_GetRefTotal() _Py_GetGlobalRefTotal() PyAPI_FUNC(Py_ssize_t) _Py_GetLegacyRefTotal(void); +PyAPI_FUNC(Py_ssize_t) _PyInterpreterState_GetRefTotal(PyInterpreterState *); #endif diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index fd7b92e86aa120..fcdf8d2f2c8e15 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -25,6 +25,7 @@ extern "C" { #include "pycore_import.h" // struct _import_state #include "pycore_list.h" // struct _Py_list_state #include "pycore_global_objects.h" // struct _Py_interp_static_objects +#include "pycore_object_state.h" // struct _py_object_state #include "pycore_tuple.h" // struct _Py_tuple_state #include "pycore_typeobject.h" // struct type_cache #include "pycore_unicodeobject.h" // struct _Py_unicode_state @@ -138,6 +139,7 @@ struct _is { // One bit is set for each non-NULL entry in code_watchers uint8_t active_code_watchers; + struct _py_object_state object_state; struct _Py_unicode_state unicode; struct _Py_float_state float_state; struct _Py_long_state long_state; diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index b985eff8a8a08b..d6bbafd4b6cccc 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -43,18 +43,19 @@ PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalRefcountErrorFunc( built against the pre-3.12 stable ABI. */ PyAPI_DATA(Py_ssize_t) _Py_RefTotal; -extern void _Py_AddRefTotal(Py_ssize_t); -extern void _Py_IncRefTotal(void); -extern void _Py_DecRefTotal(void); +extern void _Py_AddRefTotal(PyInterpreterState *, Py_ssize_t); +extern void _Py_IncRefTotal(PyInterpreterState *); +extern void _Py_DecRefTotal(PyInterpreterState *); -# define _Py_DEC_REFTOTAL() _PyRuntime.object_state.reftotal-- +# define _Py_DEC_REFTOTAL(interp) \ + interp->object_state.reftotal-- #endif // Increment reference count by n static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n) { #ifdef Py_REF_DEBUG - _Py_AddRefTotal(n); + _Py_AddRefTotal(_PyInterpreterState_GET(), n); #endif op->ob_refcnt += n; } @@ -65,7 +66,7 @@ _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct) { _Py_DECREF_STAT_INC(); #ifdef Py_REF_DEBUG - _Py_DEC_REFTOTAL(); + _Py_DEC_REFTOTAL(_PyInterpreterState_GET()); #endif if (--op->ob_refcnt != 0) { assert(op->ob_refcnt > 0); @@ -83,7 +84,7 @@ _Py_DECREF_NO_DEALLOC(PyObject *op) { _Py_DECREF_STAT_INC(); #ifdef Py_REF_DEBUG - _Py_DEC_REFTOTAL(); + _Py_DEC_REFTOTAL(_PyInterpreterState_GET()); #endif op->ob_refcnt--; #ifdef Py_DEBUG @@ -226,6 +227,7 @@ static inline void _PyObject_GC_UNTRACK( #endif #ifdef Py_REF_DEBUG +extern void _PyInterpreterState_FinalizeRefTotal(PyInterpreterState *); extern void _Py_FinalizeRefTotal(_PyRuntimeState *); extern void _PyDebug_PrintTotalRefs(void); #endif diff --git a/Include/internal/pycore_object_state.h b/Include/internal/pycore_object_state.h index 4e5862a11eddc5..94005d77881432 100644 --- a/Include/internal/pycore_object_state.h +++ b/Include/internal/pycore_object_state.h @@ -9,6 +9,14 @@ extern "C" { #endif struct _py_object_runtime_state { +#ifdef Py_REF_DEBUG + Py_ssize_t interpreter_leaks; +#else + int _not_used; +#endif +}; + +struct _py_object_state { #ifdef Py_REF_DEBUG Py_ssize_t reftotal; #else diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 687a654bdae137..2d8dab6f378006 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -3067,7 +3067,7 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize) PyObject_Realloc(v, PyBytesObject_SIZE + newsize); if (*pv == NULL) { #ifdef Py_REF_DEBUG - _Py_DecRefTotal(); + _Py_DecRefTotal(_PyInterpreterState_GET()); #endif PyObject_Free(v); PyErr_NoMemory(); diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 53f9a380346a0d..2ef520044340ee 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -304,7 +304,7 @@ static inline void dictkeys_incref(PyDictKeysObject *dk) { #ifdef Py_REF_DEBUG - _Py_IncRefTotal(); + _Py_IncRefTotal(_PyInterpreterState_GET()); #endif dk->dk_refcnt++; } @@ -314,7 +314,7 @@ dictkeys_decref(PyInterpreterState *interp, PyDictKeysObject *dk) { assert(dk->dk_refcnt > 0); #ifdef Py_REF_DEBUG - _Py_DecRefTotal(); + _Py_DecRefTotal(_PyInterpreterState_GET()); #endif if (--dk->dk_refcnt == 0) { free_keys_object(interp, dk); @@ -634,7 +634,7 @@ new_keys_object(PyInterpreterState *interp, uint8_t log2_size, bool unicode) } } #ifdef Py_REF_DEBUG - _Py_IncRefTotal(); + _Py_IncRefTotal(_PyInterpreterState_GET()); #endif dk->dk_refcnt = 1; dk->dk_log2_size = log2_size; @@ -824,7 +824,7 @@ clone_combined_dict_keys(PyDictObject *orig) we have it now; calling dictkeys_incref would be an error as keys->dk_refcnt is already set to 1 (after memcpy). */ #ifdef Py_REF_DEBUG - _Py_IncRefTotal(); + _Py_IncRefTotal(_PyInterpreterState_GET()); #endif return keys; } @@ -1530,7 +1530,7 @@ dictresize(PyInterpreterState *interp, PyDictObject *mp, // We can not use free_keys_object here because key's reference // are moved already. #ifdef Py_REF_DEBUG - _Py_DecRefTotal(); + _Py_DecRefTotal(_PyInterpreterState_GET()); #endif if (oldkeys == Py_EMPTY_KEYS) { oldkeys->dk_refcnt--; diff --git a/Objects/object.c b/Objects/object.c index 95f7c966a414de..9dd5eb998217f6 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -66,25 +66,25 @@ get_legacy_reftotal(void) #ifdef Py_REF_DEBUG -# define REFTOTAL(runtime) \ - (runtime)->object_state.reftotal +# define REFTOTAL(interp) \ + interp->object_state.reftotal static inline void -reftotal_increment(_PyRuntimeState *runtime) +reftotal_increment(PyInterpreterState *interp) { - REFTOTAL(runtime)++; + REFTOTAL(interp)++; } static inline void -reftotal_decrement(_PyRuntimeState *runtime) +reftotal_decrement(PyInterpreterState *interp) { - REFTOTAL(runtime)--; + REFTOTAL(interp)--; } static inline void -reftotal_add(_PyRuntimeState *runtime, Py_ssize_t n) +reftotal_add(PyInterpreterState *interp, Py_ssize_t n) { - REFTOTAL(runtime) += n; + REFTOTAL(interp) += n; } static inline Py_ssize_t get_global_reftotal(_PyRuntimeState *); @@ -99,15 +99,43 @@ void _Py_FinalizeRefTotal(_PyRuntimeState *runtime) { last_final_reftotal = get_global_reftotal(runtime); - REFTOTAL(runtime) = 0; + runtime->object_state.interpreter_leaks = 0; +} + +void +_PyInterpreterState_FinalizeRefTotal(PyInterpreterState *interp) +{ + interp->runtime->object_state.interpreter_leaks += REFTOTAL(interp); + REFTOTAL(interp) = 0; +} + +static inline Py_ssize_t +get_reftotal(PyInterpreterState *interp) +{ + /* For a single interpreter, we ignore the legacy _Py_RefTotal, + since we can't determine which interpreter updated it. */ + return REFTOTAL(interp); } static inline Py_ssize_t get_global_reftotal(_PyRuntimeState *runtime) { - /* For an update from _Py_RefTotal first. */ - Py_ssize_t legacy = get_legacy_reftotal(); - return REFTOTAL(runtime) + legacy + last_final_reftotal; + Py_ssize_t total = 0; + + /* Add up the total from each interpreter. */ + HEAD_LOCK(&_PyRuntime); + PyInterpreterState *interp = PyInterpreterState_Head(); + for (; interp != NULL; interp = PyInterpreterState_Next(interp)) { + total += REFTOTAL(interp); + } + HEAD_UNLOCK(&_PyRuntime); + + /* Add in the updated value from the legacy _Py_RefTotal. */ + total += get_legacy_reftotal(); + total += last_final_reftotal; + total += runtime->object_state.interpreter_leaks; + + return total; } #undef REFTOTAL @@ -118,7 +146,8 @@ _PyDebug_PrintTotalRefs(void) { fprintf(stderr, "[%zd refs, %zd blocks]\n", get_global_reftotal(runtime), _Py_GetAllocatedBlocks()); - /* It may be helpful to also print the "legacy" reftotal separately. */ + /* It may be helpful to also print the "legacy" reftotal separately. + Likewise for the total for each interpreter. */ } #endif /* Py_REF_DEBUG */ @@ -177,32 +206,32 @@ _Py_NegativeRefcount(const char *filename, int lineno, PyObject *op) void _Py_IncRefTotal_DO_NOT_USE_THIS(void) { - reftotal_increment(&_PyRuntime); + reftotal_increment(_PyInterpreterState_GET()); } /* This is used strictly by Py_DECREF(). */ void _Py_DecRefTotal_DO_NOT_USE_THIS(void) { - reftotal_decrement(&_PyRuntime); + reftotal_decrement(_PyInterpreterState_GET()); } void -_Py_IncRefTotal(void) +_Py_IncRefTotal(PyInterpreterState *interp) { - reftotal_increment(&_PyRuntime); + reftotal_increment(interp); } void -_Py_DecRefTotal(void) +_Py_DecRefTotal(PyInterpreterState *interp) { - reftotal_decrement(&_PyRuntime); + reftotal_decrement(interp); } void -_Py_AddRefTotal(Py_ssize_t n) +_Py_AddRefTotal(PyInterpreterState *interp, Py_ssize_t n) { - reftotal_add(&_PyRuntime, n); + reftotal_add(interp, n); } /* This includes the legacy total @@ -219,6 +248,12 @@ _Py_GetLegacyRefTotal(void) return get_legacy_reftotal(); } +Py_ssize_t +_PyInterpreterState_GetRefTotal(PyInterpreterState *interp) +{ + return get_reftotal(interp); +} + #endif /* Py_REF_DEBUG */ void @@ -2128,7 +2163,7 @@ void _Py_NewReference(PyObject *op) { #ifdef Py_REF_DEBUG - reftotal_increment(&_PyRuntime); + reftotal_increment(_PyInterpreterState_GET()); #endif new_reference(op); } diff --git a/Objects/structseq.c b/Objects/structseq.c index c20962ecd82563..2a5343815866d3 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -592,7 +592,7 @@ _PyStructSequence_FiniType(PyTypeObject *type) // Don't use Py_DECREF(): static type must not be deallocated Py_SET_REFCNT(type, 0); #ifdef Py_REF_DEBUG - _Py_DecRefTotal(); + _Py_DecRefTotal(_PyInterpreterState_GET()); #endif // Make sure that _PyStructSequence_InitType() will initialize diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 59c0251639d3dd..61fab4078d66ba 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -944,7 +944,7 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize) if (sv == NULL) { *pv = NULL; #ifdef Py_REF_DEBUG - _Py_DecRefTotal(); + _Py_DecRefTotal(_PyInterpreterState_GET()); #endif PyObject_GC_Del(v); return -1; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f0654c239f6635..a37f97c71ec763 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -317,11 +317,27 @@ _PyType_InitCache(PyInterpreterState *interp) entry->version = 0; // Set to None so _PyType_Lookup() can use Py_SETREF(), // rather than using slower Py_XSETREF(). - entry->name = Py_NewRef(Py_None); + // (See _PyType_FixCacheRefcounts() about the refcount.) + entry->name = Py_None; entry->value = NULL; } } +// This is the temporary fix used by pycore_create_interpreter(), +// in pylifecycle.c. _PyType_InitCache() is called before the GIL +// has been created (for the main interpreter) and without the +// "current" thread state set. This causes crashes when the +// reftotal is updated, so we don't modify the refcount in +// _PyType_InitCache(), and instead do it later by calling +// _PyType_FixCacheRefcounts(). +// XXX This workaround should be removed once we have immortal +// objects (PEP 683). +void +_PyType_FixCacheRefcounts(void) +{ + _Py_RefcntAdd(Py_None, (1 << MCACHE_SIZE_EXP)); +} + static unsigned int _PyType_ClearCache(PyInterpreterState *interp) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 8b58a14c693f22..0d546d52087e10 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -802,6 +802,11 @@ pycore_interp_init(PyThreadState *tstate) PyStatus status; PyObject *sysmod = NULL; + // This is a temporary fix until we have immortal objects. + // (See _PyType_InitCache() in typeobject.c.) + extern void _PyType_FixCacheRefcounts(void); + _PyType_FixCacheRefcounts(); + // Create singletons before the first PyType_Ready() call, since // PyType_Ready() uses singletons like the Unicode empty string (tp_doc) // and the empty tuple singletons (tp_bases). diff --git a/Python/pystate.c b/Python/pystate.c index 60adb54685ce68..b17efdbefd124c 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -483,8 +483,8 @@ void _PyRuntimeState_Fini(_PyRuntimeState *runtime) { #ifdef Py_REF_DEBUG - /* The reftotal is cleared by _Py_FinalizeRefTotal(). */ - assert(runtime->object_state.reftotal == 0); + /* The count is cleared by _Py_FinalizeRefTotal(). */ + assert(runtime->object_state.interpreter_leaks == 0); #endif if (gilstate_tss_initialized(runtime)) { @@ -904,6 +904,12 @@ PyInterpreterState_Delete(PyInterpreterState *interp) _PyEval_FiniState(&interp->ceval); +#ifdef Py_REF_DEBUG + // XXX This call should be done at the end of clear_interpreter(), + // but currently some objects get decref'ed after that. + _PyInterpreterState_FinalizeRefTotal(interp); +#endif + HEAD_LOCK(runtime); PyInterpreterState **p; for (p = &interpreters->head; ; p = &(*p)->next) { diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 20761738b527cb..4afb0f1d0b5ed2 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1854,6 +1854,8 @@ static Py_ssize_t sys_gettotalrefcount_impl(PyObject *module) /*[clinic end generated code: output=4103886cf17c25bc input=53b744faa5d2e4f6]*/ { + /* It may make sense to return the total for the current interpreter + or have a second function that does so. */ return _Py_GetGlobalRefTotal(); } From 711256c8be811f8d39c349fab88d8e809d1ae3b7 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 21 Mar 2023 13:21:57 -0500 Subject: [PATCH 170/280] Tweak polynomial itertool recipes (GH-102880) --- Doc/library/itertools.rst | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 38bc369d410dda..5daadfd3759f4b 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -866,6 +866,17 @@ which incur interpreter overhead. window.append(x) yield math.sumprod(kernel, window) + def polynomial_from_roots(roots): + """Compute a polynomial's coefficients from its roots. + + (x - 5) (x + 4) (x - 3) expands to: x³ -4x² -17x + 60 + """ + # polynomial_from_roots([5, -4, 3]) --> [1, -4, -17, 60] + expansion = [1] + for r in roots: + expansion = convolve(expansion, (1, -r)) + return list(expansion) + def polynomial_eval(coefficients, x): """Evaluate a polynomial at a specific value. @@ -876,20 +887,8 @@ which incur interpreter overhead. n = len(coefficients) if n == 0: return x * 0 # coerce zero to the type of x - powers = map(pow, repeat(x), range(n)) - return math.sumprod(reversed(coefficients), powers) - - def polynomial_from_roots(roots): - """Compute a polynomial's coefficients from its roots. - - (x - 5) (x + 4) (x - 3) expands to: x³ -4x² -17x + 60 - """ - # polynomial_from_roots([5, -4, 3]) --> [1, -4, -17, 60] - roots = list(map(operator.neg, roots)) - return [ - sum(map(math.prod, combinations(roots, k))) - for k in range(len(roots) + 1) - ] + powers = map(pow, repeat(x), reversed(range(n))) + return math.sumprod(coefficients, powers) def iter_index(iterable, value, start=0): "Return indices where a value occurs in a sequence or iterable." From ac24ffadfd7cffcf4ee1062b020a0b09b6d16929 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 21 Mar 2023 12:47:55 -0600 Subject: [PATCH 171/280] gh-98608: Fix Failure-handling in new_interpreter() (gh-102658) The error-handling code in new_interpreter() has been broken for a while. We hadn't noticed because those code mostly doesn't fail. (I noticed while working on gh-101660.) The problem is that we try to clear/delete the newly-created thread/interpreter using itself, which just failed. The solution is to switch back to the calling thread state first. https://github.com/python/cpython/issues/98608 --- Python/pylifecycle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 0d546d52087e10..d0e85519d23464 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -2062,10 +2062,10 @@ new_interpreter(PyThreadState **tstate_p, const _PyInterpreterConfig *config) /* Oops, it didn't work. Undo it all. */ PyErr_PrintEx(0); + PyThreadState_Swap(save_tstate); PyThreadState_Clear(tstate); PyThreadState_Delete(tstate); PyInterpreterState_Delete(interp); - PyThreadState_Swap(save_tstate); return status; } From 67394631752571bfc9fc7695b8cef166d31ace26 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Tue, 21 Mar 2023 19:13:49 +0000 Subject: [PATCH 172/280] gh-102860: improve performance of compiler's instr_sequence_to_cfg (#102861) --- Python/compile.c | 50 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 29e55b8b30c56b..99296050445f50 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -595,17 +595,52 @@ static int instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { memset(g, 0, sizeof(cfg_builder)); RETURN_IF_ERROR(cfg_builder_init(g)); - /* Note: there can be more than one label for the same offset */ + + /* There can be more than one label for the same offset. The + * offset2lbl maping selects one of them which we use consistently. + */ + + int *offset2lbl = PyMem_Malloc(seq->s_used * sizeof(int)); + if (offset2lbl == NULL) { + PyErr_NoMemory(); + return ERROR; + } for (int i = 0; i < seq->s_used; i++) { - for (int j=0; j < seq->s_labelmap_size; j++) { - if (seq->s_labelmap[j] == i) { - jump_target_label lbl = {j}; - RETURN_IF_ERROR(cfg_builder_use_label(g, lbl)); + offset2lbl[i] = -1; + } + for (int lbl=0; lbl < seq->s_labelmap_size; lbl++) { + int offset = seq->s_labelmap[lbl]; + if (offset >= 0) { + assert(offset < seq->s_used); + offset2lbl[offset] = lbl; + } + } + + for (int i = 0; i < seq->s_used; i++) { + int lbl = offset2lbl[i]; + if (lbl >= 0) { + assert (lbl < seq->s_labelmap_size); + jump_target_label lbl_ = {lbl}; + if (cfg_builder_use_label(g, lbl_) < 0) { + goto error; } } instruction *instr = &seq->s_instrs[i]; - RETURN_IF_ERROR(cfg_builder_addop(g, instr->i_opcode, instr->i_oparg, instr->i_loc)); + int opcode = instr->i_opcode; + int oparg = instr->i_oparg; + if (HAS_TARGET(opcode)) { + int offset = seq->s_labelmap[oparg]; + assert(offset >= 0 && offset < seq->s_used); + int lbl = offset2lbl[offset]; + assert(lbl >= 0 && lbl < seq->s_labelmap_size); + oparg = lbl; + } + if (cfg_builder_addop(g, opcode, oparg, instr->i_loc) < 0) { + goto error; + } } + PyMem_Free(offset2lbl); + int nblocks = 0; for (basicblock *b = g->g_block_list; b != NULL; b = b->b_list) { nblocks++; @@ -615,6 +650,9 @@ instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) { return ERROR; } return SUCCESS; +error: + PyMem_Free(offset2lbl); + return ERROR; } From 7de1d793b7567fadd8425c976300f3d1e8047145 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 21 Mar 2023 14:01:38 -0600 Subject: [PATCH 173/280] gh-94673: Isolate the _io module to Each Interpreter (gh-102663) Aside from sys and builtins, _io is the only core builtin module that hasn't been ported to multi-phase init. We may do so later (e.g. gh-101948), but in the meantime we must at least take care of the module's static types properly. (This came up while working on gh-101660.) https://github.com/python/cpython/issues/94673 --- Modules/_io/_iomodule.c | 40 ++++++++++++++++++++++++++++++++-------- Python/pylifecycle.c | 12 ++++++++---- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c index 1506755427fc0d..5644cc05c45800 100644 --- a/Modules/_io/_iomodule.c +++ b/Modules/_io/_iomodule.c @@ -11,6 +11,7 @@ #include "Python.h" #include "_iomodule.h" #include "pycore_pystate.h" // _PyInterpreterState_GET() +#include "pycore_initconfig.h" // _PyStatus_OK() #ifdef HAVE_SYS_TYPES_H #include @@ -666,12 +667,40 @@ static PyTypeObject* static_types[] = { }; +PyStatus +_PyIO_InitTypes(PyInterpreterState *interp) +{ + if (!_Py_IsMainInterpreter(interp)) { + return _PyStatus_OK(); + } + + // Set type base classes +#ifdef HAVE_WINDOWS_CONSOLE_IO + PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type; +#endif + + for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) { + PyTypeObject *type = static_types[i]; + if (_PyStaticType_InitBuiltin(type) < 0) { + return _PyStatus_ERR("Can't initialize builtin type"); + } + } + + return _PyStatus_OK(); +} + void -_PyIO_Fini(void) +_PyIO_FiniTypes(PyInterpreterState *interp) { + if (!_Py_IsMainInterpreter(interp)) { + return; + } + + // Deallocate types in the reverse order to deallocate subclasses before + // their base classes. for (Py_ssize_t i=Py_ARRAY_LENGTH(static_types) - 1; i >= 0; i--) { - PyTypeObject *exc = static_types[i]; - _PyStaticType_Dealloc(exc); + PyTypeObject *type = static_types[i]; + _PyStaticType_Dealloc(type); } } @@ -717,11 +746,6 @@ PyInit__io(void) goto fail; } - // Set type base classes -#ifdef HAVE_WINDOWS_CONSOLE_IO - PyWindowsConsoleIO_Type.tp_base = &PyRawIOBase_Type; -#endif - // Add types for (size_t i=0; i < Py_ARRAY_LENGTH(static_types); i++) { PyTypeObject *type = static_types[i]; diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index d0e85519d23464..8110d94ba17526 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -31,7 +31,8 @@ #include "pycore_unicodeobject.h" // _PyUnicode_InitTypes() #include "opcode.h" -extern void _PyIO_Fini(void); +extern PyStatus _PyIO_InitTypes(PyInterpreterState *interp); +extern void _PyIO_FiniTypes(PyInterpreterState *interp); #include // setlocale() #include // getenv() @@ -697,6 +698,11 @@ pycore_init_types(PyInterpreterState *interp) return _PyStatus_ERR("failed to initialize an exception type"); } + status = _PyIO_InitTypes(interp); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + status = _PyExc_InitGlobalObjects(interp); if (_PyStatus_EXCEPTION(status)) { return status; @@ -1700,9 +1706,7 @@ finalize_interp_clear(PyThreadState *tstate) /* Clear interpreter state and all thread states */ _PyInterpreterState_Clear(tstate); - if (is_main_interp) { - _PyIO_Fini(); - } + _PyIO_FiniTypes(tstate->interp); /* Clear all loghooks */ /* Both _PySys_Audit function and users still need PyObject, such as tuple. From 43f13b998d4b6542a221b46cd273385be6384eea Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Tue, 21 Mar 2023 21:36:31 +0000 Subject: [PATCH 174/280] gh-102406: replace exception chaining by PEP-678 notes in codecs (#102407) --- Include/cpython/pyerrors.h | 18 --- Lib/test/test_codecs.py | 106 +++++++---------- ...-03-03-23-21-16.gh-issue-102406.XLqYO3.rst | 1 + Objects/exceptions.c | 110 ------------------ Python/codecs.c | 35 +++--- 5 files changed, 64 insertions(+), 206 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-03-03-23-21-16.gh-issue-102406.XLqYO3.rst diff --git a/Include/cpython/pyerrors.h b/Include/cpython/pyerrors.h index d0300f6ee56a25..65bdc942f5067a 100644 --- a/Include/cpython/pyerrors.h +++ b/Include/cpython/pyerrors.h @@ -116,24 +116,6 @@ PyAPI_FUNC(int) _PyException_AddNote( PyObject *exc, PyObject *note); -/* Helper that attempts to replace the current exception with one of the - * same type but with a prefix added to the exception text. The resulting - * exception description looks like: - * - * prefix (exc_type: original_exc_str) - * - * Only some exceptions can be safely replaced. If the function determines - * it isn't safe to perform the replacement, it will leave the original - * unmodified exception in place. - * - * Returns a borrowed reference to the new exception (if any), NULL if the - * existing exception was left in place. - */ -PyAPI_FUNC(PyObject *) _PyErr_TrySetFromCause( - const char *prefix_format, /* ASCII-encoded string */ - ... - ); - /* In signalmodule.c */ int PySignal_SetWakeupFd(int fd); diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index e3add0c1ee926c..376175f90f63eb 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -2819,24 +2819,19 @@ def test_binary_to_text_denylists_text_transforms(self): self.assertIsNone(failure.exception.__cause__) @unittest.skipUnless(zlib, "Requires zlib support") - def test_custom_zlib_error_is_wrapped(self): + def test_custom_zlib_error_is_noted(self): # Check zlib codec gives a good error for malformed input - msg = "^decoding with 'zlib_codec' codec failed" - with self.assertRaisesRegex(Exception, msg) as failure: + msg = "decoding with 'zlib_codec' codec failed" + with self.assertRaises(Exception) as failure: codecs.decode(b"hello", "zlib_codec") - self.assertIsInstance(failure.exception.__cause__, - type(failure.exception)) + self.assertEqual(msg, failure.exception.__notes__[0]) - def test_custom_hex_error_is_wrapped(self): + def test_custom_hex_error_is_noted(self): # Check hex codec gives a good error for malformed input - msg = "^decoding with 'hex_codec' codec failed" - with self.assertRaisesRegex(Exception, msg) as failure: + msg = "decoding with 'hex_codec' codec failed" + with self.assertRaises(Exception) as failure: codecs.decode(b"hello", "hex_codec") - self.assertIsInstance(failure.exception.__cause__, - type(failure.exception)) - - # Unfortunately, the bz2 module throws OSError, which the codec - # machinery currently can't wrap :( + self.assertEqual(msg, failure.exception.__notes__[0]) # Ensure codec aliases from http://bugs.python.org/issue7475 work def test_aliases(self): @@ -2860,11 +2855,8 @@ def test_uu_invalid(self): self.assertRaises(ValueError, codecs.decode, b"", "uu-codec") -# The codec system tries to wrap exceptions in order to ensure the error -# mentions the operation being performed and the codec involved. We -# currently *only* want this to happen for relatively stateless -# exceptions, where the only significant information they contain is their -# type and a single str argument. +# The codec system tries to add notes to exceptions in order to ensure +# the error mentions the operation being performed and the codec involved. # Use a local codec registry to avoid appearing to leak objects when # registering multiple search functions @@ -2874,10 +2866,10 @@ def _get_test_codec(codec_name): return _TEST_CODECS.get(codec_name) -class ExceptionChainingTest(unittest.TestCase): +class ExceptionNotesTest(unittest.TestCase): def setUp(self): - self.codec_name = 'exception_chaining_test' + self.codec_name = 'exception_notes_test' codecs.register(_get_test_codec) self.addCleanup(codecs.unregister, _get_test_codec) @@ -2901,91 +2893,77 @@ def set_codec(self, encode, decode): _TEST_CODECS[self.codec_name] = codec_info @contextlib.contextmanager - def assertWrapped(self, operation, exc_type, msg): - full_msg = r"{} with {!r} codec failed \({}: {}\)".format( - operation, self.codec_name, exc_type.__name__, msg) - with self.assertRaisesRegex(exc_type, full_msg) as caught: + def assertNoted(self, operation, exc_type, msg): + full_msg = r"{} with {!r} codec failed".format( + operation, self.codec_name) + with self.assertRaises(exc_type) as caught: yield caught - self.assertIsInstance(caught.exception.__cause__, exc_type) - self.assertIsNotNone(caught.exception.__cause__.__traceback__) + self.assertIn(full_msg, caught.exception.__notes__[0]) + caught.exception.__notes__.clear() def raise_obj(self, *args, **kwds): # Helper to dynamically change the object raised by a test codec raise self.obj_to_raise - def check_wrapped(self, obj_to_raise, msg, exc_type=RuntimeError): + def check_note(self, obj_to_raise, msg, exc_type=RuntimeError): self.obj_to_raise = obj_to_raise self.set_codec(self.raise_obj, self.raise_obj) - with self.assertWrapped("encoding", exc_type, msg): + with self.assertNoted("encoding", exc_type, msg): "str_input".encode(self.codec_name) - with self.assertWrapped("encoding", exc_type, msg): + with self.assertNoted("encoding", exc_type, msg): codecs.encode("str_input", self.codec_name) - with self.assertWrapped("decoding", exc_type, msg): + with self.assertNoted("decoding", exc_type, msg): b"bytes input".decode(self.codec_name) - with self.assertWrapped("decoding", exc_type, msg): + with self.assertNoted("decoding", exc_type, msg): codecs.decode(b"bytes input", self.codec_name) def test_raise_by_type(self): - self.check_wrapped(RuntimeError, "") + self.check_note(RuntimeError, "") def test_raise_by_value(self): - msg = "This should be wrapped" - self.check_wrapped(RuntimeError(msg), msg) + msg = "This should be noted" + self.check_note(RuntimeError(msg), msg) def test_raise_grandchild_subclass_exact_size(self): - msg = "This should be wrapped" + msg = "This should be noted" class MyRuntimeError(RuntimeError): __slots__ = () - self.check_wrapped(MyRuntimeError(msg), msg, MyRuntimeError) + self.check_note(MyRuntimeError(msg), msg, MyRuntimeError) def test_raise_subclass_with_weakref_support(self): - msg = "This should be wrapped" + msg = "This should be noted" class MyRuntimeError(RuntimeError): pass - self.check_wrapped(MyRuntimeError(msg), msg, MyRuntimeError) - - def check_not_wrapped(self, obj_to_raise, msg): - def raise_obj(*args, **kwds): - raise obj_to_raise - self.set_codec(raise_obj, raise_obj) - with self.assertRaisesRegex(RuntimeError, msg): - "str input".encode(self.codec_name) - with self.assertRaisesRegex(RuntimeError, msg): - codecs.encode("str input", self.codec_name) - with self.assertRaisesRegex(RuntimeError, msg): - b"bytes input".decode(self.codec_name) - with self.assertRaisesRegex(RuntimeError, msg): - codecs.decode(b"bytes input", self.codec_name) + self.check_note(MyRuntimeError(msg), msg, MyRuntimeError) - def test_init_override_is_not_wrapped(self): + def test_init_override(self): class CustomInit(RuntimeError): def __init__(self): pass - self.check_not_wrapped(CustomInit, "") + self.check_note(CustomInit, "") - def test_new_override_is_not_wrapped(self): + def test_new_override(self): class CustomNew(RuntimeError): def __new__(cls): return super().__new__(cls) - self.check_not_wrapped(CustomNew, "") + self.check_note(CustomNew, "") - def test_instance_attribute_is_not_wrapped(self): - msg = "This should NOT be wrapped" + def test_instance_attribute(self): + msg = "This should be noted" exc = RuntimeError(msg) exc.attr = 1 - self.check_not_wrapped(exc, "^{}$".format(msg)) + self.check_note(exc, "^{}$".format(msg)) - def test_non_str_arg_is_not_wrapped(self): - self.check_not_wrapped(RuntimeError(1), "1") + def test_non_str_arg(self): + self.check_note(RuntimeError(1), "1") - def test_multiple_args_is_not_wrapped(self): + def test_multiple_args(self): msg_re = r"^\('a', 'b', 'c'\)$" - self.check_not_wrapped(RuntimeError('a', 'b', 'c'), msg_re) + self.check_note(RuntimeError('a', 'b', 'c'), msg_re) # http://bugs.python.org/issue19609 - def test_codec_lookup_failure_not_wrapped(self): + def test_codec_lookup_failure(self): msg = "^unknown encoding: {}$".format(self.codec_name) - # The initial codec lookup should not be wrapped with self.assertRaisesRegex(LookupError, msg): "str input".encode(self.codec_name) with self.assertRaisesRegex(LookupError, msg): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-03-23-21-16.gh-issue-102406.XLqYO3.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-03-23-21-16.gh-issue-102406.XLqYO3.rst new file mode 100644 index 00000000000000..e0d061c37299f2 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-03-23-21-16.gh-issue-102406.XLqYO3.rst @@ -0,0 +1 @@ +:mod:`codecs` encoding/decoding errors now get the context information (which operation and which codecs) attached as :pep:`678` notes instead of through chaining a new instance of the exception. diff --git a/Objects/exceptions.c b/Objects/exceptions.c index d69f7400ca6042..a355244cf997e6 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -3764,113 +3764,3 @@ _PyException_AddNote(PyObject *exc, PyObject *note) return res; } -/* Helper to do the equivalent of "raise X from Y" in C, but always using - * the current exception rather than passing one in. - * - * We currently limit this to *only* exceptions that use the BaseException - * tp_init and tp_new methods, since we can be reasonably sure we can wrap - * those correctly without losing data and without losing backwards - * compatibility. - * - * We also aim to rule out *all* exceptions that might be storing additional - * state, whether by having a size difference relative to BaseException, - * additional arguments passed in during construction or by having a - * non-empty instance dict. - * - * We need to be very careful with what we wrap, since changing types to - * a broader exception type would be backwards incompatible for - * existing codecs, and with different init or new method implementations - * may either not support instantiation with PyErr_Format or lose - * information when instantiated that way. - * - * XXX (ncoghlan): This could be made more comprehensive by exploiting the - * fact that exceptions are expected to support pickling. If more builtin - * exceptions (e.g. AttributeError) start to be converted to rich - * exceptions with additional attributes, that's probably a better approach - * to pursue over adding special cases for particular stateful subclasses. - * - * Returns a borrowed reference to the new exception (if any), NULL if the - * existing exception was left in place. - */ -PyObject * -_PyErr_TrySetFromCause(const char *format, ...) -{ - PyObject* msg_prefix; - PyObject *instance_args; - Py_ssize_t num_args, caught_type_size, base_exc_size; - va_list vargs; - int same_basic_size; - - PyObject *exc = PyErr_GetRaisedException(); - PyTypeObject *caught_type = Py_TYPE(exc); - /* Ensure type info indicates no extra state is stored at the C level - * and that the type can be reinstantiated using PyErr_Format - */ - caught_type_size = caught_type->tp_basicsize; - base_exc_size = _PyExc_BaseException.tp_basicsize; - same_basic_size = ( - caught_type_size == base_exc_size || - (_PyType_SUPPORTS_WEAKREFS(caught_type) && - (caught_type_size == base_exc_size + (Py_ssize_t)sizeof(PyObject *)) - ) - ); - if (caught_type->tp_init != (initproc)BaseException_init || - caught_type->tp_new != BaseException_new || - !same_basic_size || - caught_type->tp_itemsize != _PyExc_BaseException.tp_itemsize) { - /* We can't be sure we can wrap this safely, since it may contain - * more state than just the exception type. Accordingly, we just - * leave it alone. - */ - PyErr_SetRaisedException(exc); - return NULL; - } - - /* Check the args are empty or contain a single string */ - instance_args = ((PyBaseExceptionObject *)exc)->args; - num_args = PyTuple_GET_SIZE(instance_args); - if (num_args > 1 || - (num_args == 1 && - !PyUnicode_CheckExact(PyTuple_GET_ITEM(instance_args, 0)))) { - /* More than 1 arg, or the one arg we do have isn't a string - */ - PyErr_SetRaisedException(exc); - return NULL; - } - - /* Ensure the instance dict is also empty */ - if (!_PyObject_IsInstanceDictEmpty(exc)) { - /* While we could potentially copy a non-empty instance dictionary - * to the replacement exception, for now we take the more - * conservative path of leaving exceptions with attributes set - * alone. - */ - PyErr_SetRaisedException(exc); - return NULL; - } - - /* For exceptions that we can wrap safely, we chain the original - * exception to a new one of the exact same type with an - * error message that mentions the additional details and the - * original exception. - * - * It would be nice to wrap OSError and various other exception - * types as well, but that's quite a bit trickier due to the extra - * state potentially stored on OSError instances. - */ - va_start(vargs, format); - msg_prefix = PyUnicode_FromFormatV(format, vargs); - va_end(vargs); - if (msg_prefix == NULL) { - Py_DECREF(exc); - return NULL; - } - - PyErr_Format((PyObject*)Py_TYPE(exc), "%U (%s: %S)", - msg_prefix, Py_TYPE(exc)->tp_name, exc); - Py_DECREF(msg_prefix); - PyObject *new_exc = PyErr_GetRaisedException(); - PyException_SetCause(new_exc, exc); - PyErr_SetRaisedException(new_exc); - return new_exc; -} diff --git a/Python/codecs.c b/Python/codecs.c index b2087b499dfdba..9d800f9856c2f7 100644 --- a/Python/codecs.c +++ b/Python/codecs.c @@ -382,20 +382,27 @@ PyObject *PyCodec_StreamWriter(const char *encoding, return codec_getstreamcodec(encoding, stream, errors, 3); } -/* Helper that tries to ensure the reported exception chain indicates the - * codec that was invoked to trigger the failure without changing the type - * of the exception raised. - */ static void -wrap_codec_error(const char *operation, - const char *encoding) +add_note_to_codec_error(const char *operation, + const char *encoding) { - /* TrySetFromCause will replace the active exception with a suitably - * updated clone if it can, otherwise it will leave the original - * exception alone. - */ - _PyErr_TrySetFromCause("%s with '%s' codec failed", - operation, encoding); + PyObject *exc = PyErr_GetRaisedException(); + if (exc == NULL) { + return; + } + PyObject *note = PyUnicode_FromFormat("%s with '%s' codec failed", + operation, encoding); + if (note == NULL) { + _PyErr_ChainExceptions1(exc); + return; + } + int res = _PyException_AddNote(exc, note); + Py_DECREF(note); + if (res < 0) { + _PyErr_ChainExceptions1(exc); + return; + } + PyErr_SetRaisedException(exc); } /* Encode an object (e.g. a Unicode object) using the given encoding @@ -418,7 +425,7 @@ _PyCodec_EncodeInternal(PyObject *object, result = PyObject_Call(encoder, args, NULL); if (result == NULL) { - wrap_codec_error("encoding", encoding); + add_note_to_codec_error("encoding", encoding); goto onError; } @@ -463,7 +470,7 @@ _PyCodec_DecodeInternal(PyObject *object, result = PyObject_Call(decoder, args, NULL); if (result == NULL) { - wrap_codec_error("decoding", encoding); + add_note_to_codec_error("decoding", encoding); goto onError; } if (!PyTuple_Check(result) || From 7174c0cc98d57ef5b3d3b67626b7e75b26c85298 Mon Sep 17 00:00:00 2001 From: David Poirier <1152277+david-poirier@users.noreply.github.com> Date: Wed, 22 Mar 2023 08:58:31 +1100 Subject: [PATCH 175/280] Add link to `sys.exit` function documentation (#102805) * Add link to `sys.exit` function documentation * Update Doc/library/os.rst Co-authored-by: Ezio Melotti * Update Doc/library/os.rst Co-authored-by: C.A.M. Gerlach --------- Co-authored-by: Ezio Melotti Co-authored-by: C.A.M. Gerlach --- Doc/library/os.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 3153f79e10ce1f..7bb501c5946817 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -3951,7 +3951,7 @@ to be ignored. .. note:: - The standard way to exit is ``sys.exit(n)``. :func:`_exit` should + The standard way to exit is :func:`sys.exit(n) `. :func:`!_exit` should normally only be used in the child process after a :func:`fork`. The following exit codes are defined and can be used with :func:`_exit`, From 4dc17094b6b362c3dd21c53d74e2f4211ad7d48f Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Wed, 22 Mar 2023 02:48:19 +0300 Subject: [PATCH 176/280] gh-102839: remove AC for math.log (GH-102863) --- ...-03-20-12-21-19.gh-issue-102839.RjRi12.rst | 1 + Modules/clinic/mathmodule.c.h | 45 +------------------ Modules/mathmodule.c | 35 ++++++--------- 3 files changed, 16 insertions(+), 65 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-03-20-12-21-19.gh-issue-102839.RjRi12.rst diff --git a/Misc/NEWS.d/next/Library/2023-03-20-12-21-19.gh-issue-102839.RjRi12.rst b/Misc/NEWS.d/next/Library/2023-03-20-12-21-19.gh-issue-102839.RjRi12.rst new file mode 100644 index 00000000000000..673b38974e4d1b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-20-12-21-19.gh-issue-102839.RjRi12.rst @@ -0,0 +1 @@ +Improve performance of :func:`math.log` arguments handling by removing the argument clinic. diff --git a/Modules/clinic/mathmodule.c.h b/Modules/clinic/mathmodule.c.h index 1f9725883b9820..bc5bbceb4c92b6 100644 --- a/Modules/clinic/mathmodule.c.h +++ b/Modules/clinic/mathmodule.c.h @@ -186,49 +186,6 @@ math_modf(PyObject *module, PyObject *arg) return return_value; } -PyDoc_STRVAR(math_log__doc__, -"log(x, [base=math.e])\n" -"Return the logarithm of x to the given base.\n" -"\n" -"If the base not specified, returns the natural logarithm (base e) of x."); - -#define MATH_LOG_METHODDEF \ - {"log", (PyCFunction)math_log, METH_VARARGS, math_log__doc__}, - -static PyObject * -math_log_impl(PyObject *module, PyObject *x, int group_right_1, - PyObject *base); - -static PyObject * -math_log(PyObject *module, PyObject *args) -{ - PyObject *return_value = NULL; - PyObject *x; - int group_right_1 = 0; - PyObject *base = NULL; - - switch (PyTuple_GET_SIZE(args)) { - case 1: - if (!PyArg_ParseTuple(args, "O:log", &x)) { - goto exit; - } - break; - case 2: - if (!PyArg_ParseTuple(args, "OO:log", &x, &base)) { - goto exit; - } - group_right_1 = 1; - break; - default: - PyErr_SetString(PyExc_TypeError, "math.log requires 1 to 2 arguments"); - goto exit; - } - return_value = math_log_impl(module, x, group_right_1, base); - -exit: - return return_value; -} - PyDoc_STRVAR(math_log2__doc__, "log2($module, x, /)\n" "--\n" @@ -954,4 +911,4 @@ math_ulp(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=899211ec70e4506c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a6437a3ba18c486a input=a9049054013a1b77]*/ diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index c9a2be66863993..473936edb3f5cd 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -2284,33 +2284,22 @@ loghelper(PyObject* arg, double (*func)(double)) } -/*[clinic input] -math.log - - x: object - [ - base: object(c_default="NULL") = math.e - ] - / - -Return the logarithm of x to the given base. - -If the base not specified, returns the natural logarithm (base e) of x. -[clinic start generated code]*/ - +/* AC: cannot convert yet, see gh-102839 and gh-89381, waiting + for support of multiple signatures */ static PyObject * -math_log_impl(PyObject *module, PyObject *x, int group_right_1, - PyObject *base) -/*[clinic end generated code: output=7b5a39e526b73fc9 input=0f62d5726cbfebbd]*/ +math_log(PyObject *module, PyObject * const *args, Py_ssize_t nargs) { PyObject *num, *den; PyObject *ans; - num = loghelper(x, m_log); - if (num == NULL || base == NULL) + if (!_PyArg_CheckPositional("log", nargs, 1, 2)) + return NULL; + + num = loghelper(args[0], m_log); + if (num == NULL || nargs == 1) return num; - den = loghelper(base, m_log); + den = loghelper(args[1], m_log); if (den == NULL) { Py_DECREF(num); return NULL; @@ -2322,6 +2311,10 @@ math_log_impl(PyObject *module, PyObject *x, int group_right_1, return ans; } +PyDoc_STRVAR(math_log_doc, +"log(x, [base=math.e])\n\ +Return the logarithm of x to the given base.\n\n\ +If the base not specified, returns the natural logarithm (base e) of x."); /*[clinic input] math.log2 @@ -4045,7 +4038,7 @@ static PyMethodDef math_methods[] = { {"lcm", _PyCFunction_CAST(math_lcm), METH_FASTCALL, math_lcm_doc}, MATH_LDEXP_METHODDEF {"lgamma", math_lgamma, METH_O, math_lgamma_doc}, - MATH_LOG_METHODDEF + {"log", _PyCFunction_CAST(math_log), METH_FASTCALL, math_log_doc}, {"log1p", math_log1p, METH_O, math_log1p_doc}, MATH_LOG10_METHODDEF MATH_LOG2_METHODDEF From e030c1865ae73242441c631b3afd9248f6e07c3b Mon Sep 17 00:00:00 2001 From: gaogaotiantian Date: Wed, 22 Mar 2023 04:34:52 -0700 Subject: [PATCH 177/280] Docs: improve accuracy of pdb alias example (#102892) --- Doc/library/pdb.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 21c6ca8622dceb..5988477af03abd 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -513,7 +513,7 @@ can be overridden by the local file. :file:`.pdbrc` file):: # Print instance variables (usage "pi classInst") - alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k]) + alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}") # Print instance variables in self alias ps pi self From e1394426931729a64e87b49ab94b6e9bd5508463 Mon Sep 17 00:00:00 2001 From: Artem Mukhin Date: Wed, 22 Mar 2023 12:35:27 +0100 Subject: [PATCH 178/280] GH-94808: Cover `PyOS_mystrnicmp` and `PyOS_mystricmp` (gh-102469) --- Modules/Setup.stdlib.in | 2 +- Modules/_testcapi/parts.h | 1 + Modules/_testcapi/pyos.c | 60 +++++++++++++++++++++++++++++++ Modules/_testcapimodule.c | 3 ++ PCbuild/_testcapi.vcxproj | 1 + PCbuild/_testcapi.vcxproj.filters | 3 ++ 6 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 Modules/_testcapi/pyos.c diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in index b12290d436cbeb..fe1b9f8f5380c1 100644 --- a/Modules/Setup.stdlib.in +++ b/Modules/Setup.stdlib.in @@ -169,7 +169,7 @@ @MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c @MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c @MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c -@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c +@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/pyos.c @MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c # Some testing modules MUST be built as shared libraries. diff --git a/Modules/_testcapi/parts.h b/Modules/_testcapi/parts.h index c8f31dc8e39fae..60ec81dad2ba9e 100644 --- a/Modules/_testcapi/parts.h +++ b/Modules/_testcapi/parts.h @@ -38,6 +38,7 @@ int _PyTestCapi_Init_Float(PyObject *module); int _PyTestCapi_Init_Structmember(PyObject *module); int _PyTestCapi_Init_Exceptions(PyObject *module); int _PyTestCapi_Init_Code(PyObject *module); +int _PyTestCapi_Init_PyOS(PyObject *module); #ifdef LIMITED_API_AVAILABLE int _PyTestCapi_Init_VectorcallLimited(PyObject *module); diff --git a/Modules/_testcapi/pyos.c b/Modules/_testcapi/pyos.c new file mode 100644 index 00000000000000..63140e914875db --- /dev/null +++ b/Modules/_testcapi/pyos.c @@ -0,0 +1,60 @@ +#include "parts.h" + + +static PyObject * +test_PyOS_mystrnicmp(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + assert(PyOS_mystrnicmp("", "", 0) == 0); + assert(PyOS_mystrnicmp("", "", 1) == 0); + + assert(PyOS_mystrnicmp("insert", "ins", 3) == 0); + assert(PyOS_mystrnicmp("ins", "insert", 3) == 0); + assert(PyOS_mystrnicmp("insect", "insert", 3) == 0); + + assert(PyOS_mystrnicmp("insert", "insert", 6) == 0); + assert(PyOS_mystrnicmp("Insert", "insert", 6) == 0); + assert(PyOS_mystrnicmp("INSERT", "insert", 6) == 0); + assert(PyOS_mystrnicmp("insert", "insert", 10) == 0); + + assert(PyOS_mystrnicmp("invert", "insert", 6) == ('v' - 's')); + assert(PyOS_mystrnicmp("insert", "invert", 6) == ('s' - 'v')); + assert(PyOS_mystrnicmp("insert", "ins\0rt", 6) == 'e'); + + // GH-21845 + assert(PyOS_mystrnicmp("insert\0a", "insert\0b", 8) == 0); + + Py_RETURN_NONE; +} + +static PyObject * +test_PyOS_mystricmp(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + assert(PyOS_mystricmp("", "") == 0); + assert(PyOS_mystricmp("insert", "insert") == 0); + assert(PyOS_mystricmp("Insert", "insert") == 0); + assert(PyOS_mystricmp("INSERT", "insert") == 0); + assert(PyOS_mystricmp("insert", "ins") == 'e'); + assert(PyOS_mystricmp("ins", "insert") == -'e'); + + // GH-21845 + assert(PyOS_mystricmp("insert", "ins\0rt") == 'e'); + assert(PyOS_mystricmp("invert", "insert") == ('v' - 's')); + + Py_RETURN_NONE; +} + +static PyMethodDef test_methods[] = { + {"test_PyOS_mystrnicmp", test_PyOS_mystrnicmp, METH_NOARGS, NULL}, + {"test_PyOS_mystricmp", test_PyOS_mystricmp, METH_NOARGS, NULL}, + {NULL}, +}; + +int +_PyTestCapi_Init_PyOS(PyObject *mod) +{ + if (PyModule_AddFunctions(mod, test_methods) < 0) { + return -1; + } + + return 0; +} diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index e2ebab5c5b4849..3d9a2aeeb7cfd5 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -4154,6 +4154,9 @@ PyInit__testcapi(void) if (_PyTestCapi_Init_Code(m) < 0) { return NULL; } + if (_PyTestCapi_Init_PyOS(m) < 0) { + return NULL; + } #ifndef LIMITED_API_AVAILABLE PyModule_AddObjectRef(m, "LIMITED_API_AVAILABLE", Py_False); diff --git a/PCbuild/_testcapi.vcxproj b/PCbuild/_testcapi.vcxproj index 4cc184bfc1ac82..439cd687fda61d 100644 --- a/PCbuild/_testcapi.vcxproj +++ b/PCbuild/_testcapi.vcxproj @@ -109,6 +109,7 @@ + diff --git a/PCbuild/_testcapi.vcxproj.filters b/PCbuild/_testcapi.vcxproj.filters index fbdaf04ce37cb1..0e42e4982c21ff 100644 --- a/PCbuild/_testcapi.vcxproj.filters +++ b/PCbuild/_testcapi.vcxproj.filters @@ -57,6 +57,9 @@ Source Files + + Source Files + From 563cf60b4c10a17c9c98459bf495a3b4bd39f15e Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 22 Mar 2023 12:37:13 +0100 Subject: [PATCH 179/280] Docs: improve the accuracy of the sqlite3.connect() timeout param (#102900) Co-authored-by: C.A.M. Gerlach --- Doc/library/sqlite3.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index ff036ad56acba8..a78f3eb7221746 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -272,9 +272,9 @@ Module functions :param float timeout: How many seconds the connection should wait before raising - an exception, if the database is locked by another connection. - If another connection opens a transaction to modify the database, - it will be locked until that transaction is committed. + an :exc:`OperationalError` when a table is locked. + If another connection opens a transaction to modify a table, + that table will be locked until the transaction is committed. Default five seconds. :param int detect_types: From 3e098602f61989f507e6b3ea5748e8a438ec7606 Mon Sep 17 00:00:00 2001 From: Timo Ludwig Date: Wed, 22 Mar 2023 12:46:58 +0100 Subject: [PATCH 180/280] gh-100989: Improve the accuracy of collections.deque docstrings (#100990) Co-authored-by: C.A.M. Gerlach --- Modules/_collectionsmodule.c | 37 +++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 68131f3b54d2ea..ba4a9760f7b906 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -910,7 +910,9 @@ deque_rotate(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(rotate_doc, -"Rotate the deque n steps to the right (default n=1). If n is negative, rotates left."); +"rotate(n)\n\n" +"Rotate the deque *n* steps to the right (default ``n=1``). " +"If *n* is negative, rotates left."); static PyObject * deque_reverse(dequeobject *deque, PyObject *unused) @@ -951,7 +953,8 @@ deque_reverse(dequeobject *deque, PyObject *unused) } PyDoc_STRVAR(reverse_doc, -"D.reverse() -- reverse *IN PLACE*"); +"reverse()\n\n" +"Reverse the elements of the deque *IN PLACE*."); static PyObject * deque_count(dequeobject *deque, PyObject *v) @@ -990,7 +993,8 @@ deque_count(dequeobject *deque, PyObject *v) } PyDoc_STRVAR(count_doc, -"D.count(value) -> integer -- return number of occurrences of value"); +"count(x) -> int\n\n" +"Count the number of deque elements equal to *x*."); static int deque_contains(dequeobject *deque, PyObject *v) @@ -1098,8 +1102,10 @@ deque_index(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(index_doc, -"D.index(value, [start, [stop]]) -> integer -- return first index of value.\n" -"Raises ValueError if the value is not present."); +"index(x, [start, [stop]]) -> int\n\n" +"Return the position of *x* in the deque " +"(at or after index *start* and before index *stop*). " +"Returns the first match or raises a ValueError if not found."); /* insert(), remove(), and delitem() are implemented in terms of rotate() for simplicity and reasonable performance near the end @@ -1144,10 +1150,13 @@ deque_insert(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(insert_doc, -"D.insert(index, object) -- insert object before index"); +"insert(i, x)\n\n" +"Insert *x* into the deque at position *i*."); PyDoc_STRVAR(remove_doc, -"D.remove(value) -- remove first occurrence of value."); +"remove(x)\n\n" +"Remove the first occurrence of *x*." +"If not found, raises a ValueError."); static int valid_index(Py_ssize_t i, Py_ssize_t limit) @@ -1518,7 +1527,8 @@ deque_sizeof(dequeobject *deque, void *unused) } PyDoc_STRVAR(sizeof_doc, -"D.__sizeof__() -- size of D in memory, in bytes"); +"__sizeof__() -> int\n\n" +"Size of the deque in memory, in bytes."); static PyObject * deque_get_maxlen(dequeobject *deque, void *Py_UNUSED(ignored)) @@ -1553,7 +1563,8 @@ static PySequenceMethods deque_as_sequence = { static PyObject *deque_iter(dequeobject *deque); static PyObject *deque_reviter(dequeobject *deque, PyObject *Py_UNUSED(ignored)); PyDoc_STRVAR(reversed_doc, - "D.__reversed__() -- return a reverse iterator over the deque"); +"__reversed__()\n\n" +"Return a reverse iterator over the deque."); static PyMethodDef deque_methods[] = { {"append", (PyCFunction)deque_append, @@ -1598,9 +1609,8 @@ static PyMethodDef deque_methods[] = { }; PyDoc_STRVAR(deque_doc, -"deque([iterable[, maxlen]]) --> deque object\n\ -\n\ -A list-like sequence optimized for data accesses near its endpoints."); +"deque([iterable[, maxlen]]) -> collections.deque\n\n" +"A list-like sequence optimized for data accesses near its endpoints."); static PyTypeObject deque_type = { PyVarObject_HEAD_INIT(NULL, 0) @@ -1979,7 +1989,8 @@ new_defdict(defdictobject *dd, PyObject *arg) dd->default_factory ? dd->default_factory : Py_None, arg, NULL); } -PyDoc_STRVAR(defdict_copy_doc, "D.copy() -> a shallow copy of D."); +PyDoc_STRVAR(defdict_copy_doc, "copy() -> collections.deque\n\n" +"A shallow copy of the deque."); static PyObject * defdict_copy(defdictobject *dd, PyObject *Py_UNUSED(ignored)) From f59f943f907a06ffb41f540ce94659a8d3b14f92 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 22 Mar 2023 12:50:00 +0100 Subject: [PATCH 181/280] Docs: improve accuracy of sqlite3.Connection.interrupt() (#102904) Co-authored-by: C.A.M. Gerlach --- Doc/library/sqlite3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index a78f3eb7221746..4b2d13ab3a8fcd 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -911,7 +911,7 @@ Connection objects Call this method from a different thread to abort any queries that might be executing on the connection. - Aborted queries will raise an exception. + Aborted queries will raise an :exc:`OperationalError`. .. method:: set_authorizer(authorizer_callback) From 6a956105bc59951a1fa76d60508202826cea5fc7 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 22 Mar 2023 08:16:26 -0400 Subject: [PATCH 182/280] GH-95494: Fix transport EOF handling in OpenSSL 3.0 (GH-95495) GH-25309 enabled SSL_OP_IGNORE_UNEXPECTED_EOF by default, with a comment that it restores OpenSSL 1.1.1 behavior, but this wasn't quite right. That option causes OpenSSL to treat transport EOF as the same as close_notify (i.e. SSL_ERROR_ZERO_RETURN), whereas Python actually has distinct SSLEOFError and SSLZeroReturnError exceptions. (The latter is usually mapped to a zero return from read.) In OpenSSL 1.1.1, the ssl module would raise them for transport EOF and close_notify, respectively. In OpenSSL 3.0, both act like close_notify. Fix this by, instead, just detecting SSL_R_UNEXPECTED_EOF_WHILE_READING and mapping that to the other exception type. There doesn't seem to have been any unit test of this error, so fill in the missing one. This had to be done with the BIO path because it's actually slightly tricky to simulate a transport EOF with Python's fd based APIs. (If you instruct the server to close the socket, it gets confused, probably because the server's SSL object is still referencing the now dead fd?) --- Lib/test/test_ssl.py | 18 +++++++++++++++--- ...22-07-30-23-01-43.gh-issue-95495.RA-q1d.rst | 7 +++++++ Modules/_ssl.c | 14 ++++++++++---- 3 files changed, 32 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index d4eb2d2e81fe0f..76669bdac72f3f 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -151,7 +151,6 @@ def data_file(*name): OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0) OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0) OP_ENABLE_MIDDLEBOX_COMPAT = getattr(ssl, "OP_ENABLE_MIDDLEBOX_COMPAT", 0) -OP_IGNORE_UNEXPECTED_EOF = getattr(ssl, "OP_IGNORE_UNEXPECTED_EOF", 0) # Ubuntu has patched OpenSSL and changed behavior of security level 2 # see https://bugs.python.org/issue41561#msg389003 @@ -958,8 +957,7 @@ def test_options(self): # SSLContext also enables these by default default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE | OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE | - OP_ENABLE_MIDDLEBOX_COMPAT | - OP_IGNORE_UNEXPECTED_EOF) + OP_ENABLE_MIDDLEBOX_COMPAT) self.assertEqual(default, ctx.options) with warnings_helper.check_warnings(): ctx.options |= ssl.OP_NO_TLSv1 @@ -2120,6 +2118,20 @@ def test_bio_read_write_data(self): self.assertEqual(buf, b'foo\n') self.ssl_io_loop(sock, incoming, outgoing, sslobj.unwrap) + def test_transport_eof(self): + client_context, server_context, hostname = testing_context() + with socket.socket(socket.AF_INET) as sock: + sock.connect(self.server_addr) + incoming = ssl.MemoryBIO() + outgoing = ssl.MemoryBIO() + sslobj = client_context.wrap_bio(incoming, outgoing, + server_hostname=hostname) + self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake) + + # Simulate EOF from the transport. + incoming.write_eof() + self.assertRaises(ssl.SSLEOFError, sslobj.read) + @support.requires_resource('network') class NetworkedTests(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst b/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst new file mode 100644 index 00000000000000..d0f4ccbdd3e39f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-07-30-23-01-43.gh-issue-95495.RA-q1d.rst @@ -0,0 +1,7 @@ +When built against OpenSSL 3.0, the :mod:`ssl` module had a bug where it +reported unauthenticated EOFs (i.e. without close_notify) as a clean TLS-level +EOF. It now raises :exc:`~ssl.SSLEOFError`, matching the behavior in previous +versions of OpenSSL. The :attr:`~ssl.SSLContext.options` attribute on +:class:`~ssl.SSLContext` also no longer includes +:data:`~ssl.OP_IGNORE_UNEXPECTED_EOF` by default. This option may be set to +specify the previous OpenSSL 3.0 behavior. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 121d18884d0a9f..321b6ec52b7775 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -660,6 +660,16 @@ PySSL_SetError(PySSLSocket *sslsock, int ret, const char *filename, int lineno) ERR_GET_REASON(e) == SSL_R_CERTIFICATE_VERIFY_FAILED) { type = state->PySSLCertVerificationErrorObject; } +#if defined(SSL_R_UNEXPECTED_EOF_WHILE_READING) + /* OpenSSL 3.0 changed transport EOF from SSL_ERROR_SYSCALL with + * zero return value to SSL_ERROR_SSL with a special error code. */ + if (ERR_GET_LIB(e) == ERR_LIB_SSL && + ERR_GET_REASON(e) == SSL_R_UNEXPECTED_EOF_WHILE_READING) { + p = PY_SSL_ERROR_EOF; + type = state->PySSLEOFErrorObject; + errstr = "EOF occurred in violation of protocol"; + } +#endif break; } default: @@ -3092,10 +3102,6 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) #endif #ifdef SSL_OP_SINGLE_ECDH_USE options |= SSL_OP_SINGLE_ECDH_USE; -#endif -#ifdef SSL_OP_IGNORE_UNEXPECTED_EOF - /* Make OpenSSL 3.0.0 behave like 1.1.1 */ - options |= SSL_OP_IGNORE_UNEXPECTED_EOF; #endif SSL_CTX_set_options(self->ctx, options); From f0e93195a08882b610a32ed54766dbcf340c0a73 Mon Sep 17 00:00:00 2001 From: Icelain Date: Wed, 22 Mar 2023 17:49:52 +0530 Subject: [PATCH 183/280] gh-101313: Add -h and --help arguments to the webbrowser module (gh-101374) --- Lib/webbrowser.py | 10 +++++++--- .../2023-01-27-14-51-07.gh-issue-101313.10AEXh.rst | 1 + 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-01-27-14-51-07.gh-issue-101313.10AEXh.rst diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py index a56ff33dbbdc69..4336597e68f625 100755 --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -713,11 +713,12 @@ def open(self, url, new=0, autoraise=True): def main(): import getopt - usage = """Usage: %s [-n | -t] url + usage = """Usage: %s [-n | -t | -h] url -n: open new window - -t: open new tab""" % sys.argv[0] + -t: open new tab + -h, --help: show help""" % sys.argv[0] try: - opts, args = getopt.getopt(sys.argv[1:], 'ntd') + opts, args = getopt.getopt(sys.argv[1:], 'ntdh',['help']) except getopt.error as msg: print(msg, file=sys.stderr) print(usage, file=sys.stderr) @@ -726,6 +727,9 @@ def main(): for o, a in opts: if o == '-n': new_win = 1 elif o == '-t': new_win = 2 + elif o == '-h' or o == '--help': + print(usage, file=sys.stderr) + sys.exit() if len(args) != 1: print(usage, file=sys.stderr) sys.exit(1) diff --git a/Misc/NEWS.d/next/Library/2023-01-27-14-51-07.gh-issue-101313.10AEXh.rst b/Misc/NEWS.d/next/Library/2023-01-27-14-51-07.gh-issue-101313.10AEXh.rst new file mode 100644 index 00000000000000..63d0a7286920a4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-01-27-14-51-07.gh-issue-101313.10AEXh.rst @@ -0,0 +1 @@ +Added -h and --help arguments to the webbrowser CLI From b6098c5a1f0633fd1cbb703adc027a47e4490a36 Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Wed, 22 Mar 2023 14:05:08 +0100 Subject: [PATCH 184/280] gh-101947: Remove size check from sqlite3 serialize test (#102914) The size of the returned data is too implementation specific. --- Lib/test/test_sqlite3/test_dbapi.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index 695e213cdc7b75..3013abfa730ed5 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -606,7 +606,6 @@ def test_serialize_deserialize(self): with cx: cx.execute("create table t(t)") data = cx.serialize() - self.assertEqual(len(data), 8192) # Remove test table, verify that it was removed. with cx: From f30f362ffc4092d8e0f9f026a79d91f1811e4065 Mon Sep 17 00:00:00 2001 From: Max Bachmann Date: Wed, 22 Mar 2023 14:44:28 +0100 Subject: [PATCH 185/280] gh-102027: Fix macro name (#102124) This fixes the ssse3 / sse2 detection when sse4 is available. Co-authored-by: Oleg Iarygin --- .../2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst | 2 ++ Modules/_blake2/impl/blake2-config.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst b/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst new file mode 100644 index 00000000000000..42d96b54677e41 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-02-21-23-42-39.gh-issue-102027.fQARG0.rst @@ -0,0 +1,2 @@ +Fix SSE2 and SSE3 detection in ``_blake2`` internal module. Patch by Max +Bachmann. diff --git a/Modules/_blake2/impl/blake2-config.h b/Modules/_blake2/impl/blake2-config.h index f5dd6faa9e6867..c09cb4bcf06723 100644 --- a/Modules/_blake2/impl/blake2-config.h +++ b/Modules/_blake2/impl/blake2-config.h @@ -53,7 +53,7 @@ #endif #endif -#ifdef HAVE_SSE41 +#ifdef HAVE_SSE4_1 #ifndef HAVE_SSSE3 #define HAVE_SSSE3 #endif From 233ef6d7bb72bf8c9e0ec0173f182ee0a2c41e98 Mon Sep 17 00:00:00 2001 From: Benjamin Fogle Date: Wed, 22 Mar 2023 10:08:41 -0400 Subject: [PATCH 186/280] gh-96931: Fix incorrect results in ssl.SSLSocket.shared_ciphers (#96932) --- Doc/library/ssl.rst | 2 +- Lib/test/test_ssl.py | 6 ++-- ...2-09-19-08-12-58.gh-issue-96931.x0WQhh.rst | 1 + Modules/_ssl.c | 36 ++++++++++++++----- 4 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst index 30f2a0765cc955..4b60b7c643b62c 100644 --- a/Doc/library/ssl.rst +++ b/Doc/library/ssl.rst @@ -1218,7 +1218,7 @@ SSL sockets also have the following additional methods and attributes: .. method:: SSLSocket.shared_ciphers() - Return the list of ciphers shared by the client during the handshake. Each + Return the list of ciphers available in both the client and server. Each entry of the returned list is a three-value tuple containing the name of the cipher, the version of the SSL protocol that defines its use, and the number of secret bits the cipher uses. :meth:`~SSLSocket.shared_ciphers` returns diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 76669bdac72f3f..1317efb33c2306 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -2082,13 +2082,13 @@ def test_bio_handshake(self): self.assertIs(sslobj._sslobj.owner, sslobj) self.assertIsNone(sslobj.cipher()) self.assertIsNone(sslobj.version()) - self.assertIsNotNone(sslobj.shared_ciphers()) + self.assertIsNone(sslobj.shared_ciphers()) self.assertRaises(ValueError, sslobj.getpeercert) if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES: self.assertIsNone(sslobj.get_channel_binding('tls-unique')) self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake) self.assertTrue(sslobj.cipher()) - self.assertIsNotNone(sslobj.shared_ciphers()) + self.assertIsNone(sslobj.shared_ciphers()) self.assertIsNotNone(sslobj.version()) self.assertTrue(sslobj.getpeercert()) if 'tls-unique' in ssl.CHANNEL_BINDING_TYPES: @@ -4051,7 +4051,7 @@ def cb_wrong_return_type(ssl_sock, server_name, initial_context): def test_shared_ciphers(self): client_context, server_context, hostname = testing_context() client_context.set_ciphers("AES128:AES256") - server_context.set_ciphers("AES256") + server_context.set_ciphers("AES256:eNULL") expected_algs = [ "AES256", "AES-256", # TLS 1.3 ciphers are always enabled diff --git a/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst b/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst new file mode 100644 index 00000000000000..766b1d4d477b72 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-09-19-08-12-58.gh-issue-96931.x0WQhh.rst @@ -0,0 +1 @@ +Fix incorrect results from :meth:`ssl.SSLSocket.shared_ciphers` diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 321b6ec52b7775..36b66cdb5310c6 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -1998,24 +1998,44 @@ static PyObject * _ssl__SSLSocket_shared_ciphers_impl(PySSLSocket *self) /*[clinic end generated code: output=3d174ead2e42c4fd input=0bfe149da8fe6306]*/ { - STACK_OF(SSL_CIPHER) *ciphers; - int i; + STACK_OF(SSL_CIPHER) *server_ciphers; + STACK_OF(SSL_CIPHER) *client_ciphers; + int i, len; PyObject *res; + const SSL_CIPHER* cipher; + + /* Rather than use SSL_get_shared_ciphers, we use an equivalent algorithm because: + + 1) It returns a colon seperated list of strings, in an undefined + order, that we would have to post process back into tuples. + 2) It will return a truncated string with no indication that it has + done so, if the buffer is too small. + */ - ciphers = SSL_get_ciphers(self->ssl); - if (!ciphers) + server_ciphers = SSL_get_ciphers(self->ssl); + if (!server_ciphers) Py_RETURN_NONE; - res = PyList_New(sk_SSL_CIPHER_num(ciphers)); + client_ciphers = SSL_get_client_ciphers(self->ssl); + if (!client_ciphers) + Py_RETURN_NONE; + + res = PyList_New(sk_SSL_CIPHER_num(server_ciphers)); if (!res) return NULL; - for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { - PyObject *tup = cipher_to_tuple(sk_SSL_CIPHER_value(ciphers, i)); + len = 0; + for (i = 0; i < sk_SSL_CIPHER_num(server_ciphers); i++) { + cipher = sk_SSL_CIPHER_value(server_ciphers, i); + if (sk_SSL_CIPHER_find(client_ciphers, cipher) < 0) + continue; + + PyObject *tup = cipher_to_tuple(cipher); if (!tup) { Py_DECREF(res); return NULL; } - PyList_SET_ITEM(res, i, tup); + PyList_SET_ITEM(res, len++, tup); } + Py_SET_SIZE(res, len); return res; } From b645f1b925cfc3b869bb0ec1e4ea6243848f0ed7 Mon Sep 17 00:00:00 2001 From: Stanislav Zmiev Date: Wed, 22 Mar 2023 18:45:25 +0400 Subject: [PATCH 187/280] GH-89727: Fix pathlib.Path.walk RecursionError on deep trees (GH-100282) Use a stack to implement `pathlib.Path.walk()` iteratively instead of recursively to avoid hitting recursion limits on deeply nested trees. Co-authored-by: Barney Gale Co-authored-by: Brett Cannon --- Lib/pathlib.py | 78 ++++++++++--------- Lib/test/test_pathlib.py | 13 ++++ ...2-12-16-10-27-58.gh-issue-89727.y64ZLM.rst | 1 + 3 files changed, 54 insertions(+), 38 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-12-16-10-27-58.gh-issue-89727.y64ZLM.rst diff --git a/Lib/pathlib.py b/Lib/pathlib.py index 55c44f12e5a2fb..a126bf2fe5570a 100644 --- a/Lib/pathlib.py +++ b/Lib/pathlib.py @@ -1197,45 +1197,47 @@ def expanduser(self): def walk(self, top_down=True, on_error=None, follow_symlinks=False): """Walk the directory tree from this directory, similar to os.walk().""" sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks) - return self._walk(top_down, on_error, follow_symlinks) - - def _walk(self, top_down, on_error, follow_symlinks): - # We may not have read permission for self, in which case we can't - # get a list of the files the directory contains. os.walk - # always suppressed the exception then, rather than blow up for a - # minor reason when (say) a thousand readable directories are still - # left to visit. That logic is copied here. - try: - scandir_it = self._scandir() - except OSError as error: - if on_error is not None: - on_error(error) - return - - with scandir_it: - dirnames = [] - filenames = [] - for entry in scandir_it: - try: - is_dir = entry.is_dir(follow_symlinks=follow_symlinks) - except OSError: - # Carried over from os.path.isdir(). - is_dir = False - - if is_dir: - dirnames.append(entry.name) - else: - filenames.append(entry.name) - - if top_down: - yield self, dirnames, filenames - - for dirname in dirnames: - dirpath = self._make_child_relpath(dirname) - yield from dirpath._walk(top_down, on_error, follow_symlinks) + paths = [self] + + while paths: + path = paths.pop() + if isinstance(path, tuple): + yield path + continue + + # We may not have read permission for self, in which case we can't + # get a list of the files the directory contains. os.walk() + # always suppressed the exception in that instance, rather than + # blow up for a minor reason when (say) a thousand readable + # directories are still left to visit. That logic is copied here. + try: + scandir_it = path._scandir() + except OSError as error: + if on_error is not None: + on_error(error) + continue + + with scandir_it: + dirnames = [] + filenames = [] + for entry in scandir_it: + try: + is_dir = entry.is_dir(follow_symlinks=follow_symlinks) + except OSError: + # Carried over from os.path.isdir(). + is_dir = False + + if is_dir: + dirnames.append(entry.name) + else: + filenames.append(entry.name) + + if top_down: + yield path, dirnames, filenames + else: + paths.append((path, dirnames, filenames)) - if not top_down: - yield self, dirnames, filenames + paths += [path._make_child_relpath(d) for d in reversed(dirnames)] class PosixPath(Path, PurePosixPath): diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py index f05dead5886743..3041630da67899 100644 --- a/Lib/test/test_pathlib.py +++ b/Lib/test/test_pathlib.py @@ -13,6 +13,7 @@ from unittest import mock from test.support import import_helper +from test.support import set_recursion_limit from test.support import is_emscripten, is_wasi from test.support import os_helper from test.support.os_helper import TESTFN, FakePath @@ -2793,6 +2794,18 @@ def test_walk_many_open_files(self): self.assertEqual(next(it), expected) path = path / 'd' + def test_walk_above_recursion_limit(self): + recursion_limit = 40 + # directory_depth > recursion_limit + directory_depth = recursion_limit + 10 + base = pathlib.Path(os_helper.TESTFN, 'deep') + path = pathlib.Path(base, *(['d'] * directory_depth)) + path.mkdir(parents=True) + + with set_recursion_limit(recursion_limit): + list(base.walk()) + list(base.walk(top_down=False)) + class PathTest(_BasePathTest, unittest.TestCase): cls = pathlib.Path diff --git a/Misc/NEWS.d/next/Library/2022-12-16-10-27-58.gh-issue-89727.y64ZLM.rst b/Misc/NEWS.d/next/Library/2022-12-16-10-27-58.gh-issue-89727.y64ZLM.rst new file mode 100644 index 00000000000000..f9ac1475dceb00 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-12-16-10-27-58.gh-issue-89727.y64ZLM.rst @@ -0,0 +1 @@ +Fix pathlib.Path.walk RecursionError on deep directory trees by rewriting it using iteration instead of recursion. From 32f8276e679d5a03fec35867f5691a31e8f136e8 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 22 Mar 2023 14:49:51 +0000 Subject: [PATCH 188/280] GH-101291: Rearrange the size bits in PyLongObject (GH-102464) * Eliminate all remaining uses of Py_SIZE and Py_SET_SIZE on PyLongObject, adding asserts. * Change layout of size/sign bits in longobject to support future addition of immortal ints and tagged medium ints. * Add functions to hide some internals of long object, and for setting sign and digit count. * Replace uses of IS_MEDIUM_VALUE macro with _PyLong_IsCompact(). --- Include/cpython/longintrepr.h | 6 +- Include/internal/pycore_long.h | 164 ++++- Include/internal/pycore_object.h | 3 +- Include/internal/pycore_runtime_init.h | 10 +- Include/object.h | 8 +- ...-03-06-10-02-22.gh-issue-101291.0FT2QS.rst | 7 + Modules/_decimal/_decimal.c | 43 +- Modules/_testcapi/mem.c | 2 +- Modules/_tkinter.c | 7 +- Modules/mathmodule.c | 19 +- Objects/abstract.c | 3 +- Objects/boolobject.c | 9 +- Objects/listobject.c | 20 +- Objects/longobject.c | 694 ++++++++---------- Objects/rangeobject.c | 2 +- Objects/sliceobject.c | 6 +- Objects/typeobject.c | 3 +- Python/ast_opt.c | 13 +- Python/bltinmodule.c | 16 +- Python/bytecodes.c | 19 +- Python/generated_cases.c.h | 19 +- Python/marshal.c | 9 +- Python/specialize.c | 8 +- Tools/build/deepfreeze.py | 10 +- Tools/gdb/libpython.py | 26 +- 25 files changed, 605 insertions(+), 521 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst diff --git a/Include/cpython/longintrepr.h b/Include/cpython/longintrepr.h index 810daa83165e71..c4cf820da5e4f2 100644 --- a/Include/cpython/longintrepr.h +++ b/Include/cpython/longintrepr.h @@ -80,7 +80,7 @@ typedef long stwodigits; /* signed variant of twodigits */ */ typedef struct _PyLongValue { - Py_ssize_t ob_size; /* Number of items in variable part */ + uintptr_t lv_tag; /* Number of digits, sign and flags */ digit ob_digit[1]; } _PyLongValue; @@ -94,6 +94,10 @@ PyAPI_FUNC(PyLongObject *) _PyLong_New(Py_ssize_t); /* Return a copy of src. */ PyAPI_FUNC(PyObject *) _PyLong_Copy(PyLongObject *src); +PyAPI_FUNC(PyLongObject *) +_PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits); + + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 8c1d017bb95e4e..137a0465d5ec60 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -82,8 +82,6 @@ PyObject *_PyLong_Add(PyLongObject *left, PyLongObject *right); PyObject *_PyLong_Multiply(PyLongObject *left, PyLongObject *right); PyObject *_PyLong_Subtract(PyLongObject *left, PyLongObject *right); -int _PyLong_AssignValue(PyObject **target, Py_ssize_t value); - /* Used by Python/mystrtoul.c, _PyBytes_FromHex(), _PyBytes_DecodeEscape(), etc. */ PyAPI_DATA(unsigned char) _PyLong_DigitValue[256]; @@ -110,25 +108,155 @@ PyAPI_FUNC(char*) _PyLong_FormatBytesWriter( int base, int alternate); -/* Return 1 if the argument is positive single digit int */ +/* Long value tag bits: + * 0-1: Sign bits value = (1-sign), ie. negative=2, positive=0, zero=1. + * 2: Reserved for immortality bit + * 3+ Unsigned digit count + */ +#define SIGN_MASK 3 +#define SIGN_ZERO 1 +#define SIGN_NEGATIVE 2 +#define NON_SIZE_BITS 3 + +/* All *compact" values are guaranteed to fit into + * a Py_ssize_t with at least one bit to spare. + * In other words, for 64 bit machines, compact + * will be signed 63 (or fewer) bit values + */ + +/* Return 1 if the argument is compact int */ +static inline int +_PyLong_IsNonNegativeCompact(const PyLongObject* op) { + assert(PyLong_Check(op)); + return op->long_value.lv_tag <= (1 << NON_SIZE_BITS); +} + +static inline int +_PyLong_IsCompact(const PyLongObject* op) { + assert(PyLong_Check(op)); + return op->long_value.lv_tag < (2 << NON_SIZE_BITS); +} + static inline int -_PyLong_IsPositiveSingleDigit(PyObject* sub) { - /* For a positive single digit int, the value of Py_SIZE(sub) is 0 or 1. - - We perform a fast check using a single comparison by casting from int - to uint which casts negative numbers to large positive numbers. - For details see Section 14.2 "Bounds Checking" in the Agner Fog - optimization manual found at: - https://www.agner.org/optimize/optimizing_cpp.pdf - - The function is not affected by -fwrapv, -fno-wrapv and -ftrapv - compiler options of GCC and clang - */ - assert(PyLong_CheckExact(sub)); - Py_ssize_t signed_size = Py_SIZE(sub); - return ((size_t)signed_size) <= 1; +_PyLong_BothAreCompact(const PyLongObject* a, const PyLongObject* b) { + assert(PyLong_Check(a)); + assert(PyLong_Check(b)); + return (a->long_value.lv_tag | b->long_value.lv_tag) < (2 << NON_SIZE_BITS); +} + +/* Returns a *compact* value, iff `_PyLong_IsCompact` is true for `op`. + * + * "Compact" values have at least one bit to spare, + * so that addition and subtraction can be performed on the values + * without risk of overflow. + */ +static inline Py_ssize_t +_PyLong_CompactValue(const PyLongObject *op) +{ + assert(PyLong_Check(op)); + assert(_PyLong_IsCompact(op)); + Py_ssize_t sign = 1 - (op->long_value.lv_tag & SIGN_MASK); + return sign * (Py_ssize_t)op->long_value.ob_digit[0]; +} + +static inline bool +_PyLong_IsZero(const PyLongObject *op) +{ + return (op->long_value.lv_tag & SIGN_MASK) == SIGN_ZERO; +} + +static inline bool +_PyLong_IsNegative(const PyLongObject *op) +{ + return (op->long_value.lv_tag & SIGN_MASK) == SIGN_NEGATIVE; +} + +static inline bool +_PyLong_IsPositive(const PyLongObject *op) +{ + return (op->long_value.lv_tag & SIGN_MASK) == 0; +} + +static inline Py_ssize_t +_PyLong_DigitCount(const PyLongObject *op) +{ + assert(PyLong_Check(op)); + return op->long_value.lv_tag >> NON_SIZE_BITS; } +/* Equivalent to _PyLong_DigitCount(op) * _PyLong_NonCompactSign(op) */ +static inline Py_ssize_t +_PyLong_SignedDigitCount(const PyLongObject *op) +{ + assert(PyLong_Check(op)); + Py_ssize_t sign = 1 - (op->long_value.lv_tag & SIGN_MASK); + return sign * (Py_ssize_t)(op->long_value.lv_tag >> NON_SIZE_BITS); +} + +static inline int +_PyLong_CompactSign(const PyLongObject *op) +{ + assert(PyLong_Check(op)); + assert(_PyLong_IsCompact(op)); + return 1 - (op->long_value.lv_tag & SIGN_MASK); +} + +static inline int +_PyLong_NonCompactSign(const PyLongObject *op) +{ + assert(PyLong_Check(op)); + assert(!_PyLong_IsCompact(op)); + return 1 - (op->long_value.lv_tag & SIGN_MASK); +} + +/* Do a and b have the same sign? */ +static inline int +_PyLong_SameSign(const PyLongObject *a, const PyLongObject *b) +{ + return (a->long_value.lv_tag & SIGN_MASK) == (b->long_value.lv_tag & SIGN_MASK); +} + +#define TAG_FROM_SIGN_AND_SIZE(sign, size) ((1 - (sign)) | ((size) << NON_SIZE_BITS)) + +static inline void +_PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size) +{ + assert(size >= 0); + assert(-1 <= sign && sign <= 1); + assert(sign != 0 || size == 0); + op->long_value.lv_tag = TAG_FROM_SIGN_AND_SIZE(sign, (size_t)size); +} + +static inline void +_PyLong_SetDigitCount(PyLongObject *op, Py_ssize_t size) +{ + assert(size >= 0); + op->long_value.lv_tag = (((size_t)size) << NON_SIZE_BITS) | (op->long_value.lv_tag & SIGN_MASK); +} + +#define NON_SIZE_MASK ~((1 << NON_SIZE_BITS) - 1) + +static inline void +_PyLong_FlipSign(PyLongObject *op) { + unsigned int flipped_sign = 2 - (op->long_value.lv_tag & SIGN_MASK); + op->long_value.lv_tag &= NON_SIZE_MASK; + op->long_value.lv_tag |= flipped_sign; +} + +#define _PyLong_DIGIT_INIT(val) \ + { \ + .ob_base = _PyObject_IMMORTAL_INIT(&PyLong_Type), \ + .long_value = { \ + .lv_tag = TAG_FROM_SIGN_AND_SIZE( \ + (val) == 0 ? 0 : ((val) < 0 ? -1 : 1), \ + (val) == 0 ? 0 : 1), \ + { ((val) >= 0 ? (val) : -(val)) }, \ + } \ + } + +#define _PyLong_FALSE_TAG TAG_FROM_SIGN_AND_SIZE(0, 0) +#define _PyLong_TRUE_TAG TAG_FROM_SIGN_AND_SIZE(1, 1) + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index d6bbafd4b6cccc..e18e787449c257 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -137,8 +137,9 @@ static inline void _PyObject_InitVar(PyVarObject *op, PyTypeObject *typeobj, Py_ssize_t size) { assert(op != NULL); - Py_SET_SIZE(op, size); + assert(typeobj != &PyLong_Type); _PyObject_Init((PyObject *)op, typeobj); + Py_SET_SIZE(op, size); } diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index bdecac944dfd3a..7cfa7c0c02494a 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -8,6 +8,7 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +#include "pycore_long.h" #include "pycore_object.h" #include "pycore_parser.h" #include "pycore_pymem_init.h" @@ -130,15 +131,6 @@ extern PyTypeObject _PyExc_MemoryError; // global objects -#define _PyLong_DIGIT_INIT(val) \ - { \ - .ob_base = _PyObject_IMMORTAL_INIT(&PyLong_Type), \ - .long_value = { \ - ((val) == 0 ? 0 : ((val) > 0 ? 1 : -1)), \ - { ((val) >= 0 ? (val) : -(val)) }, \ - } \ - } - #define _PyBytes_SIMPLE_INIT(CH, LEN) \ { \ _PyVarObject_IMMORTAL_INIT(&PyBytes_Type, (LEN)), \ diff --git a/Include/object.h b/Include/object.h index fc577353c1cc13..2943a6066818cd 100644 --- a/Include/object.h +++ b/Include/object.h @@ -138,8 +138,13 @@ static inline PyTypeObject* Py_TYPE(PyObject *ob) { # define Py_TYPE(ob) Py_TYPE(_PyObject_CAST(ob)) #endif +PyAPI_DATA(PyTypeObject) PyLong_Type; +PyAPI_DATA(PyTypeObject) PyBool_Type; + // bpo-39573: The Py_SET_SIZE() function must be used to set an object size. static inline Py_ssize_t Py_SIZE(PyObject *ob) { + assert(ob->ob_type != &PyLong_Type); + assert(ob->ob_type != &PyBool_Type); PyVarObject *var_ob = _PyVarObject_CAST(ob); return var_ob->ob_size; } @@ -171,8 +176,9 @@ static inline void Py_SET_TYPE(PyObject *ob, PyTypeObject *type) { # define Py_SET_TYPE(ob, type) Py_SET_TYPE(_PyObject_CAST(ob), type) #endif - static inline void Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) { + assert(ob->ob_base.ob_type != &PyLong_Type); + assert(ob->ob_base.ob_type != &PyBool_Type); ob->ob_size = size; } #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst new file mode 100644 index 00000000000000..46f0f325f91630 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-06-10-02-22.gh-issue-101291.0FT2QS.rst @@ -0,0 +1,7 @@ +Rearrage bits in first field (after header) of PyLongObject. +* Bits 0 and 1: 1 - sign. I.e. 0 for positive numbers, 1 for zero and 2 for negative numbers. +* Bit 2 reserved (probably for the immortal bit) +* Bits 3+ the unsigned size. + +This makes a few operations slightly more efficient, and will enable a more +compact and faster 2s-complement representation of most ints in future. diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 5936fbaaf35eb0..0e11c879732ab6 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -30,6 +30,7 @@ #endif #include +#include "pycore_long.h" // _PyLong_IsZero() #include "pycore_pystate.h" // _PyThreadState_GET() #include "complexobject.h" #include "mpdecimal.h" @@ -2146,35 +2147,25 @@ dec_from_long(PyTypeObject *type, PyObject *v, { PyObject *dec; PyLongObject *l = (PyLongObject *)v; - Py_ssize_t ob_size; - size_t len; - uint8_t sign; dec = PyDecType_New(type); if (dec == NULL) { return NULL; } - ob_size = Py_SIZE(l); - if (ob_size == 0) { + if (_PyLong_IsZero(l)) { _dec_settriple(dec, MPD_POS, 0, 0); return dec; } - if (ob_size < 0) { - len = -ob_size; - sign = MPD_NEG; - } - else { - len = ob_size; - sign = MPD_POS; - } + uint8_t sign = _PyLong_IsNegative(l) ? MPD_NEG : MPD_POS; - if (len == 1) { - _dec_settriple(dec, sign, *l->long_value.ob_digit, 0); + if (_PyLong_IsCompact(l)) { + _dec_settriple(dec, sign, l->long_value.ob_digit[0], 0); mpd_qfinalize(MPD(dec), ctx, status); return dec; } + size_t len = _PyLong_DigitCount(l); #if PYLONG_BITS_IN_DIGIT == 30 mpd_qimport_u32(MPD(dec), l->long_value.ob_digit, len, sign, PyLong_BASE, @@ -3482,7 +3473,6 @@ dec_as_long(PyObject *dec, PyObject *context, int round) PyLongObject *pylong; digit *ob_digit; size_t n; - Py_ssize_t i; mpd_t *x; mpd_context_t workctx; uint32_t status = 0; @@ -3536,26 +3526,9 @@ dec_as_long(PyObject *dec, PyObject *context, int round) } assert(n > 0); - pylong = _PyLong_New(n); - if (pylong == NULL) { - mpd_free(ob_digit); - mpd_del(x); - return NULL; - } - - memcpy(pylong->long_value.ob_digit, ob_digit, n * sizeof(digit)); + assert(!mpd_iszero(x)); + pylong = _PyLong_FromDigits(mpd_isnegative(x), n, ob_digit); mpd_free(ob_digit); - - i = n; - while ((i > 0) && (pylong->long_value.ob_digit[i-1] == 0)) { - i--; - } - - Py_SET_SIZE(pylong, i); - if (mpd_isnegative(x) && !mpd_iszero(x)) { - Py_SET_SIZE(pylong, -i); - } - mpd_del(x); return (PyObject *) pylong; } diff --git a/Modules/_testcapi/mem.c b/Modules/_testcapi/mem.c index ae3f7a4372dcd8..af32e9668dda2d 100644 --- a/Modules/_testcapi/mem.c +++ b/Modules/_testcapi/mem.c @@ -347,7 +347,7 @@ test_pyobject_new(PyObject *self, PyObject *Py_UNUSED(ignored)) { PyObject *obj; PyTypeObject *type = &PyBaseObject_Type; - PyTypeObject *var_type = &PyLong_Type; + PyTypeObject *var_type = &PyBytes_Type; // PyObject_New() obj = PyObject_New(PyObject, type); diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 1608939766ffb6..606e578a1f3116 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -32,6 +32,8 @@ Copyright (C) 1994 Steen Lumholt. # include "pycore_fileutils.h" // _Py_stat() #endif +#include "pycore_long.h" + #ifdef MS_WINDOWS #include #endif @@ -886,7 +888,8 @@ asBignumObj(PyObject *value) const char *hexchars; mp_int bigValue; - neg = Py_SIZE(value) < 0; + assert(PyLong_Check(value)); + neg = _PyLong_IsNegative((PyLongObject *)value); hexstr = _PyLong_Format(value, 16); if (hexstr == NULL) return NULL; @@ -1950,7 +1953,7 @@ _tkinter_tkapp_getboolean(TkappObject *self, PyObject *arg) int v; if (PyLong_Check(arg)) { /* int or bool */ - return PyBool_FromLong(Py_SIZE(arg) != 0); + return PyBool_FromLong(!_PyLong_IsZero((PyLongObject *)arg)); } if (PyTclObject_Check(arg)) { diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 473936edb3f5cd..eddc1a33a953e6 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -836,7 +836,7 @@ long_lcm(PyObject *a, PyObject *b) { PyObject *g, *m, *f, *ab; - if (Py_SIZE(a) == 0 || Py_SIZE(b) == 0) { + if (_PyLong_IsZero((PyLongObject *)a) || _PyLong_IsZero((PyLongObject *)b)) { return PyLong_FromLong(0); } g = _PyLong_GCD(a, b); @@ -1726,13 +1726,13 @@ math_isqrt(PyObject *module, PyObject *n) return NULL; } - if (_PyLong_Sign(n) < 0) { + if (_PyLong_IsNegative((PyLongObject *)n)) { PyErr_SetString( PyExc_ValueError, "isqrt() argument must be nonnegative"); goto error; } - if (_PyLong_Sign(n) == 0) { + if (_PyLong_IsZero((PyLongObject *)n)) { Py_DECREF(n); return PyLong_FromLong(0); } @@ -2254,7 +2254,7 @@ loghelper(PyObject* arg, double (*func)(double)) Py_ssize_t e; /* Negative or zero inputs give a ValueError. */ - if (Py_SIZE(arg) <= 0) { + if (!_PyLong_IsPositive((PyLongObject *)arg)) { PyErr_SetString(PyExc_ValueError, "math domain error"); return NULL; @@ -3716,12 +3716,12 @@ math_perm_impl(PyObject *module, PyObject *n, PyObject *k) } assert(PyLong_CheckExact(n) && PyLong_CheckExact(k)); - if (Py_SIZE(n) < 0) { + if (_PyLong_IsNegative((PyLongObject *)n)) { PyErr_SetString(PyExc_ValueError, "n must be a non-negative integer"); goto error; } - if (Py_SIZE(k) < 0) { + if (_PyLong_IsNegative((PyLongObject *)k)) { PyErr_SetString(PyExc_ValueError, "k must be a non-negative integer"); goto error; @@ -3808,12 +3808,12 @@ math_comb_impl(PyObject *module, PyObject *n, PyObject *k) } assert(PyLong_CheckExact(n) && PyLong_CheckExact(k)); - if (Py_SIZE(n) < 0) { + if (_PyLong_IsNegative((PyLongObject *)n)) { PyErr_SetString(PyExc_ValueError, "n must be a non-negative integer"); goto error; } - if (Py_SIZE(k) < 0) { + if (_PyLong_IsNegative((PyLongObject *)k)) { PyErr_SetString(PyExc_ValueError, "k must be a non-negative integer"); goto error; @@ -3845,7 +3845,8 @@ math_comb_impl(PyObject *module, PyObject *n, PyObject *k) if (temp == NULL) { goto error; } - if (Py_SIZE(temp) < 0) { + assert(PyLong_Check(temp)); + if (_PyLong_IsNegative((PyLongObject *)temp)) { Py_DECREF(temp); result = PyLong_FromLong(0); goto done; diff --git a/Objects/abstract.c b/Objects/abstract.c index 9dc74fb9c2608c..e95785900c9c5f 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -5,6 +5,7 @@ #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate() #include "pycore_object.h" // _Py_CheckSlotResult() +#include "pycore_long.h" // _Py_IsNegative #include "pycore_pyerrors.h" // _PyErr_Occurred() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_unionobject.h" // _PyUnion_Check() @@ -1483,7 +1484,7 @@ PyNumber_AsSsize_t(PyObject *item, PyObject *err) /* Whether or not it is less than or equal to zero is determined by the sign of ob_size */ - if (_PyLong_Sign(value) < 0) + if (_PyLong_IsNegative((PyLongObject *)value)) result = PY_SSIZE_T_MIN; else result = PY_SSIZE_T_MAX; diff --git a/Objects/boolobject.c b/Objects/boolobject.c index a035f463323823..9d8e956e06f712 100644 --- a/Objects/boolobject.c +++ b/Objects/boolobject.c @@ -2,6 +2,7 @@ #include "Python.h" #include "pycore_object.h" // _Py_FatalRefcountError() +#include "pycore_long.h" // FALSE_TAG TRUE_TAG #include "pycore_runtime.h" // _Py_ID() #include @@ -198,10 +199,14 @@ PyTypeObject PyBool_Type = { struct _longobject _Py_FalseStruct = { PyObject_HEAD_INIT(&PyBool_Type) - { 0, { 0 } } + { .lv_tag = _PyLong_FALSE_TAG, + { 0 } + } }; struct _longobject _Py_TrueStruct = { PyObject_HEAD_INIT(&PyBool_Type) - { 1, { 1 } } + { .lv_tag = _PyLong_TRUE_TAG, + { 1 } + } }; diff --git a/Objects/listobject.c b/Objects/listobject.c index 1a210e77d55c29..f1edfb3a9a039d 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -4,6 +4,7 @@ #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_interp.h" // PyInterpreterState.list #include "pycore_list.h" // struct _Py_list_state, _PyListIterObject +#include "pycore_long.h" // _PyLong_DigitCount #include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_tuple.h" // _PyTuple_FromArray() #include @@ -2144,24 +2145,21 @@ unsafe_latin_compare(PyObject *v, PyObject *w, MergeState *ms) static int unsafe_long_compare(PyObject *v, PyObject *w, MergeState *ms) { - PyLongObject *vl, *wl; sdigit v0, w0; int res; + PyLongObject *vl, *wl; + intptr_t v0, w0; + int res; /* Modified from Objects/longobject.c:long_compare, assuming: */ assert(Py_IS_TYPE(v, &PyLong_Type)); assert(Py_IS_TYPE(w, &PyLong_Type)); - assert(Py_ABS(Py_SIZE(v)) <= 1); - assert(Py_ABS(Py_SIZE(w)) <= 1); + assert(_PyLong_IsCompact((PyLongObject *)v)); + assert(_PyLong_IsCompact((PyLongObject *)w)); vl = (PyLongObject*)v; wl = (PyLongObject*)w; - v0 = Py_SIZE(vl) == 0 ? 0 : (sdigit)vl->long_value.ob_digit[0]; - w0 = Py_SIZE(wl) == 0 ? 0 : (sdigit)wl->long_value.ob_digit[0]; - - if (Py_SIZE(vl) < 0) - v0 = -v0; - if (Py_SIZE(wl) < 0) - w0 = -w0; + v0 = _PyLong_CompactValue(vl); + w0 = _PyLong_CompactValue(wl); res = v0 < w0; assert(res == PyObject_RichCompareBool(v, w, Py_LT)); @@ -2359,7 +2357,7 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse) if (keys_are_all_same_type) { if (key_type == &PyLong_Type && ints_are_bounded && - Py_ABS(Py_SIZE(key)) > 1) { + !_PyLong_IsCompact((PyLongObject *)key)) { ints_are_bounded = 0; } diff --git a/Objects/longobject.c b/Objects/longobject.c index 51655cd0bad9ec..bb4eac0d932bb8 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -6,7 +6,7 @@ #include "pycore_bitutils.h" // _Py_popcount32() #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_long.h" // _Py_SmallInts -#include "pycore_object.h" // _PyObject_InitVar() +#include "pycore_object.h" // _PyObject_Init() #include "pycore_pystate.h" // _Py_IsMainInterpreter() #include "pycore_runtime.h" // _PY_NSMALLPOSINTS #include "pycore_structseq.h" // _PyStructSequence_FiniType() @@ -22,16 +22,7 @@ class int "PyObject *" "&PyLong_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=ec0275e3422a36e3]*/ -/* Is this PyLong of size 1, 0 or -1? */ -#define IS_MEDIUM_VALUE(x) (((size_t)Py_SIZE(x)) + 1U < 3U) - -/* convert a PyLong of size 1, 0 or -1 to a C integer */ -static inline stwodigits -medium_value(PyLongObject *x) -{ - assert(IS_MEDIUM_VALUE(x)); - return ((stwodigits)Py_SIZE(x)) * x->long_value.ob_digit[0]; -} +#define medium_value(x) ((stwodigits)_PyLong_CompactValue(x)) #define IS_SMALL_INT(ival) (-_PY_NSMALLNEGINTS <= (ival) && (ival) < _PY_NSMALLPOSINTS) #define IS_SMALL_UINT(ival) ((ival) < _PY_NSMALLPOSINTS) @@ -68,7 +59,7 @@ get_small_int(sdigit ival) static PyLongObject * maybe_small_long(PyLongObject *v) { - if (v && IS_MEDIUM_VALUE(v)) { + if (v && _PyLong_IsCompact(v)) { stwodigits ival = medium_value(v); if (IS_SMALL_INT(ival)) { _Py_DECREF_INT(v); @@ -126,13 +117,18 @@ maybe_small_long(PyLongObject *v) static PyLongObject * long_normalize(PyLongObject *v) { - Py_ssize_t j = Py_ABS(Py_SIZE(v)); + Py_ssize_t j = _PyLong_DigitCount(v); Py_ssize_t i = j; while (i > 0 && v->long_value.ob_digit[i-1] == 0) --i; if (i != j) { - Py_SET_SIZE(v, (Py_SIZE(v) < 0) ? -(i) : i); + if (i == 0) { + _PyLong_SetSignAndDigitCount(v, 0, 0); + } + else { + _PyLong_SetDigitCount(v, i); + } } return v; } @@ -146,6 +142,7 @@ long_normalize(PyLongObject *v) PyLongObject * _PyLong_New(Py_ssize_t size) { + assert(size >= 0); PyLongObject *result; if (size > (Py_ssize_t)MAX_LONG_DIGITS) { PyErr_SetString(PyExc_OverflowError, @@ -157,8 +154,8 @@ _PyLong_New(Py_ssize_t size) Py_ssize_t ndigits = size ? size : 1; /* Number of bytes needed is: offsetof(PyLongObject, ob_digit) + sizeof(digit)*size. Previous incarnations of this code used - sizeof(PyVarObject) instead of the offsetof, but this risks being - incorrect in the presence of padding between the PyVarObject header + sizeof() instead of the offsetof, but this risks being + incorrect in the presence of padding between the header and the digits. */ result = PyObject_Malloc(offsetof(PyLongObject, long_value.ob_digit) + ndigits*sizeof(digit)); @@ -166,34 +163,41 @@ _PyLong_New(Py_ssize_t size) PyErr_NoMemory(); return NULL; } - _PyObject_InitVar((PyVarObject*)result, &PyLong_Type, size); + _PyLong_SetSignAndDigitCount(result, size != 0, size); + _PyObject_Init((PyObject*)result, &PyLong_Type); + return result; +} + +PyLongObject * +_PyLong_FromDigits(int negative, Py_ssize_t digit_count, digit *digits) +{ + assert(digit_count >= 0); + if (digit_count == 0) { + return (PyLongObject *)Py_NewRef(_PyLong_GetZero()); + } + PyLongObject *result = _PyLong_New(digit_count); + if (result == NULL) { + PyErr_NoMemory(); + return NULL; + } + _PyLong_SetSignAndDigitCount(result, negative?-1:1, digit_count); + memcpy(result->long_value.ob_digit, digits, digit_count * sizeof(digit)); return result; } PyObject * _PyLong_Copy(PyLongObject *src) { - PyLongObject *result; - Py_ssize_t i; - assert(src != NULL); - i = Py_SIZE(src); - if (i < 0) - i = -(i); - if (i < 2) { + + if (_PyLong_IsCompact(src)) { stwodigits ival = medium_value(src); if (IS_SMALL_INT(ival)) { return get_small_int((sdigit)ival); } } - result = _PyLong_New(i); - if (result != NULL) { - Py_SET_SIZE(result, Py_SIZE(src)); - while (--i >= 0) { - result->long_value.ob_digit[i] = src->long_value.ob_digit[i]; - } - } - return (PyObject *)result; + Py_ssize_t size = _PyLong_DigitCount(src); + return (PyObject *)_PyLong_FromDigits(_PyLong_IsNegative(src), size, src->long_value.ob_digit); } static PyObject * @@ -207,9 +211,9 @@ _PyLong_FromMedium(sdigit x) PyErr_NoMemory(); return NULL; } - Py_ssize_t sign = x < 0 ? -1: 1; digit abs_x = x < 0 ? -x : x; - _PyObject_InitVar((PyVarObject*)v, &PyLong_Type, sign); + _PyLong_SetSignAndDigitCount(v, x<0?-1:1, 1); + _PyObject_Init((PyObject*)v, &PyLong_Type); v->long_value.ob_digit[0] = abs_x; return (PyObject*)v; } @@ -242,7 +246,7 @@ _PyLong_FromLarge(stwodigits ival) PyLongObject *v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - Py_SET_SIZE(v, ndigits * sign); + _PyLong_SetSignAndDigitCount(v, sign, ndigits); t = abs_ival; while (t) { *p++ = Py_SAFE_DOWNCAST( @@ -267,38 +271,6 @@ _PyLong_FromSTwoDigits(stwodigits x) return _PyLong_FromLarge(x); } -int -_PyLong_AssignValue(PyObject **target, Py_ssize_t value) -{ - PyObject *old = *target; - if (IS_SMALL_INT(value)) { - *target = get_small_int(Py_SAFE_DOWNCAST(value, Py_ssize_t, sdigit)); - Py_XDECREF(old); - return 0; - } - else if (old != NULL && PyLong_CheckExact(old) && - Py_REFCNT(old) == 1 && Py_SIZE(old) == 1 && - (size_t)value <= PyLong_MASK) - { - // Mutate in place if there are no other references the old - // object. This avoids an allocation in a common case. - // Since the primary use-case is iterating over ranges, which - // are typically positive, only do this optimization - // for positive integers (for now). - ((PyLongObject *)old)->long_value.ob_digit[0] = - Py_SAFE_DOWNCAST(value, Py_ssize_t, digit); - return 0; - } - else { - *target = PyLong_FromSsize_t(value); - Py_XDECREF(old); - if (*target == NULL) { - return -1; - } - return 0; - } -} - /* If a freshly-allocated int is already shared, it must be a small integer, so negating it must go to PyLong_FromLong */ Py_LOCAL_INLINE(void) @@ -308,7 +280,7 @@ _PyLong_Negate(PyLongObject **x_p) x = (PyLongObject *)*x_p; if (Py_REFCNT(x) == 1) { - Py_SET_SIZE(x, -Py_SIZE(x)); + _PyLong_FlipSign(x); return; } @@ -347,7 +319,7 @@ PyLong_FromLong(long ival) v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - Py_SET_SIZE(v, ival < 0 ? -ndigits : ndigits); + _PyLong_SetSignAndDigitCount(v, ival < 0 ? -1 : 1, ndigits); t = abs_ival; while (t) { *p++ = (digit)(t & PyLong_MASK); @@ -457,7 +429,7 @@ PyLong_FromDouble(double dval) frac = ldexp(frac, PyLong_SHIFT); } if (neg) { - Py_SET_SIZE(v, -(Py_SIZE(v))); + _PyLong_FlipSign(v); } return (PyObject *)v; } @@ -510,27 +482,22 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) return -1; do_decref = 1; } - - res = -1; - i = Py_SIZE(v); - - switch (i) { - case -1: - res = -(sdigit)v->long_value.ob_digit[0]; - break; - case 0: - res = 0; - break; - case 1: - res = v->long_value.ob_digit[0]; - break; - default: - sign = 1; - x = 0; - if (i < 0) { - sign = -1; - i = -(i); + if (_PyLong_IsCompact(v)) { +#if SIZEOF_LONG < SIZEOF_VOID_P + intptr_t tmp = _PyLong_CompactValue(v); + res = (long)tmp; + if (res != tmp) { + *overflow = tmp < 0 ? -1 : 1; } +#else + res = _PyLong_CompactValue(v); +#endif + } + else { + res = -1; + i = _PyLong_DigitCount(v); + sign = _PyLong_NonCompactSign(v); + x = 0; while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; @@ -540,8 +507,8 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) } } /* Haven't lost any bits, but casting to long requires extra - * care (see comment above). - */ + * care (see comment above). + */ if (x <= (unsigned long)LONG_MAX) { res = (long)x * sign; } @@ -615,18 +582,12 @@ PyLong_AsSsize_t(PyObject *vv) { } v = (PyLongObject *)vv; - i = Py_SIZE(v); - switch (i) { - case -1: return -(sdigit)v->long_value.ob_digit[0]; - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; + if (_PyLong_IsCompact(v)) { + return _PyLong_CompactValue(v); } - sign = 1; + i = _PyLong_DigitCount(v); + sign = _PyLong_NonCompactSign(v); x = 0; - if (i < 0) { - sign = -1; - i = -(i); - } while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; @@ -670,28 +631,37 @@ PyLong_AsUnsignedLong(PyObject *vv) } v = (PyLongObject *)vv; - i = Py_SIZE(v); - x = 0; - if (i < 0) { + if (_PyLong_IsNonNegativeCompact(v)) { +#if SIZEOF_LONG < SIZEOF_VOID_P + intptr_t tmp = _PyLong_CompactValue(v); + unsigned long res = (unsigned long)tmp; + if (res != tmp) { + goto overflow; + } +#else + return _PyLong_CompactValue(v); +#endif + } + if (_PyLong_IsNegative(v)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to unsigned int"); return (unsigned long) -1; } - switch (i) { - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; - } + i = _PyLong_DigitCount(v); + x = 0; while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; if ((x >> PyLong_SHIFT) != prev) { - PyErr_SetString(PyExc_OverflowError, - "Python int too large to convert " - "to C unsigned long"); - return (unsigned long) -1; + goto overflow; } } return x; +overflow: + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert " + "to C unsigned long"); + return (unsigned long) -1; } /* Get a C size_t from an int object. Returns (size_t)-1 and sets @@ -714,17 +684,16 @@ PyLong_AsSize_t(PyObject *vv) } v = (PyLongObject *)vv; - i = Py_SIZE(v); - x = 0; - if (i < 0) { + if (_PyLong_IsNonNegativeCompact(v)) { + return _PyLong_CompactValue(v); + } + if (_PyLong_IsNegative(v)) { PyErr_SetString(PyExc_OverflowError, "can't convert negative value to size_t"); return (size_t) -1; } - switch (i) { - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; - } + i = _PyLong_DigitCount(v); + x = 0; while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; @@ -746,24 +715,18 @@ _PyLong_AsUnsignedLongMask(PyObject *vv) PyLongObject *v; unsigned long x; Py_ssize_t i; - int sign; if (vv == NULL || !PyLong_Check(vv)) { PyErr_BadInternalCall(); return (unsigned long) -1; } v = (PyLongObject *)vv; - i = Py_SIZE(v); - switch (i) { - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; + if (_PyLong_IsCompact(v)) { + return (unsigned long)_PyLong_CompactValue(v); } - sign = 1; + i = _PyLong_DigitCount(v); + int sign = _PyLong_NonCompactSign(v); x = 0; - if (i < 0) { - sign = -1; - i = -i; - } while (--i >= 0) { x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; } @@ -801,8 +764,10 @@ _PyLong_Sign(PyObject *vv) assert(v != NULL); assert(PyLong_Check(v)); - - return Py_SIZE(v) == 0 ? 0 : (Py_SIZE(v) < 0 ? -1 : 1); + if (_PyLong_IsCompact(v)) { + return _PyLong_CompactSign(v); + } + return _PyLong_NonCompactSign(v); } static int @@ -825,7 +790,7 @@ _PyLong_NumBits(PyObject *vv) assert(v != NULL); assert(PyLong_Check(v)); - ndigits = Py_ABS(Py_SIZE(v)); + ndigits = _PyLong_DigitCount(v); assert(ndigits == 0 || v->long_value.ob_digit[ndigits - 1] != 0); if (ndigits > 0) { digit msd = v->long_value.ob_digit[ndigits - 1]; @@ -952,7 +917,11 @@ _PyLong_FromByteArray(const unsigned char* bytes, size_t n, } } - Py_SET_SIZE(v, is_signed ? -idigit : idigit); + int sign = is_signed ? -1: 1; + if (idigit == 0) { + sign = 0; + } + _PyLong_SetSignAndDigitCount(v, sign, idigit); return (PyObject *)maybe_small_long(long_normalize(v)); } @@ -962,7 +931,7 @@ _PyLong_AsByteArray(PyLongObject* v, int little_endian, int is_signed) { Py_ssize_t i; /* index into v->long_value.ob_digit */ - Py_ssize_t ndigits; /* |v->ob_size| */ + Py_ssize_t ndigits; /* number of digits */ twodigits accum; /* sliding register */ unsigned int accumbits; /* # bits in accum */ int do_twos_comp; /* store 2's-comp? is_signed and v < 0 */ @@ -973,8 +942,8 @@ _PyLong_AsByteArray(PyLongObject* v, assert(v != NULL && PyLong_Check(v)); - if (Py_SIZE(v) < 0) { - ndigits = -(Py_SIZE(v)); + ndigits = _PyLong_DigitCount(v); + if (_PyLong_IsNegative(v)) { if (!is_signed) { PyErr_SetString(PyExc_OverflowError, "can't convert negative int to unsigned"); @@ -983,7 +952,6 @@ _PyLong_AsByteArray(PyLongObject* v, do_twos_comp = 1; } else { - ndigits = Py_SIZE(v); do_twos_comp = 0; } @@ -1114,10 +1082,12 @@ PyLong_AsVoidPtr(PyObject *vv) #if SIZEOF_VOID_P <= SIZEOF_LONG long x; - if (PyLong_Check(vv) && _PyLong_Sign(vv) < 0) + if (PyLong_Check(vv) && _PyLong_IsNegative((PyLongObject *)vv)) { x = PyLong_AsLong(vv); - else + } + else { x = PyLong_AsUnsignedLong(vv); + } #else #if SIZEOF_LONG_LONG < SIZEOF_VOID_P @@ -1125,10 +1095,12 @@ PyLong_AsVoidPtr(PyObject *vv) #endif long long x; - if (PyLong_Check(vv) && _PyLong_Sign(vv) < 0) + if (PyLong_Check(vv) && _PyLong_IsNegative((PyLongObject *)vv)) { x = PyLong_AsLongLong(vv); - else + } + else { x = PyLong_AsUnsignedLongLong(vv); + } #endif /* SIZEOF_VOID_P <= SIZEOF_LONG */ @@ -1174,7 +1146,7 @@ PyLong_FromLongLong(long long ival) v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - Py_SET_SIZE(v, ival < 0 ? -ndigits : ndigits); + _PyLong_SetSignAndDigitCount(v, ival < 0 ? -1 : 1, ndigits); t = abs_ival; while (t) { *p++ = (digit)(t & PyLong_MASK); @@ -1217,7 +1189,7 @@ PyLong_FromSsize_t(Py_ssize_t ival) v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->long_value.ob_digit; - Py_SET_SIZE(v, negative ? -ndigits : ndigits); + _PyLong_SetSignAndDigitCount(v, negative ? -1 : 1, ndigits); t = abs_ival; while (t) { *p++ = (digit)(t & PyLong_MASK); @@ -1253,18 +1225,11 @@ PyLong_AsLongLong(PyObject *vv) do_decref = 1; } - res = 0; - switch(Py_SIZE(v)) { - case -1: - bytes = -(sdigit)v->long_value.ob_digit[0]; - break; - case 0: - bytes = 0; - break; - case 1: - bytes = v->long_value.ob_digit[0]; - break; - default: + if (_PyLong_IsCompact(v)) { + res = 0; + bytes = _PyLong_CompactValue(v); + } + else { res = _PyLong_AsByteArray((PyLongObject *)v, (unsigned char *)&bytes, SIZEOF_LONG_LONG, PY_LITTLE_ENDIAN, 1); } @@ -1299,13 +1264,14 @@ PyLong_AsUnsignedLongLong(PyObject *vv) } v = (PyLongObject*)vv; - switch(Py_SIZE(v)) { - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; + if (_PyLong_IsNonNegativeCompact(v)) { + res = 0; + bytes = _PyLong_CompactValue(v); } - - res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes, + else { + res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes, SIZEOF_LONG_LONG, PY_LITTLE_ENDIAN, 0); + } /* Plan 9 can't handle long long in ? : expressions */ if (res < 0) @@ -1330,17 +1296,12 @@ _PyLong_AsUnsignedLongLongMask(PyObject *vv) return (unsigned long long) -1; } v = (PyLongObject *)vv; - switch(Py_SIZE(v)) { - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; + if (_PyLong_IsCompact(v)) { + return (unsigned long long)(signed long long)_PyLong_CompactValue(v); } - i = Py_SIZE(v); - sign = 1; + i = _PyLong_DigitCount(v); + sign = _PyLong_NonCompactSign(v); x = 0; - if (i < 0) { - sign = -1; - i = -i; - } while (--i >= 0) { x = (x << PyLong_SHIFT) | v->long_value.ob_digit[i]; } @@ -1407,32 +1368,19 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow) return -1; do_decref = 1; } - - res = -1; - i = Py_SIZE(v); - - switch (i) { - case -1: - res = -(sdigit)v->long_value.ob_digit[0]; - break; - case 0: - res = 0; - break; - case 1: - res = v->long_value.ob_digit[0]; - break; - default: - sign = 1; + if (_PyLong_IsCompact(v)) { + res = _PyLong_CompactValue(v); + } + else { + i = _PyLong_DigitCount(v); + sign = _PyLong_NonCompactSign(v); x = 0; - if (i < 0) { - sign = -1; - i = -(i); - } while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) + v->long_value.ob_digit[i]; if ((x >> PyLong_SHIFT) != prev) { *overflow = sign; + res = -1; goto exit; } } @@ -1447,7 +1395,7 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow) } else { *overflow = sign; - /* res is already set to -1 */ + res = -1; } } exit: @@ -1462,7 +1410,7 @@ _PyLong_UnsignedShort_Converter(PyObject *obj, void *ptr) { unsigned long uval; - if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) { + if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) { PyErr_SetString(PyExc_ValueError, "value must be positive"); return 0; } @@ -1484,7 +1432,7 @@ _PyLong_UnsignedInt_Converter(PyObject *obj, void *ptr) { unsigned long uval; - if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) { + if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) { PyErr_SetString(PyExc_ValueError, "value must be positive"); return 0; } @@ -1506,7 +1454,7 @@ _PyLong_UnsignedLong_Converter(PyObject *obj, void *ptr) { unsigned long uval; - if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) { + if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) { PyErr_SetString(PyExc_ValueError, "value must be positive"); return 0; } @@ -1523,7 +1471,7 @@ _PyLong_UnsignedLongLong_Converter(PyObject *obj, void *ptr) { unsigned long long uval; - if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) { + if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) { PyErr_SetString(PyExc_ValueError, "value must be positive"); return 0; } @@ -1540,7 +1488,7 @@ _PyLong_Size_t_Converter(PyObject *obj, void *ptr) { size_t uval; - if (PyLong_Check(obj) && _PyLong_Sign(obj) < 0) { + if (PyLong_Check(obj) && _PyLong_IsNegative((PyLongObject *)obj)) { PyErr_SetString(PyExc_ValueError, "value must be positive"); return 0; } @@ -1694,7 +1642,7 @@ inplace_divrem1(digit *pout, digit *pin, Py_ssize_t size, digit n) static PyLongObject * divrem1(PyLongObject *a, digit n, digit *prem) { - const Py_ssize_t size = Py_ABS(Py_SIZE(a)); + const Py_ssize_t size = _PyLong_DigitCount(a); PyLongObject *z; assert(n > 0 && n <= PyLong_MASK); @@ -1726,7 +1674,7 @@ inplace_rem1(digit *pin, Py_ssize_t size, digit n) static PyLongObject * rem1(PyLongObject *a, digit n) { - const Py_ssize_t size = Py_ABS(Py_SIZE(a)); + const Py_ssize_t size = _PyLong_DigitCount(a); assert(n > 0 && n <= PyLong_MASK); return (PyLongObject *)PyLong_FromLong( @@ -1824,8 +1772,8 @@ long_to_decimal_string_internal(PyObject *aa, PyErr_BadInternalCall(); return -1; } - size_a = Py_ABS(Py_SIZE(a)); - negative = Py_SIZE(a) < 0; + size_a = _PyLong_DigitCount(a); + negative = _PyLong_IsNegative(a); /* quick and dirty pre-check for overflowing the decimal digit limit, based on the inequality 10/3 >= log2(10) @@ -2055,8 +2003,8 @@ long_format_binary(PyObject *aa, int base, int alternate, PyErr_BadInternalCall(); return -1; } - size_a = Py_ABS(Py_SIZE(a)); - negative = Py_SIZE(a) < 0; + size_a = _PyLong_DigitCount(a); + negative = _PyLong_IsNegative(a); /* Compute a rough upper bound for the length of the string */ switch (base) { @@ -2532,7 +2480,7 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, *res = NULL; return 0; } - Py_SET_SIZE(z, 0); + _PyLong_SetSignAndDigitCount(z, 0, 0); /* `convwidth` consecutive input digits are treated as a single * digit in base `convmultmax`. @@ -2572,7 +2520,7 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, /* Multiply z by convmult, and add c. */ pz = z->long_value.ob_digit; - pzstop = pz + Py_SIZE(z); + pzstop = pz + _PyLong_DigitCount(z); for (; pz < pzstop; ++pz) { c += (twodigits)*pz * convmult; *pz = (digit)(c & PyLong_MASK); @@ -2581,14 +2529,15 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits, /* carry off the current end? */ if (c) { assert(c < PyLong_BASE); - if (Py_SIZE(z) < size_z) { + if (_PyLong_DigitCount(z) < size_z) { *pz = (digit)c; - Py_SET_SIZE(z, Py_SIZE(z) + 1); + assert(!_PyLong_IsNegative(z)); + _PyLong_SetSignAndDigitCount(z, 1, _PyLong_DigitCount(z) + 1); } else { PyLongObject *tmp; /* Extremely rare. Get more space. */ - assert(Py_SIZE(z) == size_z); + assert(_PyLong_DigitCount(z) == size_z); tmp = _PyLong_New(size_z + 1); if (tmp == NULL) { Py_DECREF(z); @@ -2790,7 +2739,7 @@ PyLong_FromString(const char *str, char **pend, int base) /* reset the base to 0, else the exception message doesn't make too much sense */ base = 0; - if (Py_SIZE(z) != 0) { + if (!_PyLong_IsZero(z)) { goto onError; } /* there might still be other problems, therefore base @@ -2799,7 +2748,7 @@ PyLong_FromString(const char *str, char **pend, int base) /* Set sign and normalize */ if (sign < 0) { - Py_SET_SIZE(z, -(Py_SIZE(z))); + _PyLong_FlipSign(z); } long_normalize(z); z = maybe_small_long(z); @@ -2891,7 +2840,7 @@ static int long_divrem(PyLongObject *a, PyLongObject *b, PyLongObject **pdiv, PyLongObject **prem) { - Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b)); + Py_ssize_t size_a = _PyLong_DigitCount(a), size_b = _PyLong_DigitCount(b); PyLongObject *z; if (size_b == 0) { @@ -2932,14 +2881,14 @@ long_divrem(PyLongObject *a, PyLongObject *b, The quotient z has the sign of a*b; the remainder r has the sign of a, so a = b*z + r. */ - if ((Py_SIZE(a) < 0) != (Py_SIZE(b) < 0)) { + if ((_PyLong_IsNegative(a)) != (_PyLong_IsNegative(b))) { _PyLong_Negate(&z); if (z == NULL) { Py_CLEAR(*prem); return -1; } } - if (Py_SIZE(a) < 0 && Py_SIZE(*prem) != 0) { + if (_PyLong_IsNegative(a) && !_PyLong_IsZero(*prem)) { _PyLong_Negate(prem); if (*prem == NULL) { Py_DECREF(z); @@ -2956,7 +2905,7 @@ long_divrem(PyLongObject *a, PyLongObject *b, static int long_rem(PyLongObject *a, PyLongObject *b, PyLongObject **prem) { - Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b)); + Py_ssize_t size_a = _PyLong_DigitCount(a), size_b = _PyLong_DigitCount(b); if (size_b == 0) { PyErr_SetString(PyExc_ZeroDivisionError, @@ -2983,7 +2932,7 @@ long_rem(PyLongObject *a, PyLongObject *b, PyLongObject **prem) return -1; } /* Set the sign. */ - if (Py_SIZE(a) < 0 && Py_SIZE(*prem) != 0) { + if (_PyLong_IsNegative(a) && !_PyLong_IsZero(*prem)) { _PyLong_Negate(prem); if (*prem == NULL) { Py_CLEAR(*prem); @@ -2994,7 +2943,7 @@ long_rem(PyLongObject *a, PyLongObject *b, PyLongObject **prem) } /* Unsigned int division with remainder -- the algorithm. The arguments v1 - and w1 should satisfy 2 <= Py_ABS(Py_SIZE(w1)) <= Py_ABS(Py_SIZE(v1)). */ + and w1 should satisfy 2 <= _PyLong_DigitCount(w1) <= _PyLong_DigitCount(v1). */ static PyLongObject * x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem) @@ -3014,8 +2963,8 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem) that won't overflow a digit. */ /* allocate space; w will also be used to hold the final remainder */ - size_v = Py_ABS(Py_SIZE(v1)); - size_w = Py_ABS(Py_SIZE(w1)); + size_v = _PyLong_DigitCount(v1); + size_w = _PyLong_DigitCount(w1); assert(size_v >= size_w && size_w >= 2); /* Assert checks by div() */ v = _PyLong_New(size_v+1); if (v == NULL) { @@ -3154,7 +3103,7 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e) multiple of 4, rounding ties to a multiple of 8. */ static const int half_even_correction[8] = {0, -1, -2, 1, 0, -1, 2, 1}; - a_size = Py_ABS(Py_SIZE(a)); + a_size = _PyLong_DigitCount(a); if (a_size == 0) { /* Special case for 0: significand 0.0, exponent 0. */ *e = 0; @@ -3240,7 +3189,7 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e) } *e = a_bits; - return Py_SIZE(a) < 0 ? -dx : dx; + return _PyLong_IsNegative(a) ? -dx : dx; overflow: /* exponent > PY_SSIZE_T_MAX */ @@ -3267,7 +3216,7 @@ PyLong_AsDouble(PyObject *v) PyErr_SetString(PyExc_TypeError, "an integer is required"); return -1.0; } - if (IS_MEDIUM_VALUE(v)) { + if (_PyLong_IsCompact((PyLongObject *)v)) { /* Fast path; single digit long (31 bits) will cast safely to double. This improves performance of FP/long operations by 20%. @@ -3292,9 +3241,12 @@ PyLong_AsDouble(PyObject *v) static Py_ssize_t long_compare(PyLongObject *a, PyLongObject *b) { - Py_ssize_t sign = Py_SIZE(a) - Py_SIZE(b); + if (_PyLong_BothAreCompact(a, b)) { + return _PyLong_CompactValue(a) - _PyLong_CompactValue(b); + } + Py_ssize_t sign = _PyLong_SignedDigitCount(a) - _PyLong_SignedDigitCount(b); if (sign == 0) { - Py_ssize_t i = Py_ABS(Py_SIZE(a)); + Py_ssize_t i = _PyLong_DigitCount(a); sdigit diff = 0; while (--i >= 0) { diff = (sdigit) a->long_value.ob_digit[i] - (sdigit) b->long_value.ob_digit[i]; @@ -3302,7 +3254,7 @@ long_compare(PyLongObject *a, PyLongObject *b) break; } } - sign = Py_SIZE(a) < 0 ? -diff : diff; + sign = _PyLong_IsNegative(a) ? -diff : diff; } return sign; } @@ -3326,18 +3278,16 @@ long_hash(PyLongObject *v) Py_ssize_t i; int sign; - i = Py_SIZE(v); - switch(i) { - case -1: return v->long_value.ob_digit[0]==1 ? -2 : -(sdigit)v->long_value.ob_digit[0]; - case 0: return 0; - case 1: return v->long_value.ob_digit[0]; + if (_PyLong_IsCompact(v)) { + x = _PyLong_CompactValue(v); + if (x == (Py_uhash_t)-1) { + x = (Py_uhash_t)-2; + } + return x; } - sign = 1; + i = _PyLong_DigitCount(v); + sign = _PyLong_NonCompactSign(v); x = 0; - if (i < 0) { - sign = -1; - i = -(i); - } while (--i >= 0) { /* Here x is a quantity in the range [0, _PyHASH_MODULUS); we want to compute x * 2**PyLong_SHIFT + v->long_value.ob_digit[i] modulo @@ -3382,7 +3332,7 @@ long_hash(PyLongObject *v) static PyLongObject * x_add(PyLongObject *a, PyLongObject *b) { - Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b)); + Py_ssize_t size_a = _PyLong_DigitCount(a), size_b = _PyLong_DigitCount(b); PyLongObject *z; Py_ssize_t i; digit carry = 0; @@ -3416,7 +3366,7 @@ x_add(PyLongObject *a, PyLongObject *b) static PyLongObject * x_sub(PyLongObject *a, PyLongObject *b) { - Py_ssize_t size_a = Py_ABS(Py_SIZE(a)), size_b = Py_ABS(Py_SIZE(b)); + Py_ssize_t size_a = _PyLong_DigitCount(a), size_b = _PyLong_DigitCount(b); PyLongObject *z; Py_ssize_t i; int sign = 1; @@ -3462,7 +3412,7 @@ x_sub(PyLongObject *a, PyLongObject *b) } assert(borrow == 0); if (sign < 0) { - Py_SET_SIZE(z, -Py_SIZE(z)); + _PyLong_FlipSign(z); } return maybe_small_long(long_normalize(z)); } @@ -3470,13 +3420,13 @@ x_sub(PyLongObject *a, PyLongObject *b) PyObject * _PyLong_Add(PyLongObject *a, PyLongObject *b) { - if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { + if (_PyLong_BothAreCompact(a, b)) { return _PyLong_FromSTwoDigits(medium_value(a) + medium_value(b)); } PyLongObject *z; - if (Py_SIZE(a) < 0) { - if (Py_SIZE(b) < 0) { + if (_PyLong_IsNegative(a)) { + if (_PyLong_IsNegative(b)) { z = x_add(a, b); if (z != NULL) { /* x_add received at least one multiple-digit int, @@ -3484,14 +3434,14 @@ _PyLong_Add(PyLongObject *a, PyLongObject *b) That also means z is not an element of small_ints, so negating it in-place is safe. */ assert(Py_REFCNT(z) == 1); - Py_SET_SIZE(z, -(Py_SIZE(z))); + _PyLong_FlipSign(z); } } else z = x_sub(b, a); } else { - if (Py_SIZE(b) < 0) + if (_PyLong_IsNegative(b)) z = x_sub(a, b); else z = x_add(a, b); @@ -3511,23 +3461,23 @@ _PyLong_Subtract(PyLongObject *a, PyLongObject *b) { PyLongObject *z; - if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { + if (_PyLong_BothAreCompact(a, b)) { return _PyLong_FromSTwoDigits(medium_value(a) - medium_value(b)); } - if (Py_SIZE(a) < 0) { - if (Py_SIZE(b) < 0) { + if (_PyLong_IsNegative(a)) { + if (_PyLong_IsNegative(b)) { z = x_sub(b, a); } else { z = x_add(a, b); if (z != NULL) { - assert(Py_SIZE(z) == 0 || Py_REFCNT(z) == 1); - Py_SET_SIZE(z, -(Py_SIZE(z))); + assert(_PyLong_IsZero(z) || Py_REFCNT(z) == 1); + _PyLong_FlipSign(z); } } } else { - if (Py_SIZE(b) < 0) + if (_PyLong_IsNegative(b)) z = x_add(a, b); else z = x_sub(a, b); @@ -3549,15 +3499,15 @@ static PyLongObject * x_mul(PyLongObject *a, PyLongObject *b) { PyLongObject *z; - Py_ssize_t size_a = Py_ABS(Py_SIZE(a)); - Py_ssize_t size_b = Py_ABS(Py_SIZE(b)); + Py_ssize_t size_a = _PyLong_DigitCount(a); + Py_ssize_t size_b = _PyLong_DigitCount(b); Py_ssize_t i; z = _PyLong_New(size_a + size_b); if (z == NULL) return NULL; - memset(z->long_value.ob_digit, 0, Py_SIZE(z) * sizeof(digit)); + memset(z->long_value.ob_digit, 0, _PyLong_DigitCount(z) * sizeof(digit)); if (a == b) { /* Efficient squaring per HAC, Algorithm 14.16: * http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf @@ -3658,7 +3608,7 @@ kmul_split(PyLongObject *n, { PyLongObject *hi, *lo; Py_ssize_t size_lo, size_hi; - const Py_ssize_t size_n = Py_ABS(Py_SIZE(n)); + const Py_ssize_t size_n = _PyLong_DigitCount(n); size_lo = Py_MIN(size_n, size); size_hi = size_n - size_lo; @@ -3687,8 +3637,8 @@ static PyLongObject *k_lopsided_mul(PyLongObject *a, PyLongObject *b); static PyLongObject * k_mul(PyLongObject *a, PyLongObject *b) { - Py_ssize_t asize = Py_ABS(Py_SIZE(a)); - Py_ssize_t bsize = Py_ABS(Py_SIZE(b)); + Py_ssize_t asize = _PyLong_DigitCount(a); + Py_ssize_t bsize = _PyLong_DigitCount(b); PyLongObject *ah = NULL; PyLongObject *al = NULL; PyLongObject *bh = NULL; @@ -3731,7 +3681,7 @@ k_mul(PyLongObject *a, PyLongObject *b) /* If a is small compared to b, splitting on b gives a degenerate * case with ah==0, and Karatsuba may be (even much) less efficient * than "grade school" then. However, we can still win, by viewing - * b as a string of "big digits", each of width a->ob_size. That + * b as a string of "big digits", each of the same width as a. That * leads to a sequence of balanced calls to k_mul. */ if (2 * asize <= bsize) @@ -3740,7 +3690,7 @@ k_mul(PyLongObject *a, PyLongObject *b) /* Split a & b into hi & lo pieces. */ shift = bsize >> 1; if (kmul_split(a, shift, &ah, &al) < 0) goto fail; - assert(Py_SIZE(ah) > 0); /* the split isn't degenerate */ + assert(_PyLong_IsPositive(ah)); /* the split isn't degenerate */ if (a == b) { bh = (PyLongObject*)Py_NewRef(ah); @@ -3769,20 +3719,20 @@ k_mul(PyLongObject *a, PyLongObject *b) if (ret == NULL) goto fail; #ifdef Py_DEBUG /* Fill with trash, to catch reference to uninitialized digits. */ - memset(ret->long_value.ob_digit, 0xDF, Py_SIZE(ret) * sizeof(digit)); + memset(ret->long_value.ob_digit, 0xDF, _PyLong_DigitCount(ret) * sizeof(digit)); #endif /* 2. t1 <- ah*bh, and copy into high digits of result. */ if ((t1 = k_mul(ah, bh)) == NULL) goto fail; - assert(Py_SIZE(t1) >= 0); - assert(2*shift + Py_SIZE(t1) <= Py_SIZE(ret)); + assert(!_PyLong_IsNegative(t1)); + assert(2*shift + _PyLong_DigitCount(t1) <= _PyLong_DigitCount(ret)); memcpy(ret->long_value.ob_digit + 2*shift, t1->long_value.ob_digit, - Py_SIZE(t1) * sizeof(digit)); + _PyLong_DigitCount(t1) * sizeof(digit)); /* Zero-out the digits higher than the ah*bh copy. */ - i = Py_SIZE(ret) - 2*shift - Py_SIZE(t1); + i = _PyLong_DigitCount(ret) - 2*shift - _PyLong_DigitCount(t1); if (i) - memset(ret->long_value.ob_digit + 2*shift + Py_SIZE(t1), 0, + memset(ret->long_value.ob_digit + 2*shift + _PyLong_DigitCount(t1), 0, i * sizeof(digit)); /* 3. t2 <- al*bl, and copy into the low digits. */ @@ -3790,23 +3740,23 @@ k_mul(PyLongObject *a, PyLongObject *b) Py_DECREF(t1); goto fail; } - assert(Py_SIZE(t2) >= 0); - assert(Py_SIZE(t2) <= 2*shift); /* no overlap with high digits */ - memcpy(ret->long_value.ob_digit, t2->long_value.ob_digit, Py_SIZE(t2) * sizeof(digit)); + assert(!_PyLong_IsNegative(t2)); + assert(_PyLong_DigitCount(t2) <= 2*shift); /* no overlap with high digits */ + memcpy(ret->long_value.ob_digit, t2->long_value.ob_digit, _PyLong_DigitCount(t2) * sizeof(digit)); /* Zero out remaining digits. */ - i = 2*shift - Py_SIZE(t2); /* number of uninitialized digits */ + i = 2*shift - _PyLong_DigitCount(t2); /* number of uninitialized digits */ if (i) - memset(ret->long_value.ob_digit + Py_SIZE(t2), 0, i * sizeof(digit)); + memset(ret->long_value.ob_digit + _PyLong_DigitCount(t2), 0, i * sizeof(digit)); /* 4 & 5. Subtract ah*bh (t1) and al*bl (t2). We do al*bl first * because it's fresher in cache. */ - i = Py_SIZE(ret) - shift; /* # digits after shift */ - (void)v_isub(ret->long_value.ob_digit + shift, i, t2->long_value.ob_digit, Py_SIZE(t2)); + i = _PyLong_DigitCount(ret) - shift; /* # digits after shift */ + (void)v_isub(ret->long_value.ob_digit + shift, i, t2->long_value.ob_digit, _PyLong_DigitCount(t2)); _Py_DECREF_INT(t2); - (void)v_isub(ret->long_value.ob_digit + shift, i, t1->long_value.ob_digit, Py_SIZE(t1)); + (void)v_isub(ret->long_value.ob_digit + shift, i, t1->long_value.ob_digit, _PyLong_DigitCount(t1)); _Py_DECREF_INT(t1); /* 6. t3 <- (ah+al)(bh+bl), and add into result. */ @@ -3830,12 +3780,12 @@ k_mul(PyLongObject *a, PyLongObject *b) _Py_DECREF_INT(t1); _Py_DECREF_INT(t2); if (t3 == NULL) goto fail; - assert(Py_SIZE(t3) >= 0); + assert(!_PyLong_IsNegative(t3)); /* Add t3. It's not obvious why we can't run out of room here. * See the (*) comment after this function. */ - (void)v_iadd(ret->long_value.ob_digit + shift, i, t3->long_value.ob_digit, Py_SIZE(t3)); + (void)v_iadd(ret->long_value.ob_digit + shift, i, t3->long_value.ob_digit, _PyLong_DigitCount(t3)); _Py_DECREF_INT(t3); return long_normalize(ret); @@ -3896,17 +3846,17 @@ ah*bh and al*bl too. /* b has at least twice the digits of a, and a is big enough that Karatsuba * would pay off *if* the inputs had balanced sizes. View b as a sequence - * of slices, each with a->ob_size digits, and multiply the slices by a, - * one at a time. This gives k_mul balanced inputs to work with, and is - * also cache-friendly (we compute one double-width slice of the result + * of slices, each with the same number of digits as a, and multiply the + * slices by a, one at a time. This gives k_mul balanced inputs to work with, + * and is also cache-friendly (we compute one double-width slice of the result * at a time, then move on, never backtracking except for the helpful * single-width slice overlap between successive partial sums). */ static PyLongObject * k_lopsided_mul(PyLongObject *a, PyLongObject *b) { - const Py_ssize_t asize = Py_ABS(Py_SIZE(a)); - Py_ssize_t bsize = Py_ABS(Py_SIZE(b)); + const Py_ssize_t asize = _PyLong_DigitCount(a); + Py_ssize_t bsize = _PyLong_DigitCount(b); Py_ssize_t nbdone; /* # of b digits already multiplied */ PyLongObject *ret; PyLongObject *bslice = NULL; @@ -3918,7 +3868,7 @@ k_lopsided_mul(PyLongObject *a, PyLongObject *b) ret = _PyLong_New(asize + bsize); if (ret == NULL) return NULL; - memset(ret->long_value.ob_digit, 0, Py_SIZE(ret) * sizeof(digit)); + memset(ret->long_value.ob_digit, 0, _PyLong_DigitCount(ret) * sizeof(digit)); /* Successive slices of b are copied into bslice. */ bslice = _PyLong_New(asize); @@ -3933,14 +3883,15 @@ k_lopsided_mul(PyLongObject *a, PyLongObject *b) /* Multiply the next slice of b by a. */ memcpy(bslice->long_value.ob_digit, b->long_value.ob_digit + nbdone, nbtouse * sizeof(digit)); - Py_SET_SIZE(bslice, nbtouse); + assert(nbtouse >= 0); + _PyLong_SetSignAndDigitCount(bslice, 1, nbtouse); product = k_mul(a, bslice); if (product == NULL) goto fail; /* Add into result. */ - (void)v_iadd(ret->long_value.ob_digit + nbdone, Py_SIZE(ret) - nbdone, - product->long_value.ob_digit, Py_SIZE(product)); + (void)v_iadd(ret->long_value.ob_digit + nbdone, _PyLong_DigitCount(ret) - nbdone, + product->long_value.ob_digit, _PyLong_DigitCount(product)); _Py_DECREF_INT(product); bsize -= nbtouse; @@ -3962,14 +3913,14 @@ _PyLong_Multiply(PyLongObject *a, PyLongObject *b) PyLongObject *z; /* fast path for single-digit multiplication */ - if (IS_MEDIUM_VALUE(a) && IS_MEDIUM_VALUE(b)) { + if (_PyLong_BothAreCompact(a, b)) { stwodigits v = medium_value(a) * medium_value(b); return _PyLong_FromSTwoDigits(v); } z = k_mul(a, b); /* Negate if exactly one of the inputs is negative. */ - if (((Py_SIZE(a) ^ Py_SIZE(b)) < 0) && z) { + if (!_PyLong_SameSign(a, b) && z) { _PyLong_Negate(&z); if (z == NULL) return NULL; @@ -3992,11 +3943,10 @@ fast_mod(PyLongObject *a, PyLongObject *b) sdigit right = b->long_value.ob_digit[0]; sdigit mod; - assert(Py_ABS(Py_SIZE(a)) == 1); - assert(Py_ABS(Py_SIZE(b)) == 1); - - if (Py_SIZE(a) == Py_SIZE(b)) { - /* 'a' and 'b' have the same sign. */ + assert(_PyLong_DigitCount(a) == 1); + assert(_PyLong_DigitCount(b) == 1); + sdigit sign = _PyLong_CompactSign(b); + if (_PyLong_SameSign(a, b)) { mod = left % right; } else { @@ -4004,7 +3954,7 @@ fast_mod(PyLongObject *a, PyLongObject *b) mod = right - 1 - (left - 1) % right; } - return PyLong_FromLong(mod * (sdigit)Py_SIZE(b)); + return PyLong_FromLong(mod * sign); } /* Fast floor division for single-digit longs. */ @@ -4015,11 +3965,10 @@ fast_floor_div(PyLongObject *a, PyLongObject *b) sdigit right = b->long_value.ob_digit[0]; sdigit div; - assert(Py_ABS(Py_SIZE(a)) == 1); - assert(Py_ABS(Py_SIZE(b)) == 1); + assert(_PyLong_DigitCount(a) == 1); + assert(_PyLong_DigitCount(b) == 1); - if (Py_SIZE(a) == Py_SIZE(b)) { - /* 'a' and 'b' have the same sign. */ + if (_PyLong_SameSign(a, b)) { div = left / right; } else { @@ -4097,7 +4046,7 @@ l_divmod(PyLongObject *v, PyLongObject *w, { PyLongObject *div, *mod; - if (Py_ABS(Py_SIZE(v)) == 1 && Py_ABS(Py_SIZE(w)) == 1) { + if (_PyLong_DigitCount(v) == 1 && _PyLong_DigitCount(w) == 1) { /* Fast path for single-digit longs */ div = NULL; if (pdiv != NULL) { @@ -4122,8 +4071,8 @@ l_divmod(PyLongObject *v, PyLongObject *w, return 0; } #if WITH_PYLONG_MODULE - Py_ssize_t size_v = Py_ABS(Py_SIZE(v)); /* digits in numerator */ - Py_ssize_t size_w = Py_ABS(Py_SIZE(w)); /* digits in denominator */ + Py_ssize_t size_v = _PyLong_DigitCount(v); /* digits in numerator */ + Py_ssize_t size_w = _PyLong_DigitCount(w); /* digits in denominator */ if (size_w > 300 && (size_v - size_w) > 150) { /* Switch to _pylong.int_divmod(). If the quotient is small then "schoolbook" division is linear-time so don't use in that case. @@ -4135,8 +4084,8 @@ l_divmod(PyLongObject *v, PyLongObject *w, #endif if (long_divrem(v, w, &div, &mod) < 0) return -1; - if ((Py_SIZE(mod) < 0 && Py_SIZE(w) > 0) || - (Py_SIZE(mod) > 0 && Py_SIZE(w) < 0)) { + if ((_PyLong_IsNegative(mod) && _PyLong_IsPositive(w)) || + (_PyLong_IsPositive(mod) && _PyLong_IsNegative(w))) { PyLongObject *temp; temp = (PyLongObject *) long_add(mod, w); Py_SETREF(mod, temp); @@ -4175,15 +4124,15 @@ l_mod(PyLongObject *v, PyLongObject *w, PyLongObject **pmod) PyLongObject *mod; assert(pmod); - if (Py_ABS(Py_SIZE(v)) == 1 && Py_ABS(Py_SIZE(w)) == 1) { + if (_PyLong_DigitCount(v) == 1 && _PyLong_DigitCount(w) == 1) { /* Fast path for single-digit longs */ *pmod = (PyLongObject *)fast_mod(v, w); return -(*pmod == NULL); } if (long_rem(v, w, &mod) < 0) return -1; - if ((Py_SIZE(mod) < 0 && Py_SIZE(w) > 0) || - (Py_SIZE(mod) > 0 && Py_SIZE(w) < 0)) { + if ((_PyLong_IsNegative(mod) && _PyLong_IsPositive(w)) || + (_PyLong_IsPositive(mod) && _PyLong_IsNegative(w))) { PyLongObject *temp; temp = (PyLongObject *) long_add(mod, w); Py_SETREF(mod, temp); @@ -4202,7 +4151,7 @@ long_div(PyObject *a, PyObject *b) CHECK_BINOP(a, b); - if (Py_ABS(Py_SIZE(a)) == 1 && Py_ABS(Py_SIZE(b)) == 1) { + if (_PyLong_DigitCount((PyLongObject*)a) == 1 && _PyLong_DigitCount((PyLongObject*)b) == 1) { return fast_floor_div((PyLongObject*)a, (PyLongObject*)b); } @@ -4317,9 +4266,9 @@ long_true_divide(PyObject *v, PyObject *w) */ /* Reduce to case where a and b are both positive. */ - a_size = Py_ABS(Py_SIZE(a)); - b_size = Py_ABS(Py_SIZE(b)); - negate = (Py_SIZE(a) < 0) ^ (Py_SIZE(b) < 0); + a_size = _PyLong_DigitCount(a); + b_size = _PyLong_DigitCount(b); + negate = (_PyLong_IsNegative(a)) != (_PyLong_IsNegative(b)); if (b_size == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "division by zero"); @@ -4412,7 +4361,7 @@ long_true_divide(PyObject *v, PyObject *w) inexact = 1; } long_normalize(x); - x_size = Py_SIZE(x); + x_size = _PyLong_SignedDigitCount(x); /* x //= b. If the remainder is nonzero, set inexact. We own the only reference to x, so it's safe to modify it in-place. */ @@ -4429,11 +4378,11 @@ long_true_divide(PyObject *v, PyObject *w) Py_SETREF(x, div); if (x == NULL) goto error; - if (Py_SIZE(rem)) + if (!_PyLong_IsZero(rem)) inexact = 1; Py_DECREF(rem); } - x_size = Py_ABS(Py_SIZE(x)); + x_size = _PyLong_DigitCount(x); assert(x_size > 0); /* result of division is never zero */ x_bits = (x_size-1)*PyLong_SHIFT+bit_length_digit(x->long_value.ob_digit[x_size-1]); @@ -4535,7 +4484,7 @@ long_invmod(PyLongObject *a, PyLongObject *n) PyLongObject *b, *c; /* Should only ever be called for positive n */ - assert(Py_SIZE(n) > 0); + assert(_PyLong_IsPositive(n)); b = (PyLongObject *)PyLong_FromLong(1L); if (b == NULL) { @@ -4550,7 +4499,7 @@ long_invmod(PyLongObject *a, PyLongObject *n) Py_INCREF(n); /* references now owned: a, b, c, n */ - while (Py_SIZE(n) != 0) { + while (!_PyLong_IsZero(n)) { PyLongObject *q, *r, *s, *t; if (l_divmod(a, n, &q, &r) == -1) { @@ -4636,7 +4585,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) Py_RETURN_NOTIMPLEMENTED; } - if (Py_SIZE(b) < 0 && c == NULL) { + if (_PyLong_IsNegative(b) && c == NULL) { /* if exponent is negative and there's no modulus: return a float. This works because we know that this calls float_pow() which converts its @@ -4649,7 +4598,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) if (c) { /* if modulus == 0: raise ValueError() */ - if (Py_SIZE(c) == 0) { + if (_PyLong_IsZero(c)) { PyErr_SetString(PyExc_ValueError, "pow() 3rd argument cannot be 0"); goto Error; @@ -4658,7 +4607,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) /* if modulus < 0: negativeOutput = True modulus = -modulus */ - if (Py_SIZE(c) < 0) { + if (_PyLong_IsNegative(c)) { negativeOutput = 1; temp = (PyLongObject *)_PyLong_Copy(c); if (temp == NULL) @@ -4672,14 +4621,14 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) /* if modulus == 1: return 0 */ - if ((Py_SIZE(c) == 1) && (c->long_value.ob_digit[0] == 1)) { + if (_PyLong_IsNonNegativeCompact(c) && (c->long_value.ob_digit[0] == 1)) { z = (PyLongObject *)PyLong_FromLong(0L); goto Done; } /* if exponent is negative, negate the exponent and replace the base with a modular inverse */ - if (Py_SIZE(b) < 0) { + if (_PyLong_IsNegative(b)) { temp = (PyLongObject *)_PyLong_Copy(b); if (temp == NULL) goto Error; @@ -4705,7 +4654,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) base % modulus instead. We could _always_ do this reduction, but l_mod() isn't cheap, so we only do it when it buys something. */ - if (Py_SIZE(a) < 0 || Py_SIZE(a) > Py_SIZE(c)) { + if (_PyLong_IsNegative(a) || _PyLong_DigitCount(a) > _PyLong_DigitCount(c)) { if (l_mod(a, c, &temp) < 0) goto Error; Py_SETREF(a, temp); @@ -4747,7 +4696,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) REDUCE(result); \ } while(0) - i = Py_SIZE(b); + i = _PyLong_SignedDigitCount(b); digit bi = i ? b->long_value.ob_digit[i-1] : 0; digit bit; if (i <= 1 && bi <= 3) { @@ -4839,7 +4788,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) pending = 0; \ } while(0) - for (i = Py_SIZE(b) - 1; i >= 0; --i) { + for (i = _PyLong_SignedDigitCount(b) - 1; i >= 0; --i) { const digit bi = b->long_value.ob_digit[i]; for (j = PyLong_SHIFT - 1; j >= 0; --j) { const int bit = (bi >> j) & 1; @@ -4857,7 +4806,7 @@ long_pow(PyObject *v, PyObject *w, PyObject *x) ABSORB_PENDING; } - if (negativeOutput && (Py_SIZE(z) != 0)) { + if (negativeOutput && !_PyLong_IsZero(z)) { temp = (PyLongObject *)long_sub(z, c); if (temp == NULL) goto Error; @@ -4885,14 +4834,14 @@ long_invert(PyLongObject *v) { /* Implement ~x as -(x+1) */ PyLongObject *x; - if (IS_MEDIUM_VALUE(v)) + if (_PyLong_IsCompact(v)) return _PyLong_FromSTwoDigits(~medium_value(v)); x = (PyLongObject *) long_add(v, (PyLongObject *)_PyLong_GetOne()); if (x == NULL) return NULL; _PyLong_Negate(&x); - /* No need for maybe_small_long here, since any small - longs will have been caught in the Py_SIZE <= 1 fast path. */ + /* No need for maybe_small_long here, since any small longs + will have been caught in the _PyLong_IsCompact() fast path. */ return (PyObject *)x; } @@ -4900,18 +4849,18 @@ static PyObject * long_neg(PyLongObject *v) { PyLongObject *z; - if (IS_MEDIUM_VALUE(v)) + if (_PyLong_IsCompact(v)) return _PyLong_FromSTwoDigits(-medium_value(v)); z = (PyLongObject *)_PyLong_Copy(v); if (z != NULL) - Py_SET_SIZE(z, -(Py_SIZE(v))); + _PyLong_FlipSign(z); return (PyObject *)z; } static PyObject * long_abs(PyLongObject *v) { - if (Py_SIZE(v) < 0) + if (_PyLong_IsNegative(v)) return long_neg(v); else return long_long((PyObject *)v); @@ -4920,7 +4869,7 @@ long_abs(PyLongObject *v) static int long_bool(PyLongObject *v) { - return Py_SIZE(v) != 0; + return !_PyLong_IsZero(v); } /* wordshift, remshift = divmod(shiftby, PyLong_SHIFT) */ @@ -4928,14 +4877,14 @@ static int divmod_shift(PyObject *shiftby, Py_ssize_t *wordshift, digit *remshift) { assert(PyLong_Check(shiftby)); - assert(Py_SIZE(shiftby) >= 0); + assert(!_PyLong_IsNegative((PyLongObject *)shiftby)); Py_ssize_t lshiftby = PyLong_AsSsize_t((PyObject *)shiftby); if (lshiftby >= 0) { *wordshift = lshiftby / PyLong_SHIFT; *remshift = lshiftby % PyLong_SHIFT; return 0; } - /* PyLong_Check(shiftby) is true and Py_SIZE(shiftby) >= 0, so it must + /* PyLong_Check(shiftby) is true and shiftby is not negative, so it must be that PyLong_AsSsize_t raised an OverflowError. */ assert(PyErr_ExceptionMatches(PyExc_OverflowError)); PyErr_Clear(); @@ -4973,7 +4922,7 @@ long_rshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) assert(remshift < PyLong_SHIFT); /* Fast path for small a. */ - if (IS_MEDIUM_VALUE(a)) { + if (_PyLong_IsCompact(a)) { stwodigits m, x; digit shift; m = medium_value(a); @@ -4982,8 +4931,8 @@ long_rshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) return _PyLong_FromSTwoDigits(x); } - a_negative = Py_SIZE(a) < 0; - size_a = Py_ABS(Py_SIZE(a)); + a_negative = _PyLong_IsNegative(a); + size_a = _PyLong_DigitCount(a); if (a_negative) { /* For negative 'a', adjust so that 0 < remshift <= PyLong_SHIFT, @@ -5024,7 +4973,7 @@ long_rshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) significant `wordshift` digits of `a` is nonzero. Digit `wordshift` of `2**shift - 1` has value `PyLong_MASK >> hishift`. */ - Py_SET_SIZE(z, -newsize); + _PyLong_SetSignAndDigitCount(z, -1, newsize); digit sticky = 0; for (Py_ssize_t j = 0; j < wordshift; j++) { @@ -5054,11 +5003,11 @@ long_rshift(PyObject *a, PyObject *b) CHECK_BINOP(a, b); - if (Py_SIZE(b) < 0) { + if (_PyLong_IsNegative((PyLongObject *)b)) { PyErr_SetString(PyExc_ValueError, "negative shift count"); return NULL; } - if (Py_SIZE(a) == 0) { + if (_PyLong_IsZero((PyLongObject *)a)) { return PyLong_FromLong(0); } if (divmod_shift(b, &wordshift, &remshift) < 0) @@ -5074,7 +5023,7 @@ _PyLong_Rshift(PyObject *a, size_t shiftby) digit remshift; assert(PyLong_Check(a)); - if (Py_SIZE(a) == 0) { + if (_PyLong_IsZero((PyLongObject *)a)) { return PyLong_FromLong(0); } wordshift = shiftby / PyLong_SHIFT; @@ -5089,23 +5038,23 @@ long_lshift1(PyLongObject *a, Py_ssize_t wordshift, digit remshift) Py_ssize_t oldsize, newsize, i, j; twodigits accum; - if (wordshift == 0 && IS_MEDIUM_VALUE(a)) { + if (wordshift == 0 && _PyLong_IsCompact(a)) { stwodigits m = medium_value(a); // bypass undefined shift operator behavior stwodigits x = m < 0 ? -(-m << remshift) : m << remshift; return _PyLong_FromSTwoDigits(x); } - oldsize = Py_ABS(Py_SIZE(a)); + oldsize = _PyLong_DigitCount(a); newsize = oldsize + wordshift; if (remshift) ++newsize; z = _PyLong_New(newsize); if (z == NULL) return NULL; - if (Py_SIZE(a) < 0) { + if (_PyLong_IsNegative(a)) { assert(Py_REFCNT(z) == 1); - Py_SET_SIZE(z, -Py_SIZE(z)); + _PyLong_FlipSign(z); } for (i = 0; i < wordshift; i++) z->long_value.ob_digit[i] = 0; @@ -5131,11 +5080,11 @@ long_lshift(PyObject *a, PyObject *b) CHECK_BINOP(a, b); - if (Py_SIZE(b) < 0) { + if (_PyLong_IsNegative((PyLongObject *)b)) { PyErr_SetString(PyExc_ValueError, "negative shift count"); return NULL; } - if (Py_SIZE(a) == 0) { + if (_PyLong_IsZero((PyLongObject *)a)) { return PyLong_FromLong(0); } if (divmod_shift(b, &wordshift, &remshift) < 0) @@ -5151,7 +5100,7 @@ _PyLong_Lshift(PyObject *a, size_t shiftby) digit remshift; assert(PyLong_Check(a)); - if (Py_SIZE(a) == 0) { + if (_PyLong_IsZero((PyLongObject *)a)) { return PyLong_FromLong(0); } wordshift = shiftby / PyLong_SHIFT; @@ -5193,8 +5142,8 @@ long_bitwise(PyLongObject *a, result back to sign-magnitude at the end. */ /* If a is negative, replace it by its two's complement. */ - size_a = Py_ABS(Py_SIZE(a)); - nega = Py_SIZE(a) < 0; + size_a = _PyLong_DigitCount(a); + nega = _PyLong_IsNegative(a); if (nega) { z = _PyLong_New(size_a); if (z == NULL) @@ -5207,8 +5156,8 @@ long_bitwise(PyLongObject *a, Py_INCREF(a); /* Same for b. */ - size_b = Py_ABS(Py_SIZE(b)); - negb = Py_SIZE(b) < 0; + size_b = _PyLong_DigitCount(b); + negb = _PyLong_IsNegative(b); if (negb) { z = _PyLong_New(size_b); if (z == NULL) { @@ -5289,7 +5238,7 @@ long_bitwise(PyLongObject *a, /* Complement result if negative. */ if (negz) { - Py_SET_SIZE(z, -(Py_SIZE(z))); + _PyLong_FlipSign(z); z->long_value.ob_digit[size_z] = PyLong_MASK; v_complement(z->long_value.ob_digit, z->long_value.ob_digit, size_z+1); } @@ -5305,7 +5254,7 @@ long_and(PyObject *a, PyObject *b) CHECK_BINOP(a, b); PyLongObject *x = (PyLongObject*)a; PyLongObject *y = (PyLongObject*)b; - if (IS_MEDIUM_VALUE(x) && IS_MEDIUM_VALUE(y)) { + if (_PyLong_IsCompact(x) && _PyLong_IsCompact(y)) { return _PyLong_FromSTwoDigits(medium_value(x) & medium_value(y)); } return long_bitwise(x, '&', y); @@ -5317,7 +5266,7 @@ long_xor(PyObject *a, PyObject *b) CHECK_BINOP(a, b); PyLongObject *x = (PyLongObject*)a; PyLongObject *y = (PyLongObject*)b; - if (IS_MEDIUM_VALUE(x) && IS_MEDIUM_VALUE(y)) { + if (_PyLong_IsCompact(x) && _PyLong_IsCompact(y)) { return _PyLong_FromSTwoDigits(medium_value(x) ^ medium_value(y)); } return long_bitwise(x, '^', y); @@ -5329,7 +5278,7 @@ long_or(PyObject *a, PyObject *b) CHECK_BINOP(a, b); PyLongObject *x = (PyLongObject*)a; PyLongObject *y = (PyLongObject*)b; - if (IS_MEDIUM_VALUE(x) && IS_MEDIUM_VALUE(y)) { + if (_PyLong_IsCompact(x) && _PyLong_IsCompact(y)) { return _PyLong_FromSTwoDigits(medium_value(x) | medium_value(y)); } return long_bitwise(x, '|', y); @@ -5353,14 +5302,11 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) stwodigits x, y, q, s, t, c_carry, d_carry; stwodigits A, B, C, D, T; int nbits, k; - Py_ssize_t size_a, size_b, alloc_a, alloc_b; digit *a_digit, *b_digit, *c_digit, *d_digit, *a_end, *b_end; a = (PyLongObject *)aarg; b = (PyLongObject *)barg; - size_a = Py_SIZE(a); - size_b = Py_SIZE(b); - if (-2 <= size_a && size_a <= 2 && -2 <= size_b && size_b <= 2) { + if (_PyLong_DigitCount(a) <= 2 && _PyLong_DigitCount(b) <= 2) { Py_INCREF(a); Py_INCREF(b); goto simple; @@ -5382,14 +5328,15 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) } /* We now own references to a and b */ - alloc_a = Py_SIZE(a); - alloc_b = Py_SIZE(b); + Py_ssize_t size_a, size_b, alloc_a, alloc_b; + alloc_a = _PyLong_DigitCount(a); + alloc_b = _PyLong_DigitCount(b); /* reduce until a fits into 2 digits */ - while ((size_a = Py_SIZE(a)) > 2) { + while ((size_a = _PyLong_DigitCount(a)) > 2) { nbits = bit_length_digit(a->long_value.ob_digit[size_a-1]); /* extract top 2*PyLong_SHIFT bits of a into x, along with corresponding bits of b into y */ - size_b = Py_SIZE(b); + size_b = _PyLong_DigitCount(b); assert(size_b <= size_a); if (size_b == 0) { if (size_a < alloc_a) { @@ -5433,7 +5380,7 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) Py_SETREF(a, b); b = r; alloc_a = alloc_b; - alloc_b = Py_SIZE(b); + alloc_b = _PyLong_DigitCount(b); continue; } @@ -5446,7 +5393,8 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) T = -C; C = -D; D = T; } if (c != NULL) { - Py_SET_SIZE(c, size_a); + assert(size_a >= 0); + _PyLong_SetSignAndDigitCount(c, 1, size_a); } else if (Py_REFCNT(a) == 1) { c = (PyLongObject*)Py_NewRef(a); @@ -5459,11 +5407,13 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) } if (d != NULL) { - Py_SET_SIZE(d, size_a); + assert(size_a >= 0); + _PyLong_SetSignAndDigitCount(d, 1, size_a); } else if (Py_REFCNT(b) == 1 && size_a <= alloc_b) { d = (PyLongObject*)Py_NewRef(b); - Py_SET_SIZE(d, size_a); + assert(size_a >= 0); + _PyLong_SetSignAndDigitCount(d, 1, size_a); } else { alloc_b = size_a; @@ -5635,9 +5585,7 @@ long_subtype_new(PyTypeObject *type, PyObject *x, PyObject *obase) if (tmp == NULL) return NULL; assert(PyLong_Check(tmp)); - n = Py_SIZE(tmp); - if (n < 0) - n = -n; + n = _PyLong_DigitCount(tmp); /* Fast operations for single digit integers (including zero) * assume that there is always at least one digit present. */ if (n == 0) { @@ -5649,7 +5597,7 @@ long_subtype_new(PyTypeObject *type, PyObject *x, PyObject *obase) return NULL; } assert(PyLong_Check(newobj)); - Py_SET_SIZE(newobj, Py_SIZE(tmp)); + newobj->long_value.lv_tag = tmp->long_value.lv_tag; for (i = 0; i < n; i++) { newobj->long_value.ob_digit[i] = tmp->long_value.ob_digit[i]; } @@ -5743,7 +5691,7 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b) } /* Do a and b have different signs? If so, quotient is negative. */ - quo_is_neg = (Py_SIZE(a) < 0) != (Py_SIZE(b) < 0); + quo_is_neg = (_PyLong_IsNegative((PyLongObject *)a)) != (_PyLong_IsNegative((PyLongObject *)b)); if (long_divrem((PyLongObject*)a, (PyLongObject*)b, &quo, &rem) < 0) goto error; @@ -5763,8 +5711,8 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b) cmp = long_compare((PyLongObject *)twice_rem, (PyLongObject *)b); Py_DECREF(twice_rem); - quo_is_odd = Py_SIZE(quo) != 0 && ((quo->long_value.ob_digit[0] & 1) != 0); - if ((Py_SIZE(b) < 0 ? cmp < 0 : cmp > 0) || (cmp == 0 && quo_is_odd)) { + quo_is_odd = (quo->long_value.ob_digit[0] & 1) != 0; + if ((_PyLong_IsNegative((PyLongObject *)b) ? cmp < 0 : cmp > 0) || (cmp == 0 && quo_is_odd)) { /* fix up quotient */ if (quo_is_neg) temp = long_sub(quo, (PyLongObject *)one); @@ -5837,7 +5785,7 @@ int___round___impl(PyObject *self, PyObject *o_ndigits) return NULL; /* if ndigits >= 0 then no rounding is necessary; return self unchanged */ - if (Py_SIZE(ndigits) >= 0) { + if (!_PyLong_IsNegative((PyLongObject *)ndigits)) { Py_DECREF(ndigits); return long_long(self); } @@ -5883,8 +5831,8 @@ int___sizeof___impl(PyObject *self) /*[clinic end generated code: output=3303f008eaa6a0a5 input=9b51620c76fc4507]*/ { /* using Py_MAX(..., 1) because we always allocate space for at least - one digit, even though the integer zero has a Py_SIZE of 0 */ - Py_ssize_t ndigits = Py_MAX(Py_ABS(Py_SIZE(self)), 1); + one digit, even though the integer zero has a digit count of 0 */ + Py_ssize_t ndigits = Py_MAX(_PyLong_DigitCount((PyLongObject *)self), 1); return Py_TYPE(self)->tp_basicsize + Py_TYPE(self)->tp_itemsize * ndigits; } @@ -5911,7 +5859,7 @@ int_bit_length_impl(PyObject *self) assert(self != NULL); assert(PyLong_Check(self)); - ndigits = Py_ABS(Py_SIZE(self)); + ndigits = _PyLong_DigitCount((PyLongObject *)self); if (ndigits == 0) return PyLong_FromLong(0); @@ -5980,7 +5928,7 @@ int_bit_count_impl(PyObject *self) assert(PyLong_Check(self)); PyLongObject *z = (PyLongObject *)self; - Py_ssize_t ndigits = Py_ABS(Py_SIZE(z)); + Py_ssize_t ndigits = _PyLong_DigitCount(z); Py_ssize_t bit_count = 0; /* Each digit has up to PyLong_SHIFT ones, so the accumulated bit count diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index b4d0bbf32c84c8..beb86b9623bdbc 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -33,7 +33,7 @@ validate_step(PyObject *step) return PyLong_FromLong(1); step = PyNumber_Index(step); - if (step && _PyLong_Sign(step) == 0) { + if (step && _PyLong_IsZero((PyLongObject *)step)) { PyErr_SetString(PyExc_ValueError, "range() arg 3 must not be zero"); Py_CLEAR(step); diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index 5d2e6ad522bcf2..584ebce721faed 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -445,7 +445,7 @@ _PySlice_GetLongIndices(PySliceObject *self, PyObject *length, if (start == NULL) goto error; - if (_PyLong_Sign(start) < 0) { + if (_PyLong_IsNegative((PyLongObject *)start)) { /* start += length */ PyObject *tmp = PyNumber_Add(start, length); Py_SETREF(start, tmp); @@ -478,7 +478,7 @@ _PySlice_GetLongIndices(PySliceObject *self, PyObject *length, if (stop == NULL) goto error; - if (_PyLong_Sign(stop) < 0) { + if (_PyLong_IsNegative((PyLongObject *)stop)) { /* stop += length */ PyObject *tmp = PyNumber_Add(stop, length); Py_SETREF(stop, tmp); @@ -533,7 +533,7 @@ slice_indices(PySliceObject* self, PyObject* len) if (length == NULL) return NULL; - if (_PyLong_Sign(length) < 0) { + if (_PyLong_IsNegative((PyLongObject *)length)) { PyErr_SetString(PyExc_ValueError, "length should not be negative"); Py_DECREF(length); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index a37f97c71ec763..69e84743f13aac 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -8,6 +8,7 @@ #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_moduleobject.h" // _PyModule_GetDef() #include "pycore_object.h" // _PyType_HasFeature() +#include "pycore_long.h" // _PyLong_IsNegative() #include "pycore_pyerrors.h" // _PyErr_Occurred() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_typeobject.h" // struct type_cache @@ -7865,7 +7866,7 @@ slot_sq_length(PyObject *self) return -1; assert(PyLong_Check(res)); - if (Py_SIZE(res) < 0) { + if (_PyLong_IsNegative((PyLongObject *)res)) { Py_DECREF(res); PyErr_SetString(PyExc_ValueError, "__len__() should return >= 0"); diff --git a/Python/ast_opt.c b/Python/ast_opt.c index 1a0b2a05b1c713..8270fa8e372d93 100644 --- a/Python/ast_opt.c +++ b/Python/ast_opt.c @@ -2,6 +2,7 @@ #include "Python.h" #include "pycore_ast.h" // _PyAST_GetDocString() #include "pycore_compile.h" // _PyASTOptimizeState +#include "pycore_long.h" // _PyLong #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_format.h" // F_LJUST @@ -152,7 +153,9 @@ check_complexity(PyObject *obj, Py_ssize_t limit) static PyObject * safe_multiply(PyObject *v, PyObject *w) { - if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w)) { + if (PyLong_Check(v) && PyLong_Check(w) && + !_PyLong_IsZero((PyLongObject *)v) && !_PyLong_IsZero((PyLongObject *)w) + ) { size_t vbits = _PyLong_NumBits(v); size_t wbits = _PyLong_NumBits(w); if (vbits == (size_t)-1 || wbits == (size_t)-1) { @@ -198,7 +201,9 @@ safe_multiply(PyObject *v, PyObject *w) static PyObject * safe_power(PyObject *v, PyObject *w) { - if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w) > 0) { + if (PyLong_Check(v) && PyLong_Check(w) && + !_PyLong_IsZero((PyLongObject *)v) && _PyLong_IsPositive((PyLongObject *)w) + ) { size_t vbits = _PyLong_NumBits(v); size_t wbits = PyLong_AsSize_t(w); if (vbits == (size_t)-1 || wbits == (size_t)-1) { @@ -215,7 +220,9 @@ safe_power(PyObject *v, PyObject *w) static PyObject * safe_lshift(PyObject *v, PyObject *w) { - if (PyLong_Check(v) && PyLong_Check(w) && Py_SIZE(v) && Py_SIZE(w)) { + if (PyLong_Check(v) && PyLong_Check(w) && + !_PyLong_IsZero((PyLongObject *)v) && !_PyLong_IsZero((PyLongObject *)w) + ) { size_t vbits = _PyLong_NumBits(v); size_t wbits = PyLong_AsSize_t(w); if (vbits == (size_t)-1 || wbits == (size_t)-1) { diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 12ca0ba6c4873c..55fd364d007972 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -5,6 +5,7 @@ #include "pycore_ast.h" // _PyAST_Validate() #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_compile.h" // _PyAST_Compile() +#include "pycore_long.h" // _PyLong_CompactValue #include "pycore_object.h" // _Py_AddToAllObjects() #include "pycore_pyerrors.h" // _PyErr_NoMemory() #include "pycore_pystate.h" // _PyThreadState_GET() @@ -2491,7 +2492,7 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) */ if (PyLong_CheckExact(result)) { int overflow; - long i_result = PyLong_AsLongAndOverflow(result, &overflow); + Py_ssize_t i_result = PyLong_AsLongAndOverflow(result, &overflow); /* If this already overflowed, don't even enter the loop. */ if (overflow == 0) { Py_SETREF(result, NULL); @@ -2505,15 +2506,14 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) return PyLong_FromLong(i_result); } if (PyLong_CheckExact(item) || PyBool_Check(item)) { - long b; + Py_ssize_t b; overflow = 0; /* Single digits are common, fast, and cannot overflow on unpacking. */ - switch (Py_SIZE(item)) { - case -1: b = -(sdigit) ((PyLongObject*)item)->long_value.ob_digit[0]; break; - // Note: the continue goes to the top of the "while" loop that iterates over the elements - case 0: Py_DECREF(item); continue; - case 1: b = ((PyLongObject*)item)->long_value.ob_digit[0]; break; - default: b = PyLong_AsLongAndOverflow(item, &overflow); break; + if (_PyLong_IsCompact((PyLongObject *)item)) { + b = _PyLong_CompactValue((PyLongObject *)item); + } + else { + b = PyLong_AsLongAndOverflow(item, &overflow); } if (overflow == 0 && (i_result >= 0 ? (b <= LONG_MAX - i_result) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 92fa7664e00452..5038e1bb17fc3f 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -418,8 +418,7 @@ dummy_func( DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyList_Size(list) - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); - assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0); + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -436,8 +435,7 @@ dummy_func( DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyTuple_Size(list) - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); - assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0); + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -529,7 +527,7 @@ dummy_func( DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); // Ensure nonnegative, zero-or-one-digit ints. - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), STORE_SUBSCR); + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), STORE_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; // Ensure index < len(list) DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); @@ -1828,12 +1826,13 @@ dummy_func( assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); - DEOPT_IF((size_t)(Py_SIZE(left) + 1) > 2, COMPARE_AND_BRANCH); - DEOPT_IF((size_t)(Py_SIZE(right) + 1) > 2, COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_AND_BRANCH); STAT_INC(COMPARE_AND_BRANCH, hit); - assert(Py_ABS(Py_SIZE(left)) <= 1 && Py_ABS(Py_SIZE(right)) <= 1); - Py_ssize_t ileft = Py_SIZE(left) * ((PyLongObject *)left)->long_value.ob_digit[0]; - Py_ssize_t iright = Py_SIZE(right) * ((PyLongObject *)right)->long_value.ob_digit[0]; + assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 && + _PyLong_DigitCount((PyLongObject *)right) <= 1); + Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left); + Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right); // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 9df173f843f806..d83901ce3e2158 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -597,8 +597,7 @@ DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyList_Size(list) - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); - assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0); + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -622,8 +621,7 @@ DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyTuple_Size(list) - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), BINARY_SUBSCR); - assert(((PyLongObject *)_PyLong_GetZero())->long_value.ob_digit[0] == 0); + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); @@ -748,7 +746,7 @@ DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); // Ensure nonnegative, zero-or-one-digit ints. - DEOPT_IF(!_PyLong_IsPositiveSingleDigit(sub), STORE_SUBSCR); + DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), STORE_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; // Ensure index < len(list) DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); @@ -2351,12 +2349,13 @@ assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); - DEOPT_IF((size_t)(Py_SIZE(left) + 1) > 2, COMPARE_AND_BRANCH); - DEOPT_IF((size_t)(Py_SIZE(right) + 1) > 2, COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_AND_BRANCH); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_AND_BRANCH); STAT_INC(COMPARE_AND_BRANCH, hit); - assert(Py_ABS(Py_SIZE(left)) <= 1 && Py_ABS(Py_SIZE(right)) <= 1); - Py_ssize_t ileft = Py_SIZE(left) * ((PyLongObject *)left)->long_value.ob_digit[0]; - Py_ssize_t iright = Py_SIZE(right) * ((PyLongObject *)right)->long_value.ob_digit[0]; + assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 && + _PyLong_DigitCount((PyLongObject *)right) <= 1); + Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left); + Py_ssize_t iright = _PyLong_CompactValue((PyLongObject *)right); // 2 if <, 4 if >, 8 if ==; this matches the low 4 bits of the oparg int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); diff --git a/Python/marshal.c b/Python/marshal.c index 94e79d4392ae6d..2966139cec9ae9 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -11,6 +11,7 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_code.h" // _PyCode_New() +#include "pycore_long.h" // _PyLong_DigitCount #include "pycore_hashtable.h" // _Py_hashtable_t #include "marshal.h" // Py_MARSHAL_VERSION @@ -232,13 +233,13 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p) digit d; W_TYPE(TYPE_LONG, p); - if (Py_SIZE(ob) == 0) { + if (_PyLong_IsZero(ob)) { w_long((long)0, p); return; } /* set l to number of base PyLong_MARSHAL_BASE digits */ - n = Py_ABS(Py_SIZE(ob)); + n = _PyLong_DigitCount(ob); l = (n-1) * PyLong_MARSHAL_RATIO; d = ob->long_value.ob_digit[n-1]; assert(d != 0); /* a PyLong is always normalized */ @@ -251,7 +252,7 @@ w_PyLong(const PyLongObject *ob, char flag, WFILE *p) p->error = WFERR_UNMARSHALLABLE; return; } - w_long((long)(Py_SIZE(ob) > 0 ? l : -l), p); + w_long((long)(_PyLong_IsNegative(ob) ? -l : l), p); for (i=0; i < n-1; i++) { d = ob->long_value.ob_digit[i]; @@ -839,7 +840,7 @@ r_PyLong(RFILE *p) if (ob == NULL) return NULL; - Py_SET_SIZE(ob, n > 0 ? size : -size); + _PyLong_SetSignAndDigitCount(ob, n < 0 ? -1 : 1, size); for (i = 0; i < size-1; i++) { d = 0; diff --git a/Python/specialize.c b/Python/specialize.c index 719bd5bda329ff..2e93ab193990a1 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1308,7 +1308,7 @@ _Py_Specialize_BinarySubscr( PyTypeObject *container_type = Py_TYPE(container); if (container_type == &PyList_Type) { if (PyLong_CheckExact(sub)) { - if (Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1) { + if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { instr->op.code = BINARY_SUBSCR_LIST_INT; goto success; } @@ -1321,7 +1321,7 @@ _Py_Specialize_BinarySubscr( } if (container_type == &PyTuple_Type) { if (PyLong_CheckExact(sub)) { - if (Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1) { + if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) { instr->op.code = BINARY_SUBSCR_TUPLE_INT; goto success; } @@ -1389,7 +1389,7 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins PyTypeObject *container_type = Py_TYPE(container); if (container_type == &PyList_Type) { if (PyLong_CheckExact(sub)) { - if ((Py_SIZE(sub) == 0 || Py_SIZE(sub) == 1) + if (_PyLong_IsNonNegativeCompact((PyLongObject *)sub) && ((PyLongObject *)sub)->long_value.ob_digit[0] < (size_t)PyList_GET_SIZE(container)) { instr->op.code = STORE_SUBSCR_LIST_INT; @@ -2007,7 +2007,7 @@ _Py_Specialize_CompareAndBranch(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *inst goto success; } if (PyLong_CheckExact(lhs)) { - if (Py_ABS(Py_SIZE(lhs)) <= 1 && Py_ABS(Py_SIZE(rhs)) <= 1) { + if (_PyLong_IsCompact((PyLongObject *)lhs) && _PyLong_IsCompact((PyLongObject *)rhs)) { instr->op.code = COMPARE_AND_BRANCH_INT; goto success; } diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py index 26a1d3b99e1f7f..b22d5b75139d80 100644 --- a/Tools/build/deepfreeze.py +++ b/Tools/build/deepfreeze.py @@ -312,7 +312,7 @@ def generate_tuple(self, name: str, t: Tuple[object, ...]) -> str: return f"& {name}._object.ob_base.ob_base" def _generate_int_for_bits(self, name: str, i: int, digit: int) -> None: - sign = -1 if i < 0 else 0 if i == 0 else +1 + sign = (i > 0) - (i < 0) i = abs(i) digits: list[int] = [] while i: @@ -321,10 +321,12 @@ def _generate_int_for_bits(self, name: str, i: int, digit: int) -> None: self.write("static") with self.indent(): with self.block("struct"): - self.write("PyObject_VAR_HEAD") + self.write("PyObject ob_base;") + self.write("uintptr_t lv_tag;") self.write(f"digit ob_digit[{max(1, len(digits))}];") with self.block(f"{name} =", ";"): - self.object_var_head("PyLong_Type", sign*len(digits)) + self.object_head("PyLong_Type") + self.write(f".lv_tag = TAG_FROM_SIGN_AND_SIZE({sign}, {len(digits)}),") if digits: ds = ", ".join(map(str, digits)) self.write(f".ob_digit = {{ {ds} }},") @@ -348,7 +350,7 @@ def generate_int(self, name: str, i: int) -> str: self.write('#error "PYLONG_BITS_IN_DIGIT should be 15 or 30"') self.write("#endif") # If neither clause applies, it won't compile - return f"& {name}.ob_base.ob_base" + return f"& {name}.ob_base" def generate_float(self, name: str, x: float) -> str: with self.block(f"static PyFloatObject {name} =", ";"): diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py index 56d6970b29249c..e38bd59e20a305 100755 --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -882,10 +882,16 @@ class PyLongObjectPtr(PyObjectPtr): def proxyval(self, visited): ''' Python's Include/longobjrep.h has this declaration: - struct _longobject { - PyObject_VAR_HEAD - digit ob_digit[1]; - }; + + typedef struct _PyLongValue { + uintptr_t lv_tag; /* Number of digits, sign and flags */ + digit ob_digit[1]; + } _PyLongValue; + + struct _longobject { + PyObject_HEAD + _PyLongValue long_value; + }; with this description: The absolute value of a number is equal to @@ -897,11 +903,13 @@ def proxyval(self, visited): #define PyLong_SHIFT 30 #define PyLong_SHIFT 15 ''' - ob_size = int(self.field('ob_size')) - if ob_size == 0: + long_value = self.field('long_value') + lv_tag = int(long_value['lv_tag']) + size = lv_tag >> 3 + if size == 0: return 0 - ob_digit = self.field('long_value')['ob_digit'] + ob_digit = long_value['ob_digit'] if gdb.lookup_type('digit').sizeof == 2: SHIFT = 15 @@ -909,9 +917,9 @@ def proxyval(self, visited): SHIFT = 30 digits = [int(ob_digit[i]) * 2**(SHIFT*i) - for i in safe_range(abs(ob_size))] + for i in safe_range(size)] result = sum(digits) - if ob_size < 0: + if (lv_tag & 3) == 2: result = -result return result From ae4c54b1cd2c0e2988d092c0e9a96ad30e1f29a1 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Wed, 22 Mar 2023 17:59:32 +0300 Subject: [PATCH 189/280] gh-102033: Fix syntax error in `Tools/c-analyzer` (GH-102066) The easiest way to format strings with `{}` meaningful chars is via `%`. --- Tools/c-analyzer/c_analyzer/__main__.py | 2 - Tools/c-analyzer/c_analyzer/info.py | 4 - Tools/c-analyzer/c_common/info.py | 0 Tools/c-analyzer/c_common/iterutil.py | 4 - Tools/c-analyzer/c_common/show.py | 0 Tools/c-analyzer/c_parser/__main__.py | 4 - Tools/c-analyzer/c_parser/_state_machine.py | 244 -------------------- Tools/c-analyzer/c_parser/info.py | 3 +- Tools/c-analyzer/c_parser/parser/_alt.py | 6 - Tools/c-analyzer/c_parser/parser/_delim.py | 54 ----- Tools/c-analyzer/c_parser/parser/_global.py | 1 - Tools/c-analyzer/cpython/__main__.py | 2 - Tools/c-analyzer/cpython/_analyzer.py | 4 - Tools/c-analyzer/cpython/_capi.py | 10 +- 14 files changed, 3 insertions(+), 335 deletions(-) delete mode 100644 Tools/c-analyzer/c_common/info.py delete mode 100644 Tools/c-analyzer/c_common/show.py delete mode 100644 Tools/c-analyzer/c_parser/_state_machine.py delete mode 100644 Tools/c-analyzer/c_parser/parser/_alt.py delete mode 100644 Tools/c-analyzer/c_parser/parser/_delim.py diff --git a/Tools/c-analyzer/c_analyzer/__main__.py b/Tools/c-analyzer/c_analyzer/__main__.py index 5d89b29adf899e..cde39bc4e649d9 100644 --- a/Tools/c-analyzer/c_analyzer/__main__.py +++ b/Tools/c-analyzer/c_analyzer/__main__.py @@ -18,10 +18,8 @@ configure_logger, get_prog, filter_filenames, - iter_marks, ) from c_parser.info import KIND -from c_parser.match import is_type_decl from .match import filter_forward from . import ( analyze as _analyze, diff --git a/Tools/c-analyzer/c_analyzer/info.py b/Tools/c-analyzer/c_analyzer/info.py index 27c3a5a4ee76f2..d231e07a60dd8e 100644 --- a/Tools/c-analyzer/c_analyzer/info.py +++ b/Tools/c-analyzer/c_analyzer/info.py @@ -1,4 +1,3 @@ -from collections import namedtuple import os.path from c_common import fsutil @@ -13,9 +12,6 @@ from c_parser.match import ( is_type_decl, ) -from .match import ( - is_process_global, -) IGNORED = _misc.Labeled('IGNORED') diff --git a/Tools/c-analyzer/c_common/info.py b/Tools/c-analyzer/c_common/info.py deleted file mode 100644 index e69de29bb2d1d6..00000000000000 diff --git a/Tools/c-analyzer/c_common/iterutil.py b/Tools/c-analyzer/c_common/iterutil.py index 6ded105304e454..dda3dd57c1cf5c 100644 --- a/Tools/c-analyzer/c_common/iterutil.py +++ b/Tools/c-analyzer/c_common/iterutil.py @@ -1,7 +1,3 @@ - -_NOT_SET = object() - - def peek_and_iter(items): if not items: return None, None diff --git a/Tools/c-analyzer/c_common/show.py b/Tools/c-analyzer/c_common/show.py deleted file mode 100644 index e69de29bb2d1d6..00000000000000 diff --git a/Tools/c-analyzer/c_parser/__main__.py b/Tools/c-analyzer/c_parser/__main__.py index 78f47a1808f50b..2454fcba814291 100644 --- a/Tools/c-analyzer/c_parser/__main__.py +++ b/Tools/c-analyzer/c_parser/__main__.py @@ -1,10 +1,7 @@ import logging -import os.path import sys -from c_common import fsutil from c_common.scriptutil import ( - CLIArgSpec as Arg, add_verbosity_cli, add_traceback_cli, add_kind_filtering_cli, @@ -15,7 +12,6 @@ get_prog, main_for_filenames, ) -from .preprocessor import get_preprocessor from .preprocessor.__main__ import ( add_common_cli as add_preprocessor_cli, ) diff --git a/Tools/c-analyzer/c_parser/_state_machine.py b/Tools/c-analyzer/c_parser/_state_machine.py deleted file mode 100644 index 875323188aadfd..00000000000000 --- a/Tools/c-analyzer/c_parser/_state_machine.py +++ /dev/null @@ -1,244 +0,0 @@ - -f''' - struct {ANON_IDENTIFIER}; - struct {{ ... }} - struct {IDENTIFIER} {{ ... }} - - union {ANON_IDENTIFIER}; - union {{ ... }} - union {IDENTIFIER} {{ ... }} - - enum {ANON_IDENTIFIER}; - enum {{ ... }} - enum {IDENTIFIER} {{ ... }} - - typedef {VARTYPE} {IDENTIFIER}; - typedef {IDENTIFIER}; - typedef {IDENTIFIER}; - typedef {IDENTIFIER}; -''' - - -def parse(srclines): - if isinstance(srclines, str): # a filename - raise NotImplementedError - - - -# This only handles at most 10 nested levels. -#MATCHED_PARENS = textwrap.dedent(rf''' -# # matched parens -# (?: -# [(] # level 0 -# (?: -# [^()]* -# [(] # level 1 -# (?: -# [^()]* -# [(] # level 2 -# (?: -# [^()]* -# [(] # level 3 -# (?: -# [^()]* -# [(] # level 4 -# (?: -# [^()]* -# [(] # level 5 -# (?: -# [^()]* -# [(] # level 6 -# (?: -# [^()]* -# [(] # level 7 -# (?: -# [^()]* -# [(] # level 8 -# (?: -# [^()]* -# [(] # level 9 -# (?: -# [^()]* -# [(] # level 10 -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# )* -# [^()]* -# [)] -# ) -# # end matched parens -# ''') - -r''' - # for loop - (?: - \s* \b for - \s* [(] - ( - [^;]* ; - [^;]* ; - .*? - ) #
- [)] - \s* - (?: - (?: - ( - {_ind(SIMPLE_STMT, 6)} - ) # - ; - ) - | - ( {{ ) # - ) - ) - | - - - - ( - (?: - (?: - (?: - {_ind(SIMPLE_STMT, 6)} - )? - return \b \s* - {_ind(INITIALIZER, 5)} - ) - | - (?: - (?: - {IDENTIFIER} \s* - (?: . | -> ) \s* - )* - {IDENTIFIER} - \s* = \s* - {_ind(INITIALIZER, 5)} - ) - | - (?: - {_ind(SIMPLE_STMT, 5)} - ) - ) - | - # cast compound literal - (?: - (?: - [^'"{{}};]* - {_ind(STRING_LITERAL, 5)} - )* - [^'"{{}};]*? - [^'"{{}};=] - = - \s* [(] [^)]* [)] - \s* {{ [^;]* }} - ) - ) # - - - - # compound statement - (?: - ( - (?: - - # "for" statements are handled separately above. - (?: (?: else \s+ )? if | switch | while ) \s* - {_ind(COMPOUND_HEAD, 5)} - ) - | - (?: else | do ) - # We do not worry about compound statements for labels, - # "case", or "default". - )? #
- \s* - ( {{ ) # - ) - - - - ( - (?: - [^'"{{}};]* - {_ind(STRING_LITERAL, 5)} - )* - [^'"{{}};]* - # Presumably we will not see "== {{". - [^\s='"{{}};] - )? #
- - - - ( - \b - (?: - # We don't worry about labels with a compound statement. - (?: - switch \s* [(] [^{{]* [)] - ) - | - (?: - case \b \s* [^:]+ [:] - ) - | - (?: - default \s* [:] - ) - | - (?: - do - ) - | - (?: - while \s* [(] [^{{]* [)] - ) - | - #(?: - # for \s* [(] [^{{]* [)] - # ) - #| - (?: - if \s* [(] - (?: [^{{]* [^)] \s* {{ )* [^{{]* - [)] - ) - | - (?: - else - (?: - \s* - if \s* [(] - (?: [^{{]* [^)] \s* {{ )* [^{{]* - [)] - )? - ) - ) - )? #
-''' diff --git a/Tools/c-analyzer/c_parser/info.py b/Tools/c-analyzer/c_parser/info.py index 3fa9fefbd5ec0b..799f9237877447 100644 --- a/Tools/c-analyzer/c_parser/info.py +++ b/Tools/c-analyzer/c_parser/info.py @@ -1,6 +1,5 @@ from collections import namedtuple import enum -import os.path import re from c_common import fsutil @@ -8,7 +7,7 @@ import c_common.misc as _misc import c_common.strutil as _strutil import c_common.tables as _tables -from .parser._regexes import SIMPLE_TYPE, _STORAGE +from .parser._regexes import _STORAGE FIXED_TYPE = _misc.Labeled('FIXED_TYPE') diff --git a/Tools/c-analyzer/c_parser/parser/_alt.py b/Tools/c-analyzer/c_parser/parser/_alt.py deleted file mode 100644 index 05a9101b4f529a..00000000000000 --- a/Tools/c-analyzer/c_parser/parser/_alt.py +++ /dev/null @@ -1,6 +0,0 @@ - -def _parse(srclines, anon_name): - text = ' '.join(l for _, l in srclines) - - from ._delim import parse - yield from parse(text, anon_name) diff --git a/Tools/c-analyzer/c_parser/parser/_delim.py b/Tools/c-analyzer/c_parser/parser/_delim.py deleted file mode 100644 index 51433a629d3a35..00000000000000 --- a/Tools/c-analyzer/c_parser/parser/_delim.py +++ /dev/null @@ -1,54 +0,0 @@ -import re -import textwrap - -from ._regexes import _ind, STRING_LITERAL - - -def parse(text, anon_name): - context = None - data = None - for m in DELIMITER_RE.find_iter(text): - before, opened, closed = m.groups() - delim = opened or closed - - handle_segment = HANDLERS[context][delim] - result, context, data = handle_segment(before, delim, data) - if result: - yield result - - -DELIMITER = textwrap.dedent(rf''' - ( - (?: - [^'"()\[\]{};]* - {_ind(STRING_LITERAL, 3)} - }* - [^'"()\[\]{};]+ - )? # - (?: - ( - [(\[{] - ) # - | - ( - [)\]};] - ) # - )? - ''') -DELIMITER_RE = re.compile(DELIMITER, re.VERBOSE) - -_HANDLERS = { - None: { # global - # opened - '{': ..., - '[': None, - '(': None, - # closed - '}': None, - ']': None, - ')': None, - ';': ..., - }, - '': { - }, -} diff --git a/Tools/c-analyzer/c_parser/parser/_global.py b/Tools/c-analyzer/c_parser/parser/_global.py index 35947c12998135..b1ac9f5db034e1 100644 --- a/Tools/c-analyzer/c_parser/parser/_global.py +++ b/Tools/c-analyzer/c_parser/parser/_global.py @@ -9,7 +9,6 @@ set_capture_groups, ) from ._compound_decl_body import DECL_BODY_PARSERS -#from ._func_body import parse_function_body from ._func_body import parse_function_statics as parse_function_body diff --git a/Tools/c-analyzer/cpython/__main__.py b/Tools/c-analyzer/cpython/__main__.py index fe7a16726f45a9..ec026c6932f1f4 100644 --- a/Tools/c-analyzer/cpython/__main__.py +++ b/Tools/c-analyzer/cpython/__main__.py @@ -2,7 +2,6 @@ import sys import textwrap -from c_common.fsutil import expand_filenames, iter_files_by_suffix from c_common.scriptutil import ( VERBOSITY, add_verbosity_cli, @@ -11,7 +10,6 @@ add_kind_filtering_cli, add_files_cli, add_progress_cli, - main_for_filenames, process_args_by_key, configure_logger, get_prog, diff --git a/Tools/c-analyzer/cpython/_analyzer.py b/Tools/c-analyzer/cpython/_analyzer.py index cfe5e75f2f4df6..68d6b31cf2b6f0 100644 --- a/Tools/c-analyzer/cpython/_analyzer.py +++ b/Tools/c-analyzer/cpython/_analyzer.py @@ -4,16 +4,12 @@ from c_common.clsutil import classonly from c_parser.info import ( KIND, - DeclID, Declaration, TypeDeclaration, - TypeDef, - Struct, Member, FIXED_TYPE, ) from c_parser.match import ( - is_type_decl, is_pots, is_funcptr, ) diff --git a/Tools/c-analyzer/cpython/_capi.py b/Tools/c-analyzer/cpython/_capi.py index df8159a8cc169f..4552f71479bd06 100644 --- a/Tools/c-analyzer/cpython/_capi.py +++ b/Tools/c-analyzer/cpython/_capi.py @@ -7,7 +7,7 @@ from c_common.tables import build_table, resolve_columns from c_parser.parser._regexes import _ind -from ._files import iter_header_files, resolve_filename +from ._files import iter_header_files from . import REPO_ROOT @@ -610,8 +610,7 @@ def _render_item_full(item, groupby, verbose): yield item.name yield f' {"filename:":10} {item.relfile}' for extra in ('kind', 'level'): - #if groupby != extra: - yield f' {extra+":":10} {getattr(item, extra)}' + yield f' {extra+":":10} {getattr(item, extra)}' if verbose: print(' ---------------------------------------') for lno, line in enumerate(item.text, item.lno): @@ -636,7 +635,6 @@ def render_summary(items, *, subtotals = summary['totals']['subs'] bygroup = summary['totals']['bygroup'] - lastempty = False for outer, subtotal in subtotals.items(): if bygroup: subtotal = f'({subtotal})' @@ -646,10 +644,6 @@ def render_summary(items, *, if outer in bygroup: for inner, count in bygroup[outer].items(): yield f' {inner + ":":9} {count}' - lastempty = False - else: - lastempty = True - total = f'*{summary["totals"]["all"]}*' label = '*total*:' if bygroup: From 4080fb759a013aaeebd8fe8ee9951b573a9d8771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristj=C3=A1n=20Valur=20J=C3=B3nsson?= Date: Wed, 22 Mar 2023 17:52:10 +0000 Subject: [PATCH 190/280] gh-102780: Fix uncancel() call in asyncio timeouts (#102815) Also use `raise TimeOut from ` so that the CancelledError is set in the `__cause__` field rather than in the `__context__` field. Co-authored-by: Guido van Rossum Co-authored-by: Alex Waygood --- Doc/library/asyncio-task.rst | 16 ++++++++-- Lib/asyncio/timeouts.py | 7 +++-- Lib/test/test_asyncio/test_timeouts.py | 30 +++++++++++++++++++ ...-03-22-16-15-18.gh-issue-102780.NEcljy.rst | 3 ++ 4 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index a0900cd25a7731..d908e45b3c8d8b 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -300,13 +300,17 @@ in the task at the next opportunity. It is recommended that coroutines use ``try/finally`` blocks to robustly perform clean-up logic. In case :exc:`asyncio.CancelledError` is explicitly caught, it should generally be propagated when -clean-up is complete. Most code can safely ignore :exc:`asyncio.CancelledError`. +clean-up is complete. :exc:`asyncio.CancelledError` directly subclasses +:exc:`BaseException` so most code will not need to be aware of it. The asyncio components that enable structured concurrency, like :class:`asyncio.TaskGroup` and :func:`asyncio.timeout`, are implemented using cancellation internally and might misbehave if a coroutine swallows :exc:`asyncio.CancelledError`. Similarly, user code -should not call :meth:`uncancel `. +should not generally call :meth:`uncancel `. +However, in cases when suppressing :exc:`asyncio.CancelledError` is +truly desired, it is necessary to also call ``uncancel()`` to completely +remove the cancellation state. .. _taskgroups: @@ -1148,7 +1152,9 @@ Task Object Therefore, unlike :meth:`Future.cancel`, :meth:`Task.cancel` does not guarantee that the Task will be cancelled, although suppressing cancellation completely is not common and is actively - discouraged. + discouraged. Should the coroutine nevertheless decide to suppress + the cancellation, it needs to call :meth:`Task.uncancel` in addition + to catching the exception. .. versionchanged:: 3.9 Added the *msg* parameter. @@ -1238,6 +1244,10 @@ Task Object with :meth:`uncancel`. :class:`TaskGroup` context managers use :func:`uncancel` in a similar fashion. + If end-user code is, for some reason, suppresing cancellation by + catching :exc:`CancelledError`, it needs to call this method to remove + the cancellation state. + .. method:: cancelling() Return the number of pending cancellation requests to this Task, i.e., diff --git a/Lib/asyncio/timeouts.py b/Lib/asyncio/timeouts.py index d07b291005e8f9..029c468739bf2d 100644 --- a/Lib/asyncio/timeouts.py +++ b/Lib/asyncio/timeouts.py @@ -84,6 +84,7 @@ def __repr__(self) -> str: async def __aenter__(self) -> "Timeout": self._state = _State.ENTERED self._task = tasks.current_task() + self._cancelling = self._task.cancelling() if self._task is None: raise RuntimeError("Timeout should be used inside a task") self.reschedule(self._when) @@ -104,10 +105,10 @@ async def __aexit__( if self._state is _State.EXPIRING: self._state = _State.EXPIRED - if self._task.uncancel() == 0 and exc_type is exceptions.CancelledError: - # Since there are no outstanding cancel requests, we're + if self._task.uncancel() <= self._cancelling and exc_type is exceptions.CancelledError: + # Since there are no new cancel requests, we're # handling this. - raise TimeoutError + raise TimeoutError from exc_val elif self._state is _State.ENTERED: self._state = _State.EXITED diff --git a/Lib/test/test_asyncio/test_timeouts.py b/Lib/test/test_asyncio/test_timeouts.py index b9bac6f783776b..8b6b9a1fea0be8 100644 --- a/Lib/test/test_asyncio/test_timeouts.py +++ b/Lib/test/test_asyncio/test_timeouts.py @@ -247,6 +247,36 @@ async def test_nested_timeout_in_finally(self): async with asyncio.timeout(0.01): await asyncio.sleep(10) + async def test_timeout_after_cancellation(self): + try: + asyncio.current_task().cancel() + await asyncio.sleep(1) # work which will be cancelled + except asyncio.CancelledError: + pass + finally: + with self.assertRaises(TimeoutError): + async with asyncio.timeout(0.0): + await asyncio.sleep(1) # some cleanup + + async def test_cancel_in_timeout_after_cancellation(self): + try: + asyncio.current_task().cancel() + await asyncio.sleep(1) # work which will be cancelled + except asyncio.CancelledError: + pass + finally: + with self.assertRaises(asyncio.CancelledError): + async with asyncio.timeout(1.0): + asyncio.current_task().cancel() + await asyncio.sleep(2) # some cleanup + + async def test_timeout_exception_cause (self): + with self.assertRaises(asyncio.TimeoutError) as exc: + async with asyncio.timeout(0): + await asyncio.sleep(1) + cause = exc.exception.__cause__ + assert isinstance(cause, asyncio.CancelledError) + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst b/Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst new file mode 100644 index 00000000000000..2aaffe34b86414 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-22-16-15-18.gh-issue-102780.NEcljy.rst @@ -0,0 +1,3 @@ +The :class:`asyncio.Timeout` context manager now works reliably even when performing cleanup due +to task cancellation. Previously it could raise a +:exc:`~asyncio.CancelledError` instead of an :exc:`~asyncio.TimeoutError` in such cases. From 27f390bef395d57558c922b2c23be1c8be3d70f3 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Wed, 22 Mar 2023 18:10:48 +0000 Subject: [PATCH 191/280] gh-102859: Remove JUMP_IF_FALSE_OR_POP and JUMP_IF_TRUE_OR_POP (#102870) --- Doc/library/dis.rst | 24 --- Doc/whatsnew/3.12.rst | 3 + Include/internal/pycore_opcode.h | 30 +-- Include/opcode.h | 108 +++++----- Lib/importlib/_bootstrap_external.py | 3 +- Lib/opcode.py | 2 - Lib/test/test__opcode.py | 4 - Lib/test/test_peepholer.py | 24 +-- ...-03-21-00-46-36.gh-issue-102859.PRkGca.rst | 2 + Objects/frameobject.c | 14 +- Python/bytecodes.c | 123 ----------- Python/compile.c | 192 +++++++----------- Python/generated_cases.c.h | 142 ------------- Python/opcode_metadata.h | 25 --- Python/opcode_targets.h | 20 +- Python/tier2_typepropagator.c.h | 29 --- 16 files changed, 173 insertions(+), 572 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-03-21-00-46-36.gh-issue-102859.PRkGca.rst diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index f4f47b3bf4846d..b06fe67a983aa1 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1152,30 +1152,6 @@ iterations of the loop. .. versionchanged:: 3.12 This is no longer a pseudo-instruction. - -.. opcode:: JUMP_IF_TRUE_OR_POP (delta) - - If ``STACK[-1]`` is true, increments the bytecode counter by *delta* and leaves - ``STACK[-1]`` on the stack. Otherwise (``STACK[-1]`` is false), ``STACK[-1]`` - is popped. - - .. versionadded:: 3.1 - - .. versionchanged:: 3.11 - The oparg is now a relative delta rather than an absolute target. - -.. opcode:: JUMP_IF_FALSE_OR_POP (delta) - - If ``STACK[-1]`` is false, increments the bytecode counter by *delta* and leaves - ``STACK[-1]`` on the stack. Otherwise (``STACK[-1]`` is true), ``STACK[-1]`` is - popped. - - .. versionadded:: 3.1 - - .. versionchanged:: 3.11 - The oparg is now a relative delta rather than an absolute target. - - .. opcode:: FOR_ITER (delta) ``STACK[-1]`` is an :term:`iterator`. Call its :meth:`~iterator.__next__` method. diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index b7c956d7f78456..06ea416d751354 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -435,6 +435,9 @@ CPython bytecode changes :opcode:`LOAD_METHOD` instruction if the low bit of its oparg is set. (Contributed by Ken Jin in :gh:`93429`.) +* Removed the :opcode:`JUMP_IF_FALSE_OR_POP` and :opcode:`JUMP_IF_TRUE_OR_POP` + instructions. (Contributed by Irit Katriel in :gh:`102859`.) + Demos and Tools =============== diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 5dd2ed17adee51..4a3270dd11b2de 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -21,7 +21,7 @@ static const uint32_t _PyOpcode_RelativeJump[9] = { 0U, 0U, 536870912U, - 135118848U, + 135020544U, 4163U, 0U, 0U, @@ -32,7 +32,7 @@ static const uint32_t _PyOpcode_Jump[9] = { 0U, 0U, 536870912U, - 135118848U, + 135020544U, 4163U, 0U, 0U, @@ -148,8 +148,6 @@ const uint8_t _PyOpcode_Deopt[256] = { [JUMP_BACKWARD_NO_INTERRUPT] = JUMP_BACKWARD_NO_INTERRUPT, [JUMP_BACKWARD_QUICK] = JUMP_BACKWARD, [JUMP_FORWARD] = JUMP_FORWARD, - [JUMP_IF_FALSE_OR_POP] = JUMP_IF_FALSE_OR_POP, - [JUMP_IF_TRUE_OR_POP] = JUMP_IF_TRUE_OR_POP, [KW_NAMES] = KW_NAMES, [LIST_APPEND] = LIST_APPEND, [LIST_EXTEND] = LIST_EXTEND, @@ -348,9 +346,9 @@ static const char *const _PyOpcode_OpName[263] = { [IMPORT_NAME] = "IMPORT_NAME", [IMPORT_FROM] = "IMPORT_FROM", [JUMP_FORWARD] = "JUMP_FORWARD", - [JUMP_IF_FALSE_OR_POP] = "JUMP_IF_FALSE_OR_POP", - [JUMP_IF_TRUE_OR_POP] = "JUMP_IF_TRUE_OR_POP", [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", + [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", + [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -380,7 +378,7 @@ static const char *const _PyOpcode_OpName[263] = { [JUMP_BACKWARD] = "JUMP_BACKWARD", [COMPARE_AND_BRANCH] = "COMPARE_AND_BRANCH", [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", - [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", + [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -390,30 +388,28 @@ static const char *const _PyOpcode_OpName[263] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", - [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", - [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", + [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", + [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", - [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", - [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", + [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", + [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", - [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", - [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", + [SEND_GEN] = "SEND_GEN", + [BB_BRANCH] = "BB_BRANCH", [CALL] = "CALL", [KW_NAMES] = "KW_NAMES", [CALL_INTRINSIC_1] = "CALL_INTRINSIC_1", [CALL_INTRINSIC_2] = "CALL_INTRINSIC_2", - [SEND_GEN] = "SEND_GEN", - [BB_BRANCH] = "BB_BRANCH", [BB_BRANCH_IF_FLAG_UNSET] = "BB_BRANCH_IF_FLAG_UNSET", [BB_BRANCH_IF_FLAG_SET] = "BB_BRANCH_IF_FLAG_SET", [BB_JUMP_IF_FLAG_UNSET] = "BB_JUMP_IF_FLAG_UNSET", @@ -438,6 +434,8 @@ static const char *const _PyOpcode_OpName[263] = { [STORE_FAST_BOXED_UNBOXED] = "STORE_FAST_BOXED_UNBOXED", [STORE_FAST_UNBOXED_BOXED] = "STORE_FAST_UNBOXED_BOXED", [STORE_FAST_UNBOXED_UNBOXED] = "STORE_FAST_UNBOXED_UNBOXED", + [199] = "<199>", + [200] = "<200>", [201] = "<201>", [202] = "<202>", [203] = "<203>", @@ -505,6 +503,8 @@ static const char *const _PyOpcode_OpName[263] = { #define EXTRA_CASES \ + case 199: \ + case 200: \ case 201: \ case 202: \ case 203: \ diff --git a/Include/opcode.h b/Include/opcode.h index 1a883aafd96f1b..6f02501b835718 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -66,8 +66,6 @@ extern "C" { #define IMPORT_NAME 108 #define IMPORT_FROM 109 #define JUMP_FORWARD 110 -#define JUMP_IF_FALSE_OR_POP 111 -#define JUMP_IF_TRUE_OR_POP 112 #define POP_JUMP_IF_FALSE 114 #define POP_JUMP_IF_TRUE 115 #define LOAD_GLOBAL 116 @@ -180,20 +178,20 @@ extern "C" { #define LOAD_ATTR_METHOD_WITH_VALUES 86 #define LOAD_CONST__LOAD_FAST 87 #define LOAD_FAST__LOAD_CONST 88 -#define LOAD_FAST__LOAD_FAST 113 -#define LOAD_GLOBAL_BUILTIN 143 -#define LOAD_GLOBAL_MODULE 153 -#define STORE_ATTR_INSTANCE_VALUE 154 -#define STORE_ATTR_SLOT 158 -#define STORE_ATTR_WITH_HINT 159 -#define STORE_FAST__LOAD_FAST 160 -#define STORE_FAST__STORE_FAST 161 -#define STORE_SUBSCR_DICT 166 -#define STORE_SUBSCR_LIST_INT 167 -#define UNPACK_SEQUENCE_LIST 168 -#define UNPACK_SEQUENCE_TUPLE 169 -#define UNPACK_SEQUENCE_TWO_TUPLE 170 -#define SEND_GEN 175 +#define LOAD_FAST__LOAD_FAST 111 +#define LOAD_GLOBAL_BUILTIN 112 +#define LOAD_GLOBAL_MODULE 113 +#define STORE_ATTR_INSTANCE_VALUE 143 +#define STORE_ATTR_SLOT 153 +#define STORE_ATTR_WITH_HINT 154 +#define STORE_FAST__LOAD_FAST 158 +#define STORE_FAST__STORE_FAST 159 +#define STORE_SUBSCR_DICT 160 +#define STORE_SUBSCR_LIST_INT 161 +#define UNPACK_SEQUENCE_LIST 166 +#define UNPACK_SEQUENCE_TUPLE 167 +#define UNPACK_SEQUENCE_TWO_TUPLE 168 +#define SEND_GEN 169 #define DO_TRACING 255 // Tier 2 interpreter ops #define RESUME_QUICK 5 @@ -250,46 +248,46 @@ extern "C" { #define LOAD_ATTR_METHOD_WITH_VALUES 86 #define LOAD_CONST__LOAD_FAST 87 #define LOAD_FAST__LOAD_CONST 88 -#define LOAD_FAST__LOAD_FAST 113 -#define LOAD_GLOBAL_BUILTIN 143 -#define LOAD_GLOBAL_MODULE 153 -#define STORE_ATTR_INSTANCE_VALUE 154 -#define STORE_ATTR_SLOT 158 -#define STORE_ATTR_WITH_HINT 159 -#define STORE_FAST__LOAD_FAST 160 -#define STORE_FAST__STORE_FAST 161 -#define STORE_SUBSCR_DICT 166 -#define STORE_SUBSCR_LIST_INT 167 -#define UNPACK_SEQUENCE_LIST 168 -#define UNPACK_SEQUENCE_TUPLE 169 -#define UNPACK_SEQUENCE_TWO_TUPLE 170 -#define SEND_GEN 175 +#define LOAD_FAST__LOAD_FAST 111 +#define LOAD_GLOBAL_BUILTIN 112 +#define LOAD_GLOBAL_MODULE 113 +#define STORE_ATTR_INSTANCE_VALUE 143 +#define STORE_ATTR_SLOT 153 +#define STORE_ATTR_WITH_HINT 154 +#define STORE_FAST__LOAD_FAST 158 +#define STORE_FAST__STORE_FAST 159 +#define STORE_SUBSCR_DICT 160 +#define STORE_SUBSCR_LIST_INT 161 +#define UNPACK_SEQUENCE_LIST 166 +#define UNPACK_SEQUENCE_TUPLE 167 +#define UNPACK_SEQUENCE_TWO_TUPLE 168 +#define SEND_GEN 169 #define DO_TRACING 255 -#define BB_BRANCH 176 -#define BB_BRANCH_IF_FLAG_UNSET 177 -#define BB_BRANCH_IF_FLAG_SET 178 -#define BB_JUMP_IF_FLAG_UNSET 179 -#define BB_JUMP_IF_FLAG_SET 180 -#define BB_TEST_ITER 181 -#define BB_TEST_IF_FALSE_OR_POP 182 -#define BB_TEST_IF_TRUE_OR_POP 183 -#define BB_TEST_POP_IF_FALSE 184 -#define BB_TEST_POP_IF_TRUE 185 -#define BB_TEST_POP_IF_NOT_NONE 186 -#define BB_TEST_POP_IF_NONE 187 -#define BB_JUMP_BACKWARD_LAZY 188 -#define BINARY_CHECK_INT 189 -#define BINARY_CHECK_FLOAT 190 -#define UNARY_CHECK_FLOAT 191 -#define BINARY_OP_ADD_INT_REST 192 -#define BINARY_OP_ADD_FLOAT_UNBOXED 193 -#define POP_TOP_NO_DECREF 194 -#define UNBOX_FLOAT 195 -#define BOX_FLOAT 196 -#define LOAD_FAST_NO_INCREF 197 -#define STORE_FAST_BOXED_UNBOXED 198 -#define STORE_FAST_UNBOXED_BOXED 199 -#define STORE_FAST_UNBOXED_UNBOXED 200 +#define BB_BRANCH 170 +#define BB_BRANCH_IF_FLAG_UNSET 175 +#define BB_BRANCH_IF_FLAG_SET 176 +#define BB_JUMP_IF_FLAG_UNSET 177 +#define BB_JUMP_IF_FLAG_SET 178 +#define BB_TEST_ITER 179 +#define BB_TEST_IF_FALSE_OR_POP 180 +#define BB_TEST_IF_TRUE_OR_POP 181 +#define BB_TEST_POP_IF_FALSE 182 +#define BB_TEST_POP_IF_TRUE 183 +#define BB_TEST_POP_IF_NOT_NONE 184 +#define BB_TEST_POP_IF_NONE 185 +#define BB_JUMP_BACKWARD_LAZY 186 +#define BINARY_CHECK_INT 187 +#define BINARY_CHECK_FLOAT 188 +#define UNARY_CHECK_FLOAT 189 +#define BINARY_OP_ADD_INT_REST 190 +#define BINARY_OP_ADD_FLOAT_UNBOXED 191 +#define POP_TOP_NO_DECREF 192 +#define UNBOX_FLOAT 193 +#define BOX_FLOAT 194 +#define LOAD_FAST_NO_INCREF 195 +#define STORE_FAST_BOXED_UNBOXED 196 +#define STORE_FAST_UNBOXED_BOXED 197 +#define STORE_FAST_UNBOXED_UNBOXED 198 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index a01a0955182de5..3f78300c226345 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -435,6 +435,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12a6 3519 (Modify SEND instruction) # Python 3.12a6 3520 (Remove PREP_RERAISE_STAR, add CALL_INTRINSIC_2) # Python 3.12a7 3521 (Shrink the LOAD_GLOBAL caches) +# Python 3.12a7 3522 (Removed JUMP_IF_FALSE_OR_POP/JUMP_IF_TRUE_OR_POP) # Python 3.13 will start with 3550 @@ -451,7 +452,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3521).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3522).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/opcode.py b/Lib/opcode.py index 01e574509d38d5..cacbdaf575039f 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -154,8 +154,6 @@ def pseudo_op(name, op, real_ops): name_op('IMPORT_NAME', 108) # Index in name list name_op('IMPORT_FROM', 109) # Index in name list jrel_op('JUMP_FORWARD', 110) # Number of words to skip -jrel_op('JUMP_IF_FALSE_OR_POP', 111) # Number of words to skip -jrel_op('JUMP_IF_TRUE_OR_POP', 112) # "" jrel_op('POP_JUMP_IF_FALSE', 114) jrel_op('POP_JUMP_IF_TRUE', 115) name_op('LOAD_GLOBAL', 116) # Index in name list diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py index fb4ab15f7041ed..31f3c53992db13 100644 --- a/Lib/test/test__opcode.py +++ b/Lib/test/test__opcode.py @@ -34,10 +34,6 @@ def test_stack_effect(self): self.assertRaises(ValueError, stack_effect, code, 0) def test_stack_effect_jump(self): - JUMP_IF_TRUE_OR_POP = dis.opmap['JUMP_IF_TRUE_OR_POP'] - self.assertEqual(stack_effect(JUMP_IF_TRUE_OR_POP, 0), 0) - self.assertEqual(stack_effect(JUMP_IF_TRUE_OR_POP, 0, jump=True), 0) - self.assertEqual(stack_effect(JUMP_IF_TRUE_OR_POP, 0, jump=False), -1) FOR_ITER = dis.opmap['FOR_ITER'] self.assertEqual(stack_effect(FOR_ITER, 0), 1) self.assertEqual(stack_effect(FOR_ITER, 0, jump=True), 1) diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index 9ff017da53c2b1..01eb04b53060e9 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -52,10 +52,6 @@ def check_jump_targets(self, code): tgt.opname == 'RETURN_VALUE'): self.fail(f'{instr.opname} at {instr.offset} ' f'jumps to {tgt.opname} at {tgt.offset}') - # JUMP_IF_*_OR_POP jump to conditional jump - if '_OR_POP' in instr.opname and 'JUMP_IF_' in tgt.opname: - self.fail(f'{instr.opname} at {instr.offset} ' - f'jumps to {tgt.opname} at {tgt.offset}') def check_lnotab(self, code): "Check that the lnotab byte offsets are sensible." @@ -384,38 +380,36 @@ def f(): def test_elim_jump_to_uncond_jump3(self): # Intentionally use two-line expressions to test issue37213. - # JUMP_IF_FALSE_OR_POP to JUMP_IF_FALSE_OR_POP --> JUMP_IF_FALSE_OR_POP to non-jump + # POP_JUMP_IF_FALSE to POP_JUMP_IF_FALSE --> POP_JUMP_IF_FALSE to non-jump def f(a, b, c): return ((a and b) and c) self.check_jump_targets(f) self.check_lnotab(f) - self.assertEqual(count_instr_recursively(f, 'JUMP_IF_FALSE_OR_POP'), 2) - # JUMP_IF_TRUE_OR_POP to JUMP_IF_TRUE_OR_POP --> JUMP_IF_TRUE_OR_POP to non-jump + self.assertEqual(count_instr_recursively(f, 'POP_JUMP_IF_FALSE'), 2) + # POP_JUMP_IF_TRUE to POP_JUMP_IF_TRUE --> POP_JUMP_IF_TRUE to non-jump def f(a, b, c): return ((a or b) or c) self.check_jump_targets(f) self.check_lnotab(f) - self.assertEqual(count_instr_recursively(f, 'JUMP_IF_TRUE_OR_POP'), 2) + self.assertEqual(count_instr_recursively(f, 'POP_JUMP_IF_TRUE'), 2) # JUMP_IF_FALSE_OR_POP to JUMP_IF_TRUE_OR_POP --> POP_JUMP_IF_FALSE to non-jump def f(a, b, c): return ((a and b) or c) self.check_jump_targets(f) self.check_lnotab(f) - self.assertNotInBytecode(f, 'JUMP_IF_FALSE_OR_POP') - self.assertInBytecode(f, 'JUMP_IF_TRUE_OR_POP') - self.assertInBytecode(f, 'POP_JUMP_IF_FALSE') - # JUMP_IF_TRUE_OR_POP to JUMP_IF_FALSE_OR_POP --> POP_JUMP_IF_TRUE to non-jump + self.assertEqual(count_instr_recursively(f, 'POP_JUMP_IF_FALSE'), 1) + self.assertEqual(count_instr_recursively(f, 'POP_JUMP_IF_TRUE'), 1) + # POP_JUMP_IF_TRUE to POP_JUMP_IF_FALSE --> POP_JUMP_IF_TRUE to non-jump def f(a, b, c): return ((a or b) and c) self.check_jump_targets(f) self.check_lnotab(f) - self.assertNotInBytecode(f, 'JUMP_IF_TRUE_OR_POP') - self.assertInBytecode(f, 'JUMP_IF_FALSE_OR_POP') - self.assertInBytecode(f, 'POP_JUMP_IF_TRUE') + self.assertEqual(count_instr_recursively(f, 'POP_JUMP_IF_FALSE'), 1) + self.assertEqual(count_instr_recursively(f, 'POP_JUMP_IF_TRUE'), 1) def test_elim_jump_to_uncond_jump4(self): def f(): diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-21-00-46-36.gh-issue-102859.PRkGca.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-21-00-46-36.gh-issue-102859.PRkGca.rst new file mode 100644 index 00000000000000..d2e2232c33cc4d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-21-00-46-36.gh-issue-102859.PRkGca.rst @@ -0,0 +1,2 @@ +Removed :opcode:`JUMP_IF_FALSE_OR_POP` and :opcode:`JUMP_IF_TRUE_OR_POP` +instructions. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 133c991bf701c4..19bd4b10780b91 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -306,8 +306,6 @@ mark_stacks(PyCodeObject *code_obj, int len) } opcode = code[i].op.code; switch (opcode) { - case JUMP_IF_FALSE_OR_POP: - case JUMP_IF_TRUE_OR_POP: case POP_JUMP_IF_FALSE: case POP_JUMP_IF_TRUE: { @@ -318,16 +316,8 @@ mark_stacks(PyCodeObject *code_obj, int len) if (stacks[j] == UNINITIALIZED && j < i) { todo = 1; } - if (opcode == JUMP_IF_FALSE_OR_POP || - opcode == JUMP_IF_TRUE_OR_POP) - { - target_stack = next_stack; - next_stack = pop_value(next_stack); - } - else { - next_stack = pop_value(next_stack); - target_stack = next_stack; - } + next_stack = pop_value(next_stack); + target_stack = next_stack; assert(stacks[j] == UNINITIALIZED || stacks[j] == target_stack); stacks[j] = target_stack; stacks[i+1] = next_stack; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 5038e1bb17fc3f..b9a6a9e2b61208 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2050,129 +2050,6 @@ dummy_func( } } - inst(BB_TEST_POP_IF_NONE, (value -- )) { - if (Py_IsNone(value)) { - _Py_DECREF_NO_DEALLOC(value); - bb_test = false; - } - else { - Py_DECREF(value); - bb_test = true; - } - } - - inst(JUMP_IF_FALSE_OR_POP, (cond -- cond if (jump))) { - bool jump = false; - int err; - if (Py_IsTrue(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - } - else if (Py_IsFalse(cond)) { - JUMPBY(oparg); - jump = true; - } - else { - err = PyObject_IsTrue(cond); - if (err > 0) { - Py_DECREF(cond); - } - else if (err == 0) { - JUMPBY(oparg); - jump = true; - } - else { - goto error; - } - } - } - - inst(BB_TEST_IF_FALSE_OR_POP, (cond -- cond if (jump))) { - bool jump = false; - int err; - if (Py_IsTrue(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - bb_test = true; - } - else if (Py_IsFalse(cond)) { - bb_test = false; - jump = true; - } - else { - err = PyObject_IsTrue(cond); - if (err > 0) { - bb_test = true; - Py_DECREF(cond); - } - else if (err == 0) { - bb_test = false; - jump = true; - } - else { - goto error; - } - } - // This gets set so BRANCH_BB knows whether to pop - // the type stack (type propagation) when generating the - // target BB - gen_bb_requires_pop = !jump; - } - - inst(JUMP_IF_TRUE_OR_POP, (cond -- cond if (jump))) { - bool jump = false; - int err; - if (Py_IsFalse(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - } - else if (Py_IsTrue(cond)) { - JUMPBY(oparg); - jump = true; - } - else { - err = PyObject_IsTrue(cond); - if (err > 0) { - JUMPBY(oparg); - jump = true; - } - else if (err == 0) { - Py_DECREF(cond); - } - else { - goto error; - } - } - } - - inst(BB_TEST_IF_TRUE_OR_POP, (cond -- cond if (jump))) { - bool jump = false; - int err; - if (Py_IsFalse(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - bb_test = true; - } - else if (Py_IsTrue(cond)) { - bb_test = false; - jump = true; - } - else { - err = PyObject_IsTrue(cond); - if (err > 0) { - bb_test = false; - jump = true; - } - else if (err == 0) { - bb_test = true; - Py_DECREF(cond); - } - else { - goto error; - } - } - // This gets set so BRANCH_BB knows whether to pop - // the type stack (type propagation) when generating the - // target BB - gen_bb_requires_pop = !jump; - } - inst(JUMP_BACKWARD_NO_INTERRUPT, (--)) { /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost diff --git a/Python/compile.c b/Python/compile.c index 99296050445f50..33cd6ca07d3bb6 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -4241,19 +4241,18 @@ compiler_boolop(struct compiler *c, expr_ty e) location loc = LOC(e); assert(e->kind == BoolOp_kind); if (e->v.BoolOp.op == And) - jumpi = JUMP_IF_FALSE_OR_POP; + jumpi = POP_JUMP_IF_FALSE; else - jumpi = JUMP_IF_TRUE_OR_POP; + jumpi = POP_JUMP_IF_TRUE; NEW_JUMP_TARGET_LABEL(c, end); s = e->v.BoolOp.values; n = asdl_seq_LEN(s) - 1; assert(n >= 0); for (i = 0; i < n; ++i) { VISIT(c, expr, (expr_ty)asdl_seq_GET(s, i)); + ADDOP_I(c, loc, COPY, 1); ADDOP_JUMP(c, loc, jumpi, end); - NEW_JUMP_TARGET_LABEL(c, next); - - USE_LABEL(c, next); + ADDOP(c, loc, POP_TOP); } VISIT(c, expr, (expr_ty)asdl_seq_GET(s, n)); @@ -4558,7 +4557,9 @@ compiler_compare(struct compiler *c, expr_ty e) ADDOP_I(c, loc, SWAP, 2); ADDOP_I(c, loc, COPY, 2); ADDOP_COMPARE(c, loc, asdl_seq_GET(e->v.Compare.ops, i)); - ADDOP_JUMP(c, loc, JUMP_IF_FALSE_OR_POP, cleanup); + ADDOP_I(c, loc, COPY, 1); + ADDOP_JUMP(c, loc, POP_JUMP_IF_FALSE, cleanup); + ADDOP(c, loc, POP_TOP); } VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n)); ADDOP_COMPARE(c, loc, asdl_seq_GET(e->v.Compare.ops, n)); @@ -7836,21 +7837,6 @@ normalize_jumps_in_block(cfg_builder *g, basicblock *b) { case POP_JUMP_IF_TRUE: reversed_opcode = POP_JUMP_IF_FALSE; break; - case JUMP_IF_TRUE_OR_POP: - case JUMP_IF_FALSE_OR_POP: - if (!is_forward) { - /* As far as we can tell, the compiler never emits - * these jumps with a backwards target. If/when this - * exception is raised, we have found a use case for - * a backwards version of this jump (or to replace - * it with the sequence (COPY 1, POP_JUMP_IF_T/F, POP) - */ - PyErr_Format(PyExc_SystemError, - "unexpected %s jumping backwards", - last->i_opcode == JUMP_IF_TRUE_OR_POP ? - "JUMP_IF_TRUE_OR_POP" : "JUMP_IF_FALSE_OR_POP"); - } - return SUCCESS; } if (is_forward) { return SUCCESS; @@ -9143,21 +9129,30 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) assert(PyList_CheckExact(consts)); struct cfg_instr nop; INSTR_SET_OP0(&nop, NOP); - struct cfg_instr *target; + struct cfg_instr *target = &nop; + int opcode = 0; + int oparg = 0; + int nextop = 0; for (int i = 0; i < bb->b_iused; i++) { struct cfg_instr *inst = &bb->b_instr[i]; - int oparg = inst->i_oparg; - int nextop = i+1 < bb->b_iused ? bb->b_instr[i+1].i_opcode : 0; - if (HAS_TARGET(inst->i_opcode)) { - assert(inst->i_target->b_iused > 0); - target = &inst->i_target->b_instr[0]; - assert(!IS_ASSEMBLER_OPCODE(target->i_opcode)); - } - else { - target = &nop; + bool is_copy_of_load_const = (opcode == LOAD_CONST && + inst->i_opcode == COPY && + inst->i_oparg == 1); + if (! is_copy_of_load_const) { + opcode = inst->i_opcode; + oparg = inst->i_oparg; + if (HAS_TARGET(opcode)) { + assert(inst->i_target->b_iused > 0); + target = &inst->i_target->b_instr[0]; + assert(!IS_ASSEMBLER_OPCODE(target->i_opcode)); + } + else { + target = &nop; + } } - assert(!IS_ASSEMBLER_OPCODE(inst->i_opcode)); - switch (inst->i_opcode) { + nextop = i+1 < bb->b_iused ? bb->b_instr[i+1].i_opcode : 0; + assert(!IS_ASSEMBLER_OPCODE(opcode)); + switch (opcode) { /* Remove LOAD_CONST const; conditional jump */ case LOAD_CONST: { @@ -9167,7 +9162,7 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) switch(nextop) { case POP_JUMP_IF_FALSE: case POP_JUMP_IF_TRUE: - cnt = get_const_value(inst->i_opcode, oparg, consts); + cnt = get_const_value(opcode, oparg, consts); if (cnt == NULL) { goto error; } @@ -9185,28 +9180,8 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) INSTR_SET_OP0(&bb->b_instr[i + 1], NOP); } break; - case JUMP_IF_FALSE_OR_POP: - case JUMP_IF_TRUE_OR_POP: - cnt = get_const_value(inst->i_opcode, oparg, consts); - if (cnt == NULL) { - goto error; - } - is_true = PyObject_IsTrue(cnt); - Py_DECREF(cnt); - if (is_true == -1) { - goto error; - } - jump_if_true = nextop == JUMP_IF_TRUE_OR_POP; - if (is_true == jump_if_true) { - bb->b_instr[i+1].i_opcode = JUMP; - } - else { - INSTR_SET_OP0(inst, NOP); - INSTR_SET_OP0(&bb->b_instr[i + 1], NOP); - } - break; case IS_OP: - cnt = get_const_value(inst->i_opcode, oparg, consts); + cnt = get_const_value(opcode, oparg, consts); if (cnt == NULL) { goto error; } @@ -9252,65 +9227,6 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) } } break; - - /* Simplify conditional jump to conditional jump where the - result of the first test implies the success of a similar - test or the failure of the opposite test. - Arises in code like: - "a and b or c" - "(a and b) and c" - "(a or b) or c" - "(a or b) and c" - x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_FALSE_OR_POP z - --> x:JUMP_IF_FALSE_OR_POP z - x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_TRUE_OR_POP z - --> x:POP_JUMP_IF_FALSE y+1 - where y+1 is the instruction following the second test. - */ - case JUMP_IF_FALSE_OR_POP: - switch (target->i_opcode) { - case POP_JUMP_IF_FALSE: - i -= jump_thread(inst, target, POP_JUMP_IF_FALSE); - break; - case JUMP: - case JUMP_IF_FALSE_OR_POP: - i -= jump_thread(inst, target, JUMP_IF_FALSE_OR_POP); - break; - case JUMP_IF_TRUE_OR_POP: - case POP_JUMP_IF_TRUE: - if (inst->i_loc.lineno == target->i_loc.lineno) { - // We don't need to bother checking for loops here, - // since a block's b_next cannot point to itself: - assert(inst->i_target != inst->i_target->b_next); - inst->i_opcode = POP_JUMP_IF_FALSE; - inst->i_target = inst->i_target->b_next; - --i; - } - break; - } - break; - case JUMP_IF_TRUE_OR_POP: - switch (target->i_opcode) { - case POP_JUMP_IF_TRUE: - i -= jump_thread(inst, target, POP_JUMP_IF_TRUE); - break; - case JUMP: - case JUMP_IF_TRUE_OR_POP: - i -= jump_thread(inst, target, JUMP_IF_TRUE_OR_POP); - break; - case JUMP_IF_FALSE_OR_POP: - case POP_JUMP_IF_FALSE: - if (inst->i_loc.lineno == target->i_loc.lineno) { - // We don't need to bother checking for loops here, - // since a block's b_next cannot point to itself: - assert(inst->i_target != inst->i_target->b_next); - inst->i_opcode = POP_JUMP_IF_TRUE; - inst->i_target = inst->i_target->b_next; - --i; - } - break; - } - break; case POP_JUMP_IF_NOT_NONE: case POP_JUMP_IF_NONE: switch (target->i_opcode) { @@ -9398,6 +9314,52 @@ inline_small_exit_blocks(basicblock *bb) { return 0; } + +static int +remove_redundant_nops_and_pairs(basicblock *entryblock) +{ + bool done = false; + + while (! done) { + done = true; + struct cfg_instr *prev_instr = NULL; + struct cfg_instr *instr = NULL; + for (basicblock *b = entryblock; b != NULL; b = b->b_next) { + remove_redundant_nops(b); + if (IS_LABEL(b->b_label)) { + /* this block is a jump target, forget instr */ + instr = NULL; + } + for (int i = 0; i < b->b_iused; i++) { + prev_instr = instr; + instr = &b->b_instr[i]; + int prev_opcode = prev_instr ? prev_instr->i_opcode : 0; + int prev_oparg = prev_instr ? prev_instr->i_oparg : 0; + int opcode = instr->i_opcode; + bool is_redundant_pair = false; + if (opcode == POP_TOP) { + if (prev_opcode == LOAD_CONST) { + is_redundant_pair = true; + } + else if (prev_opcode == COPY && prev_oparg == 1) { + is_redundant_pair = true; + } + } + if (is_redundant_pair) { + INSTR_SET_OP0(prev_instr, NOP); + INSTR_SET_OP0(instr, NOP); + done = false; + } + } + if ((instr && is_jump(instr)) || !BB_HAS_FALLTHROUGH(b)) { + instr = NULL; + } + } + } + return SUCCESS; +} + + static int remove_redundant_nops(basicblock *bb) { /* Remove NOPs when legal to do so. */ @@ -9636,9 +9598,9 @@ optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache) assert(no_empty_basic_blocks(g)); for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { RETURN_IF_ERROR(optimize_basic_block(const_cache, b, consts)); - remove_redundant_nops(b); assert(b->b_predecessors == 0); } + RETURN_IF_ERROR(remove_redundant_nops_and_pairs(g->g_entryblock)); for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) { RETURN_IF_ERROR(inline_small_exit_blocks(b)); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index d83901ce3e2158..e74ef78c3b0aeb 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2645,148 +2645,6 @@ DISPATCH(); } - TARGET(BB_TEST_POP_IF_NONE) { - PyObject *value = stack_pointer[-1]; - if (Py_IsNone(value)) { - _Py_DECREF_NO_DEALLOC(value); - bb_test = false; - } - else { - Py_DECREF(value); - bb_test = true; - } - STACK_SHRINK(1); - DISPATCH(); - } - - TARGET(JUMP_IF_FALSE_OR_POP) { - PyObject *cond = stack_pointer[-1]; - bool jump = false; - int err; - if (Py_IsTrue(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - } - else if (Py_IsFalse(cond)) { - JUMPBY(oparg); - jump = true; - } - else { - err = PyObject_IsTrue(cond); - if (err > 0) { - Py_DECREF(cond); - } - else if (err == 0) { - JUMPBY(oparg); - jump = true; - } - else { - goto error; - } - } - STACK_SHRINK(1); - STACK_GROW((jump ? 1 : 0)); - DISPATCH(); - } - - TARGET(BB_TEST_IF_FALSE_OR_POP) { - PyObject *cond = stack_pointer[-1]; - bool jump = false; - int err; - if (Py_IsTrue(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - bb_test = true; - } - else if (Py_IsFalse(cond)) { - bb_test = false; - jump = true; - } - else { - err = PyObject_IsTrue(cond); - if (err > 0) { - bb_test = true; - Py_DECREF(cond); - } - else if (err == 0) { - bb_test = false; - jump = true; - } - else { - goto error; - } - } - // This gets set so BRANCH_BB knows whether to pop - // the type stack (type propagation) when generating the - // target BB - gen_bb_requires_pop = !jump; - STACK_SHRINK(1); - STACK_GROW((jump ? 1 : 0)); - DISPATCH(); - } - - TARGET(JUMP_IF_TRUE_OR_POP) { - PyObject *cond = stack_pointer[-1]; - bool jump = false; - int err; - if (Py_IsFalse(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - } - else if (Py_IsTrue(cond)) { - JUMPBY(oparg); - jump = true; - } - else { - err = PyObject_IsTrue(cond); - if (err > 0) { - JUMPBY(oparg); - jump = true; - } - else if (err == 0) { - Py_DECREF(cond); - } - else { - goto error; - } - } - STACK_SHRINK(1); - STACK_GROW((jump ? 1 : 0)); - DISPATCH(); - } - - TARGET(BB_TEST_IF_TRUE_OR_POP) { - PyObject *cond = stack_pointer[-1]; - bool jump = false; - int err; - if (Py_IsFalse(cond)) { - _Py_DECREF_NO_DEALLOC(cond); - bb_test = true; - } - else if (Py_IsTrue(cond)) { - bb_test = false; - jump = true; - } - else { - err = PyObject_IsTrue(cond); - if (err > 0) { - bb_test = false; - jump = true; - } - else if (err == 0) { - bb_test = true; - Py_DECREF(cond); - } - else { - goto error; - } - } - // This gets set so BRANCH_BB knows whether to pop - // the type stack (type propagation) when generating the - // target BB - gen_bb_requires_pop = !jump; - STACK_SHRINK(1); - STACK_GROW((jump ? 1 : 0)); - DISPATCH(); - } - TARGET(JUMP_BACKWARD_NO_INTERRUPT) { /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 5a00fe70a7c0bf..25463ced32d5d4 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -281,16 +281,6 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 1; case POP_JUMP_IF_NONE: return 1; - case BB_TEST_POP_IF_NONE: - return 1; - case JUMP_IF_FALSE_OR_POP: - return 1; - case BB_TEST_IF_FALSE_OR_POP: - return 1; - case JUMP_IF_TRUE_OR_POP: - return 1; - case BB_TEST_IF_TRUE_OR_POP: - return 1; case JUMP_BACKWARD_NO_INTERRUPT: return 0; case GET_LEN: @@ -687,16 +677,6 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case POP_JUMP_IF_NONE: return 0; - case BB_TEST_POP_IF_NONE: - return 0; - case JUMP_IF_FALSE_OR_POP: - return (jump ? 1 : 0); - case BB_TEST_IF_FALSE_OR_POP: - return (jump ? 1 : 0); - case JUMP_IF_TRUE_OR_POP: - return (jump ? 1 : 0); - case BB_TEST_IF_TRUE_OR_POP: - return (jump ? 1 : 0); case JUMP_BACKWARD_NO_INTERRUPT: return 0; case GET_LEN: @@ -961,11 +941,6 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB }, [BB_TEST_POP_IF_NOT_NONE] = { true, INSTR_FMT_IX }, [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB }, - [BB_TEST_POP_IF_NONE] = { true, INSTR_FMT_IX }, - [JUMP_IF_FALSE_OR_POP] = { true, INSTR_FMT_IB }, - [BB_TEST_IF_FALSE_OR_POP] = { true, INSTR_FMT_IX }, - [JUMP_IF_TRUE_OR_POP] = { true, INSTR_FMT_IB }, - [BB_TEST_IF_TRUE_OR_POP] = { true, INSTR_FMT_IX }, [JUMP_BACKWARD_NO_INTERRUPT] = { true, INSTR_FMT_IB }, [GET_LEN] = { true, INSTR_FMT_IX }, [MATCH_CLASS] = { true, INSTR_FMT_IB }, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 4a815c73acb7db..38217d9e8f2ba9 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -110,9 +110,9 @@ static void *opcode_targets[256] = { &&TARGET_IMPORT_NAME, &&TARGET_IMPORT_FROM, &&TARGET_JUMP_FORWARD, - &&TARGET_JUMP_IF_FALSE_OR_POP, - &&TARGET_JUMP_IF_TRUE_OR_POP, &&TARGET_LOAD_FAST__LOAD_FAST, + &&TARGET_LOAD_GLOBAL_BUILTIN, + &&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -142,7 +142,7 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_BACKWARD, &&TARGET_COMPARE_AND_BRANCH, &&TARGET_CALL_FUNCTION_EX, - &&TARGET_LOAD_GLOBAL_BUILTIN, + &&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,29 +152,29 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, - &&TARGET_LOAD_GLOBAL_MODULE, - &&TARGET_STORE_ATTR_INSTANCE_VALUE, + &&TARGET_STORE_ATTR_SLOT, + &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, - &&TARGET_STORE_ATTR_SLOT, - &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_STORE_FAST__STORE_FAST, + &&TARGET_STORE_SUBSCR_DICT, + &&TARGET_STORE_SUBSCR_LIST_INT, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, - &&TARGET_STORE_SUBSCR_DICT, - &&TARGET_STORE_SUBSCR_LIST_INT, &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, + &&TARGET_SEND_GEN, + &&_unknown_opcode, &&TARGET_CALL, &&TARGET_KW_NAMES, &&TARGET_CALL_INTRINSIC_1, &&TARGET_CALL_INTRINSIC_2, - &&TARGET_SEND_GEN, + &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index f3620b6c6a9b4b..c50ae42092bfd5 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -747,35 +747,6 @@ break; } - TARGET(BB_TEST_POP_IF_NONE) { - STACK_SHRINK(1); - break; - } - - TARGET(JUMP_IF_FALSE_OR_POP) { - fprintf(stderr, "Type propagation across `JUMP_IF_FALSE_OR_POP` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - - TARGET(BB_TEST_IF_FALSE_OR_POP) { - fprintf(stderr, "Type propagation across `BB_TEST_IF_FALSE_OR_POP` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - - TARGET(JUMP_IF_TRUE_OR_POP) { - fprintf(stderr, "Type propagation across `JUMP_IF_TRUE_OR_POP` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - - TARGET(BB_TEST_IF_TRUE_OR_POP) { - fprintf(stderr, "Type propagation across `BB_TEST_IF_TRUE_OR_POP` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - TARGET(JUMP_BACKWARD_NO_INTERRUPT) { break; } From 404a6c5b46c4f84de4d523f78a8cb4274cb039b1 Mon Sep 17 00:00:00 2001 From: Kevin Kirsche Date: Wed, 22 Mar 2023 14:14:05 -0400 Subject: [PATCH 192/280] gh-102921: [doc] Clarify `exc` argument name in `BaseExceptionGroup` is plural (#102922) --- Doc/library/exceptions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index 4a57e9c8799336..18c3f47dddc079 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -948,8 +948,8 @@ their subgroups based on the types of the contained exceptions. these fields do not need to be updated by :meth:`derive`. :: >>> class MyGroup(ExceptionGroup): - ... def derive(self, exc): - ... return MyGroup(self.message, exc) + ... def derive(self, excs): + ... return MyGroup(self.message, excs) ... >>> e = MyGroup("eg", [ValueError(1), TypeError(2)]) >>> e.add_note("a note") From f8f08c2701c735541832a9db99f64a310d62e615 Mon Sep 17 00:00:00 2001 From: Jens-Hilmar Bradt <17177271+jenshb@users.noreply.github.com> Date: Wed, 22 Mar 2023 19:43:41 +0100 Subject: [PATCH 193/280] [doc] Fix error in tutorial example: type(exc) is the type rather than the instance (#102751) --- Doc/tutorial/errors.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/tutorial/errors.rst b/Doc/tutorial/errors.rst index e09c829b8e9721..ca5dc3314c63b6 100644 --- a/Doc/tutorial/errors.rst +++ b/Doc/tutorial/errors.rst @@ -160,7 +160,7 @@ accessing ``.args``. :: >>> try: ... raise Exception('spam', 'eggs') ... except Exception as inst: - ... print(type(inst)) # the exception instance + ... print(type(inst)) # the exception type ... print(inst.args) # arguments stored in .args ... print(inst) # __str__ allows args to be printed directly, ... # but may be overridden in exception subclasses From 828e8878382024e1c08ebeae2ab4a5d63f806bca Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 22 Mar 2023 18:30:04 -0600 Subject: [PATCH 194/280] gh-100227: Make the Global Interned Dict Safe for Isolated Interpreters (gh-102925) This is effectively two changes. The first (the bulk of the change) is where we add _Py_AddToGlobalDict() (and _PyRuntime.cached_objects.main_tstate, etc.). The second (much smaller) change is where we update PyUnicode_InternInPlace() to use _Py_AddToGlobalDict() instead of calling PyDict_SetDefault() directly. Basically, _Py_AddToGlobalDict() is a wrapper around PyDict_SetDefault() that should be used whenever we need to add a value to a runtime-global dict object (in the few cases where we are leaving the container global rather than moving it to PyInterpreterState, e.g. the interned strings dict). _Py_AddToGlobalDict() does all the necessary work to make sure the target global dict is shared safely between isolated interpreters. This is especially important as we move the obmalloc state to each interpreter (gh-101660), as well as, potentially, the GIL (PEP 684). https://github.com/python/cpython/issues/100227 --- Include/internal/pycore_global_objects.h | 4 + Include/internal/pycore_pystate.h | 5 + Include/internal/pycore_runtime_init.h | 3 + Include/internal/pycore_unicodeobject.h | 1 + Objects/unicodeobject.c | 13 +- Python/pylifecycle.c | 4 + Python/pystate.c | 204 ++++++++++++++++++++--- 7 files changed, 204 insertions(+), 30 deletions(-) diff --git a/Include/internal/pycore_global_objects.h b/Include/internal/pycore_global_objects.h index 9957da1fc5f22a..858321d67df481 100644 --- a/Include/internal/pycore_global_objects.h +++ b/Include/internal/pycore_global_objects.h @@ -28,6 +28,10 @@ extern "C" { struct _Py_cached_objects { PyObject *interned_strings; + /* A thread state tied to the main interpreter, + used exclusively for when a global object (e.g. interned strings) + is resized (i.e. deallocated + allocated) from an arbitrary thread. */ + PyThreadState main_tstate; }; #define _Py_GLOBAL_OBJECT(NAME) \ diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index 7046ec8d9adaaf..f159b516e66b18 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -127,6 +127,11 @@ PyAPI_FUNC(void) _PyThreadState_Init( PyThreadState *tstate); PyAPI_FUNC(void) _PyThreadState_DeleteExcept(PyThreadState *tstate); +extern void _PyThreadState_InitDetached(PyThreadState *, PyInterpreterState *); +extern void _PyThreadState_ClearDetached(PyThreadState *); + +extern PyObject * _Py_AddToGlobalDict(PyObject *, PyObject *, PyObject *); + static inline void _PyThreadState_UpdateTracingState(PyThreadState *tstate) diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index 7cfa7c0c02494a..fd358b2da6ccff 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -59,6 +59,9 @@ extern PyTypeObject _PyExc_MemoryError; .types = { \ .next_version_tag = 1, \ }, \ + .cached_objects = { \ + .main_tstate = _PyThreadState_INIT, \ + }, \ .static_objects = { \ .singletons = { \ .small_ints = _Py_small_ints_INIT, \ diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h index 19faceebf1d8ee..ed4feb603d6f38 100644 --- a/Include/internal/pycore_unicodeobject.h +++ b/Include/internal/pycore_unicodeobject.h @@ -34,6 +34,7 @@ struct _Py_unicode_runtime_ids { struct _Py_unicode_runtime_state { struct _Py_unicode_runtime_ids ids; + /* The interned dict is at _PyRuntime.cached_objects.interned_strings. */ }; /* fs_codec.encoding is initialized to NULL. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index b9fb53147b9b51..891a65576ee29b 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14609,16 +14609,11 @@ PyUnicode_InternInPlace(PyObject **p) } PyObject *interned = get_interned_dict(); - assert(interned != NULL); - - PyObject *t = PyDict_SetDefault(interned, s, s); - if (t == NULL) { - PyErr_Clear(); - return; - } - + PyObject *t = _Py_AddToGlobalDict(interned, s, s); if (t != s) { - Py_SETREF(*p, Py_NewRef(t)); + if (t != NULL) { + Py_SETREF(*p, Py_NewRef(t)); + } return; } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 8110d94ba17526..5d7f8621833040 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -636,6 +636,8 @@ pycore_create_interpreter(_PyRuntimeState *runtime, return status; } + _PyThreadState_InitDetached(&runtime->cached_objects.main_tstate, interp); + *tstate_p = tstate; return _PyStatus_OK(); } @@ -1932,6 +1934,8 @@ Py_FinalizeEx(void) // XXX Do this sooner during finalization. // XXX Ensure finalizer errors are handled properly. + _PyThreadState_ClearDetached(&runtime->cached_objects.main_tstate); + finalize_interp_clear(tstate); finalize_interp_delete(tstate->interp); diff --git a/Python/pystate.c b/Python/pystate.c index b17efdbefd124c..394b12d24065f2 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -565,6 +565,124 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime) #endif +//--------------- +// global objects +//--------------- + +/* The global objects thread state is meant to be used in a very limited + way and should not be used to actually run any Python code. */ + +static PyThreadState * +bind_global_objects_state(_PyRuntimeState *runtime) +{ + PyThreadState *main_tstate = &runtime->cached_objects.main_tstate; + + bind_tstate(main_tstate); + /* Unlike _PyThreadState_Bind(), we do not modify gilstate TSS. */ + + return main_tstate; +} + +static void +unbind_global_objects_state(_PyRuntimeState *runtime) +{ + PyThreadState *main_tstate = &runtime->cached_objects.main_tstate; + assert(tstate_is_alive(main_tstate)); + assert(!main_tstate->_status.active); + assert(gilstate_tss_get(runtime) != main_tstate); + + unbind_tstate(main_tstate); + + /* This thread state may be bound/unbound repeatedly, + so we must erase evidence that it was ever bound (or unbound). */ + main_tstate->_status.bound = 0; + main_tstate->_status.unbound = 0; + + /* We must fully unlink the thread state from any OS thread, + to allow it to be bound more than once. */ + main_tstate->thread_id = 0; +#ifdef PY_HAVE_THREAD_NATIVE_ID + main_tstate->native_thread_id = 0; +#endif +} + +static inline void +acquire_global_objects_lock(_PyRuntimeState *runtime) +{ + /* For now we can rely on the GIL, so we don't actually + acquire a global lock here. */ + assert(current_fast_get(runtime) != NULL); +} + +static inline void +release_global_objects_lock(_PyRuntimeState *runtime) +{ + /* For now we can rely on the GIL, so we don't actually + release a global lock here. */ + assert(current_fast_get(runtime) != NULL); +} + +PyObject * +_Py_AddToGlobalDict(PyObject *dict, PyObject *key, PyObject *value) +{ + assert(dict != NULL); + assert(PyDict_CheckExact(dict)); + + /* All global objects are stored in _PyRuntime + and owned by the main interpreter. */ + _PyRuntimeState *runtime = &_PyRuntime; + PyThreadState *curts = current_fast_get(runtime); + PyInterpreterState *interp = curts->interp; + assert(interp != NULL); // The GIL must be held. + + /* Due to interpreter isolation we must hold a global lock, + starting at this point and ending before we return. + Note that the operations in this function are very fucused + and we should not expect any reentrancy. */ + acquire_global_objects_lock(runtime); + + /* Swap to the main interpreter, if necessary. */ + PyThreadState *oldts = NULL; + if (!_Py_IsMainInterpreter(interp)) { + PyThreadState *main_tstate = bind_global_objects_state(runtime); + + oldts = _PyThreadState_Swap(runtime, main_tstate); + assert(oldts != NULL); + assert(!_Py_IsMainInterpreter(oldts->interp)); + + /* The limitations of the global objects thread state apply + from this point to the point we swap back to oldts. */ + } + + /* This might trigger a resize, which is why we must "acquire" + the global object state. Also note that PyDict_SetDefault() + must be compatible with our reentrancy and global objects state + constraints. */ + PyObject *actual = PyDict_SetDefault(dict, key, value); + if (actual == NULL) { + /* Raising an exception from one interpreter in another + is problematic, so we clear it and let the caller deal + with the returned NULL. */ + assert(PyErr_ExceptionMatches(PyExc_MemoryError)); + PyErr_Clear(); + } + + /* Swap back, it it wasn't in the main interpreter already. */ + if (oldts != NULL) { + // The returned tstate should be _PyRuntime.cached_objects.main_tstate. + _PyThreadState_Swap(runtime, oldts); + + unbind_global_objects_state(runtime); + } + + release_global_objects_lock(runtime); + + // XXX Immortalize the key and value. + + return actual; +} + + /*************************************/ /* the per-interpreter runtime state */ /*************************************/ @@ -1217,8 +1335,7 @@ free_threadstate(PyThreadState *tstate) static void init_threadstate(PyThreadState *tstate, - PyInterpreterState *interp, uint64_t id, - PyThreadState *next) + PyInterpreterState *interp, uint64_t id) { if (tstate->_status.initialized) { Py_FatalError("thread state already initialized"); @@ -1227,18 +1344,13 @@ init_threadstate(PyThreadState *tstate, assert(interp != NULL); tstate->interp = interp; + // next/prev are set in add_threadstate(). + assert(tstate->next == NULL); + assert(tstate->prev == NULL); + assert(id > 0); tstate->id = id; - assert(interp->threads.head == tstate); - assert((next != NULL && id != 1) || (next == NULL && id == 1)); - if (next != NULL) { - assert(next->prev == NULL || next->prev == tstate); - next->prev = tstate; - } - tstate->next = next; - assert(tstate->prev == NULL); - // thread_id and native_thread_id are set in bind_tstate(). tstate->py_recursion_limit = interp->ceval.recursion_limit, @@ -1259,6 +1371,22 @@ init_threadstate(PyThreadState *tstate, tstate->_status.initialized = 1; } +static void +add_threadstate(PyInterpreterState *interp, PyThreadState *tstate, + PyThreadState *next) +{ + assert(interp->threads.head != tstate); + assert((next != NULL && tstate->id != 1) || + (next == NULL && tstate->id == 1)); + if (next != NULL) { + assert(next->prev == NULL || next->prev == tstate); + next->prev = tstate; + } + tstate->next = next; + assert(tstate->prev == NULL); + interp->threads.head = tstate; +} + static PyThreadState * new_threadstate(PyInterpreterState *interp) { @@ -1298,9 +1426,9 @@ new_threadstate(PyInterpreterState *interp) &initial._main_interpreter._initial_thread, sizeof(*tstate)); } - interp->threads.head = tstate; - init_threadstate(tstate, interp, id, old_head); + init_threadstate(tstate, interp, id); + add_threadstate(interp, tstate, old_head); HEAD_UNLOCK(runtime); if (!used_newtstate) { @@ -1347,6 +1475,33 @@ _PyThreadState_Init(PyThreadState *tstate) Py_FatalError("_PyThreadState_Init() is for internal use only"); } +void +_PyThreadState_InitDetached(PyThreadState *tstate, PyInterpreterState *interp) +{ + _PyRuntimeState *runtime = interp->runtime; + + HEAD_LOCK(runtime); + interp->threads.next_unique_id += 1; + uint64_t id = interp->threads.next_unique_id; + HEAD_UNLOCK(runtime); + + init_threadstate(tstate, interp, id); + // We do not call add_threadstate(). +} + + +static void +clear_datastack(PyThreadState *tstate) +{ + _PyStackChunk *chunk = tstate->datastack_chunk; + tstate->datastack_chunk = NULL; + while (chunk != NULL) { + _PyStackChunk *prev = chunk->previous; + _PyObject_VirtualFree(chunk, chunk->size); + chunk = prev; + } +} + void PyThreadState_Clear(PyThreadState *tstate) { @@ -1421,7 +1576,6 @@ PyThreadState_Clear(PyThreadState *tstate) // XXX Do it as early in the function as possible. } - /* Common code for PyThreadState_Delete() and PyThreadState_DeleteCurrent() */ static void tstate_delete_common(PyThreadState *tstate) @@ -1454,17 +1608,25 @@ tstate_delete_common(PyThreadState *tstate) unbind_tstate(tstate); // XXX Move to PyThreadState_Clear()? - _PyStackChunk *chunk = tstate->datastack_chunk; - tstate->datastack_chunk = NULL; - while (chunk != NULL) { - _PyStackChunk *prev = chunk->previous; - _PyObject_VirtualFree(chunk, chunk->size); - chunk = prev; - } + clear_datastack(tstate); tstate->_status.finalized = 1; } +void +_PyThreadState_ClearDetached(PyThreadState *tstate) +{ + assert(!tstate->_status.bound); + assert(!tstate->_status.bound_gilstate); + assert(tstate->datastack_chunk == NULL); + assert(tstate->thread_id == 0); + assert(tstate->native_thread_id == 0); + assert(tstate->next == NULL); + assert(tstate->prev == NULL); + + PyThreadState_Clear(tstate); + clear_datastack(tstate); +} static void zapthreads(PyInterpreterState *interp) From c95d83cd648abaeff427a5f405780fdf195bc93a Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Thu, 23 Mar 2023 13:37:04 +0300 Subject: [PATCH 195/280] gh-102939: Fix "conversion from Py_ssize_t to long" warning in builtins (GH-102940) --- Python/bltinmodule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 55fd364d007972..fcb4d7a9a975c6 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2503,7 +2503,7 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) Py_DECREF(iter); if (PyErr_Occurred()) return NULL; - return PyLong_FromLong(i_result); + return PyLong_FromSsize_t(i_result); } if (PyLong_CheckExact(item) || PyBool_Check(item)) { Py_ssize_t b; @@ -2525,7 +2525,7 @@ builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start) } } /* Either overflowed or is not an int. Restore real objects and process normally */ - result = PyLong_FromLong(i_result); + result = PyLong_FromSsize_t(i_result); if (result == NULL) { Py_DECREF(item); Py_DECREF(iter); From 24016a897f9c609315f1314e108d92495cb36e1b Mon Sep 17 00:00:00 2001 From: "Erlend E. Aasland" Date: Thu, 23 Mar 2023 14:21:32 +0100 Subject: [PATCH 196/280] Docs: fixup incorrect escape char in sqlite3 docs (#102945) --- Doc/library/sqlite3.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 4b2d13ab3a8fcd..51146e00999659 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -259,7 +259,7 @@ Module functions .. function:: connect(database, timeout=5.0, detect_types=0, \ isolation_level="DEFERRED", check_same_thread=True, \ factory=sqlite3.Connection, cached_statements=128, \ - uri=False, \*, \ + uri=False, *, \ autocommit=sqlite3.LEGACY_TRANSACTION_CONTROL) Open a connection to an SQLite database. From 4ef8efaf9c52165d9d50500bc57791c83064213b Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 23 Mar 2023 14:17:54 +0000 Subject: [PATCH 197/280] gh-102947: Improve traceback when calling `fields()` on a non-dataclass (#102948) --- Lib/dataclasses.py | 2 +- Lib/test/test_dataclasses.py | 12 ++++++++++++ .../2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 82b08fc017884f..e3fd0b3e380dd8 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1248,7 +1248,7 @@ def fields(class_or_instance): try: fields = getattr(class_or_instance, _FIELDS) except AttributeError: - raise TypeError('must be called with a dataclass type or instance') + raise TypeError('must be called with a dataclass type or instance') from None # Exclude pseudo-fields. Note that fields is sorted by insertion # order, so the order of the tuple is as the fields were defined. diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 46f33043c27071..affd9cede19c99 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -5,11 +5,13 @@ from dataclasses import * import abc +import io import pickle import inspect import builtins import types import weakref +import traceback import unittest from unittest.mock import Mock from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar, Optional, Protocol, DefaultDict @@ -1526,6 +1528,16 @@ class C: pass with self.assertRaisesRegex(TypeError, 'dataclass type or instance'): fields(C()) + def test_clean_traceback_from_fields_exception(self): + stdout = io.StringIO() + try: + fields(object) + except TypeError as exc: + traceback.print_exception(exc, file=stdout) + printed_traceback = stdout.getvalue() + self.assertNotIn("AttributeError", printed_traceback) + self.assertNotIn("__dataclass_fields__", printed_traceback) + def test_helper_asdict(self): # Basic tests for asdict(), it should return a new dictionary. @dataclass diff --git a/Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst b/Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst new file mode 100644 index 00000000000000..b59c9820356697 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-23-13-34-33.gh-issue-102947.cTwcpU.rst @@ -0,0 +1,2 @@ +Improve traceback when :func:`dataclasses.fields` is called on a +non-dataclass. Patch by Alex Waygood From 67a48e51011cbd26c622761de578d281c462234f Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Thu, 23 Mar 2023 19:26:11 +0300 Subject: [PATCH 198/280] gh-88965: typing: fix type substitution of a list of types after initial `ParamSpec` substitution (#102808) Previously, this used to fail: ```py from typing import * T = TypeVar("T") P = ParamSpec("P") class X(Generic[P]): f: Callable[P, int] Y = X[[int, T]] Z = Y[str] ``` Co-authored-by: Alex Waygood --- Lib/test/test_typing.py | 121 ++++++++++++++++++ Lib/typing.py | 33 ++++- ...3-03-18-14-59-21.gh-issue-88965.kA70Km.rst | 7 + 3 files changed, 154 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index c9f55de95c548f..f448b0ee60a92a 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -7679,6 +7679,127 @@ def test_bad_var_substitution(self): with self.assertRaises(TypeError): collections.abc.Callable[P, T][arg, str] + def test_type_var_subst_for_other_type_vars(self): + T = TypeVar('T') + T2 = TypeVar('T2') + P = ParamSpec('P') + P2 = ParamSpec('P2') + Ts = TypeVarTuple('Ts') + + class Base(Generic[P]): + pass + + A1 = Base[T] + self.assertEqual(A1.__parameters__, (T,)) + self.assertEqual(A1.__args__, ((T,),)) + self.assertEqual(A1[int], Base[int]) + + A2 = Base[[T]] + self.assertEqual(A2.__parameters__, (T,)) + self.assertEqual(A2.__args__, ((T,),)) + self.assertEqual(A2[int], Base[int]) + + A3 = Base[[int, T]] + self.assertEqual(A3.__parameters__, (T,)) + self.assertEqual(A3.__args__, ((int, T),)) + self.assertEqual(A3[str], Base[[int, str]]) + + A4 = Base[[T, int, T2]] + self.assertEqual(A4.__parameters__, (T, T2)) + self.assertEqual(A4.__args__, ((T, int, T2),)) + self.assertEqual(A4[str, bool], Base[[str, int, bool]]) + + A5 = Base[[*Ts, int]] + self.assertEqual(A5.__parameters__, (Ts,)) + self.assertEqual(A5.__args__, ((*Ts, int),)) + self.assertEqual(A5[str, bool], Base[[str, bool, int]]) + + A5_2 = Base[[int, *Ts]] + self.assertEqual(A5_2.__parameters__, (Ts,)) + self.assertEqual(A5_2.__args__, ((int, *Ts),)) + self.assertEqual(A5_2[str, bool], Base[[int, str, bool]]) + + A6 = Base[[T, *Ts]] + self.assertEqual(A6.__parameters__, (T, Ts)) + self.assertEqual(A6.__args__, ((T, *Ts),)) + self.assertEqual(A6[int, str, bool], Base[[int, str, bool]]) + + A7 = Base[[T, T]] + self.assertEqual(A7.__parameters__, (T,)) + self.assertEqual(A7.__args__, ((T, T),)) + self.assertEqual(A7[int], Base[[int, int]]) + + A8 = Base[[T, list[T]]] + self.assertEqual(A8.__parameters__, (T,)) + self.assertEqual(A8.__args__, ((T, list[T]),)) + self.assertEqual(A8[int], Base[[int, list[int]]]) + + A9 = Base[[Tuple[*Ts], *Ts]] + self.assertEqual(A9.__parameters__, (Ts,)) + self.assertEqual(A9.__args__, ((Tuple[*Ts], *Ts),)) + self.assertEqual(A9[int, str], Base[Tuple[int, str], int, str]) + + A10 = Base[P2] + self.assertEqual(A10.__parameters__, (P2,)) + self.assertEqual(A10.__args__, (P2,)) + self.assertEqual(A10[[int, str]], Base[[int, str]]) + + class DoubleP(Generic[P, P2]): + pass + + B1 = DoubleP[P, P2] + self.assertEqual(B1.__parameters__, (P, P2)) + self.assertEqual(B1.__args__, (P, P2)) + self.assertEqual(B1[[int, str], [bool]], DoubleP[[int, str], [bool]]) + self.assertEqual(B1[[], []], DoubleP[[], []]) + + B2 = DoubleP[[int, str], P2] + self.assertEqual(B2.__parameters__, (P2,)) + self.assertEqual(B2.__args__, ((int, str), P2)) + self.assertEqual(B2[[bool, bool]], DoubleP[[int, str], [bool, bool]]) + self.assertEqual(B2[[]], DoubleP[[int, str], []]) + + B3 = DoubleP[P, [bool, bool]] + self.assertEqual(B3.__parameters__, (P,)) + self.assertEqual(B3.__args__, (P, (bool, bool))) + self.assertEqual(B3[[int, str]], DoubleP[[int, str], [bool, bool]]) + self.assertEqual(B3[[]], DoubleP[[], [bool, bool]]) + + B4 = DoubleP[[T, int], [bool, T2]] + self.assertEqual(B4.__parameters__, (T, T2)) + self.assertEqual(B4.__args__, ((T, int), (bool, T2))) + self.assertEqual(B4[str, float], DoubleP[[str, int], [bool, float]]) + + B5 = DoubleP[[*Ts, int], [bool, T2]] + self.assertEqual(B5.__parameters__, (Ts, T2)) + self.assertEqual(B5.__args__, ((*Ts, int), (bool, T2))) + self.assertEqual(B5[str, bytes, float], + DoubleP[[str, bytes, int], [bool, float]]) + + B6 = DoubleP[[T, int], [bool, *Ts]] + self.assertEqual(B6.__parameters__, (T, Ts)) + self.assertEqual(B6.__args__, ((T, int), (bool, *Ts))) + self.assertEqual(B6[str, bytes, float], + DoubleP[[str, int], [bool, bytes, float]]) + + class PandT(Generic[P, T]): + pass + + C1 = PandT[P, T] + self.assertEqual(C1.__parameters__, (P, T)) + self.assertEqual(C1.__args__, (P, T)) + self.assertEqual(C1[[int, str], bool], PandT[[int, str], bool]) + + C2 = PandT[[int, T], T] + self.assertEqual(C2.__parameters__, (T,)) + self.assertEqual(C2.__args__, ((int, T), T)) + self.assertEqual(C2[str], PandT[[int, str], str]) + + C3 = PandT[[int, *Ts], T] + self.assertEqual(C3.__parameters__, (Ts, T)) + self.assertEqual(C3.__args__, ((int, *Ts), T)) + self.assertEqual(C3[str, bool, bytes], PandT[[int, str, bool], bytes]) + def test_paramspec_in_nested_generics(self): # Although ParamSpec should not be found in __parameters__ of most # generics, they probably should be found when nested in diff --git a/Lib/typing.py b/Lib/typing.py index 3ee9679e50c0c4..157a563bbecea8 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -255,10 +255,17 @@ def _collect_parameters(args): """ parameters = [] for t in args: - # We don't want __parameters__ descriptor of a bare Python class. if isinstance(t, type): - continue - if hasattr(t, '__typing_subst__'): + # We don't want __parameters__ descriptor of a bare Python class. + pass + elif isinstance(t, tuple): + # `t` might be a tuple, when `ParamSpec` is substituted with + # `[T, int]`, or `[int, *Ts]`, etc. + for x in t: + for collected in _collect_parameters([x]): + if collected not in parameters: + parameters.append(collected) + elif hasattr(t, '__typing_subst__'): if t not in parameters: parameters.append(t) else: @@ -1441,10 +1448,12 @@ def _determine_new_args(self, args): raise TypeError(f"Too {'many' if alen > plen else 'few'} arguments for {self};" f" actual {alen}, expected {plen}") new_arg_by_param = dict(zip(params, args)) + return tuple(self._make_substitution(self.__args__, new_arg_by_param)) + def _make_substitution(self, args, new_arg_by_param): + """Create a list of new type arguments.""" new_args = [] - for old_arg in self.__args__: - + for old_arg in args: if isinstance(old_arg, type): new_args.append(old_arg) continue @@ -1488,10 +1497,20 @@ def _determine_new_args(self, args): # should join all these types together in a flat list # `(float, int, str)` - so again, we should `extend`. new_args.extend(new_arg) + elif isinstance(old_arg, tuple): + # Corner case: + # P = ParamSpec('P') + # T = TypeVar('T') + # class Base(Generic[P]): ... + # Can be substituted like this: + # X = Base[[int, T]] + # In this case, `old_arg` will be a tuple: + new_args.append( + tuple(self._make_substitution(old_arg, new_arg_by_param)), + ) else: new_args.append(new_arg) - - return tuple(new_args) + return new_args def copy_with(self, args): return self.__class__(self.__origin__, args, name=self._name, inst=self._inst, diff --git a/Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst b/Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst new file mode 100644 index 00000000000000..6e9642100cd8cb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-18-14-59-21.gh-issue-88965.kA70Km.rst @@ -0,0 +1,7 @@ +typing: Fix a bug relating to substitution in custom classes generic over a +:class:`~typing.ParamSpec`. Previously, if the ``ParamSpec`` was substituted +with a parameters list that itself contained a :class:`~typing.TypeVar`, the +``TypeVar`` in the parameters list could not be subsequently substituted. This +is now fixed. + +Patch by Nikita Sobolev. From 49e03ce245d90a39c9497227264c88ceb51f0dff Mon Sep 17 00:00:00 2001 From: AN Long Date: Fri, 24 Mar 2023 00:34:48 +0800 Subject: [PATCH 199/280] gh-102943: Stop checking localized error text in socket tests on Windows (GH-102944) --- Lib/test/test_socket.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 60f106f2d1a1c2..32252f7b741fda 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -2562,8 +2562,7 @@ def testHyperVConstants(self): socket.HV_GUID_LOOPBACK def testCreateHyperVSocketWithUnknownProtoFailure(self): - expected = "A protocol was specified in the socket function call " \ - "that does not support the semantics of the socket type requested" + expected = r"\[WinError 10041\]" with self.assertRaisesRegex(OSError, expected): socket.socket(socket.AF_HYPERV, socket.SOCK_STREAM) From 47e12e5876412e1b745f8ed4b16826955a049d74 Mon Sep 17 00:00:00 2001 From: JosephSBoyle <48555120+JosephSBoyle@users.noreply.github.com> Date: Thu, 23 Mar 2023 16:43:13 +0000 Subject: [PATCH 200/280] gh-102810 Improve the sphinx docs for `asyncio.Timeout` (#102934) Co-authored-by: Alex Waygood --- Doc/library/asyncio-task.rst | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index d908e45b3c8d8b..c5a480ba20190a 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -624,32 +624,26 @@ Timeouts The context manager produced by :func:`asyncio.timeout` can be rescheduled to a different deadline and inspected. - .. class:: Timeout() + .. class:: Timeout(when) An :ref:`asynchronous context manager ` - that limits time spent inside of it. + for cancelling overdue coroutines. - .. versionadded:: 3.11 + ``when`` should be an absolute time at which the context should time out, + as measured by the event loop's clock: + + - If ``when`` is ``None``, the timeout will never trigger. + - If ``when < loop.time()``, the timeout will trigger on the next + iteration of the event loop. .. method:: when() -> float | None Return the current deadline, or ``None`` if the current deadline is not set. - The deadline is a float, consistent with the time returned by - :meth:`loop.time`. - .. method:: reschedule(when: float | None) - Change the time the timeout will trigger. - - If *when* is ``None``, any current deadline will be removed, and the - context manager will wait indefinitely. - - If *when* is a float, it is set as the new deadline. - - if *when* is in the past, the timeout will trigger on the next - iteration of the event loop. + Reschedule the timeout. .. method:: expired() -> bool From 1999027c56875faf35ab10b9dea303513b67420e Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Thu, 23 Mar 2023 12:10:12 -0500 Subject: [PATCH 201/280] Move binomialvariate() to a section for discrete distributions (GH-102955) --- Doc/library/random.rst | 6 +++--- Lib/random.py | 45 +++++++++++++++++++++++------------------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/Doc/library/random.rst b/Doc/library/random.rst index 098684d7270ffa..c192919ac62e54 100644 --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -404,8 +404,8 @@ Alternative Generator Class that implements the default pseudo-random number generator used by the :mod:`random` module. - .. deprecated:: 3.9 - In the future, the *seed* must be one of the following types: + .. deprecated-removed:: 3.9 3.11 + Formerly the *seed* could be any hashable object. Now it is limited to: :class:`NoneType`, :class:`int`, :class:`float`, :class:`str`, :class:`bytes`, or :class:`bytearray`. @@ -423,7 +423,7 @@ Notes on Reproducibility ------------------------ Sometimes it is useful to be able to reproduce the sequences given by a -pseudo-random number generator. By re-using a seed value, the same sequence should be +pseudo-random number generator. By reusing a seed value, the same sequence should be reproducible from run to run as long as multiple threads are not running. Most of the random module's algorithms and seeding functions are subject to diff --git a/Lib/random.py b/Lib/random.py index 3c4291f6a652a0..586c3f7f9da938 100644 --- a/Lib/random.py +++ b/Lib/random.py @@ -24,7 +24,6 @@ negative exponential gamma beta - binomial pareto Weibull @@ -33,6 +32,11 @@ circular uniform von Mises + discrete distributions + ---------------------- + binomial + + General notes on the underlying Mersenne Twister core generator: * The period is 2**19937-1. @@ -731,6 +735,26 @@ def betavariate(self, alpha, beta): return y / (y + self.gammavariate(beta, 1.0)) return 0.0 + def paretovariate(self, alpha): + """Pareto distribution. alpha is the shape parameter.""" + # Jain, pg. 495 + + u = 1.0 - self.random() + return u ** (-1.0 / alpha) + + def weibullvariate(self, alpha, beta): + """Weibull distribution. + + alpha is the scale parameter and beta is the shape parameter. + + """ + # Jain, pg. 499; bug fix courtesy Bill Arms + + u = 1.0 - self.random() + return alpha * (-_log(u)) ** (1.0 / beta) + + + ## -------------------- discrete distributions --------------------- def binomialvariate(self, n=1, p=0.5): """Binomial random variable. @@ -816,25 +840,6 @@ def binomialvariate(self, n=1, p=0.5): return k - def paretovariate(self, alpha): - """Pareto distribution. alpha is the shape parameter.""" - # Jain, pg. 495 - - u = 1.0 - self.random() - return u ** (-1.0 / alpha) - - def weibullvariate(self, alpha, beta): - """Weibull distribution. - - alpha is the scale parameter and beta is the shape parameter. - - """ - # Jain, pg. 499; bug fix courtesy Bill Arms - - u = 1.0 - self.random() - return alpha * (-_log(u)) ** (1.0 / beta) - - ## ------------------------------------------------------------------ ## --------------- Operating System Random Source ------------------ From 10b47a870acbaf8e553ff6a76c78543194491f99 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 23 Mar 2023 18:18:53 +0000 Subject: [PATCH 202/280] gh-102936: typing: document performance pitfalls of protocols decorated with `@runtime_checkable` (#102937) --- Doc/library/typing.rst | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst index 80a969e6335abe..08ffa0310f0f23 100644 --- a/Doc/library/typing.rst +++ b/Doc/library/typing.rst @@ -1584,16 +1584,32 @@ These are not used in annotations. They are building blocks for creating generic assert isinstance(open('/some/file'), Closable) + @runtime_checkable + class Named(Protocol): + name: str + + import threading + assert isinstance(threading.Thread(name='Bob'), Named) + .. note:: - :func:`runtime_checkable` will check only the presence of the required - methods, not their type signatures. For example, :class:`ssl.SSLObject` + :func:`!runtime_checkable` will check only the presence of the required + methods or attributes, not their type signatures or types. + For example, :class:`ssl.SSLObject` is a class, therefore it passes an :func:`issubclass` check against :data:`Callable`. However, the ``ssl.SSLObject.__init__`` method exists only to raise a :exc:`TypeError` with a more informative message, therefore making it impossible to call (instantiate) :class:`ssl.SSLObject`. + .. note:: + + An :func:`isinstance` check against a runtime-checkable protocol can be + surprisingly slow compared to an ``isinstance()`` check against + a non-protocol class. Consider using alternative idioms such as + :func:`hasattr` calls for structural checks in performance-sensitive + code. + .. versionadded:: 3.8 Other special directives From c25402d6ee349ffdcc2e70f8459121c7a59a23ee Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Thu, 23 Mar 2023 22:35:02 +0300 Subject: [PATCH 203/280] gh-98239: Document that `inspect.getsource()` can raise `TypeError` (#101689) --- Doc/library/inspect.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index ccf240193d36a9..88f843c03b1d5a 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -574,6 +574,8 @@ Retrieving source code object and the line number indicates where in the original source file the first line of code was found. An :exc:`OSError` is raised if the source code cannot be retrieved. + A :exc:`TypeError` is raised if the object is a built-in module, class, or + function. .. versionchanged:: 3.3 :exc:`OSError` is raised instead of :exc:`IOError`, now an alias of the @@ -586,6 +588,8 @@ Retrieving source code class, method, function, traceback, frame, or code object. The source code is returned as a single string. An :exc:`OSError` is raised if the source code cannot be retrieved. + A :exc:`TypeError` is raised if the object is a built-in module, class, or + function. .. versionchanged:: 3.3 :exc:`OSError` is raised instead of :exc:`IOError`, now an alias of the From 110c3dd66a1dd6e12228e4deeb659e41bbec7d5f Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Thu, 23 Mar 2023 14:46:15 -0500 Subject: [PATCH 204/280] Minor readability improvement to the factor() recipe (GH-102971) --- Doc/library/itertools.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 5daadfd3759f4b..70e5b7905f20a9 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -936,7 +936,7 @@ which incur interpreter overhead. n = quotient if n == 1: return - if n >= 2: + if n > 1: yield n def flatten(list_of_lists): From 9227b982f2a1e43a7ebe87c66031d0e3cfb5fabd Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Fri, 24 Mar 2023 05:30:18 +0900 Subject: [PATCH 205/280] gh-102558: [Enum] fix AttributeError during member repr() (GH-102601) --- Lib/enum.py | 2 ++ Lib/test/test_enum.py | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Lib/enum.py b/Lib/enum.py index d14e91a9b017d1..ba927662a43b13 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -1186,6 +1186,8 @@ def _missing_(cls, value): return None def __repr__(self): + if not isinstance(self, Enum): + return repr(self) v_repr = self.__class__._value_repr_ or repr return "<%s.%s: %s>" % (self.__class__.__name__, self._name_, v_repr(self._value_)) diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index a11bb441f06e8e..bb163c46481a42 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -11,7 +11,7 @@ import builtins as bltns from collections import OrderedDict from datetime import date -from enum import Enum, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto +from enum import Enum, EnumMeta, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum from enum import verify, UNIQUE, CONTINUOUS, NAMED_FLAGS, ReprEnum from enum import member, nonmember, _iter_bits_lsb @@ -644,6 +644,13 @@ class MySubEnum(MyEnum): theother = auto() self.assertEqual(repr(MySubEnum.that), "My name is that.") + def test_multiple_superclasses_repr(self): + class _EnumSuperClass(metaclass=EnumMeta): + pass + class E(_EnumSuperClass, Enum): + A = 1 + self.assertEqual(repr(E.A), "") + def test_reversed_iteration_order(self): self.assertEqual( list(reversed(self.MainEnum)), From 6183cbdc92d6648fa9997cdc8fc44971b3fc4983 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 23 Mar 2023 15:25:09 -0700 Subject: [PATCH 206/280] GH-100982: Break up COMPARE_AND_BRANCH (GH-102801) --- Doc/library/dis.rst | 9 -- Include/internal/pycore_code.h | 2 +- Include/internal/pycore_opcode.h | 27 +++-- Include/opcode.h | 107 +++++++++-------- Lib/importlib/_bootstrap_external.py | 4 +- Lib/opcode.py | 13 +-- Lib/test/test_compile.py | 2 +- Lib/test/test_dis.py | 16 +-- ...-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst | 1 + Objects/frameobject.c | 8 -- Python/bytecodes.c | 93 ++++++--------- Python/compile.c | 11 +- Python/generated_cases.c.h | 109 +++++++----------- Python/opcode_metadata.h | 31 +++-- Python/opcode_targets.h | 16 +-- Python/specialize.c | 92 +++++---------- Python/tier2_typepropagator.c.h | 20 ++-- Tools/c-analyzer/cpython/ignored.tsv | 1 - Tools/scripts/summarize_stats.py | 2 - 19 files changed, 232 insertions(+), 332 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index b06fe67a983aa1..8703cddb3448cc 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1042,15 +1042,6 @@ iterations of the loop. ``cmp_op[opname]``. -.. opcode:: COMPARE_AND_BRANCH (opname) - - Compares the top two values on the stack, popping them, then branches. - The direction and offset of the jump is embedded as a ``POP_JUMP_IF_TRUE`` - or ``POP_JUMP_IF_FALSE`` instruction immediately following the cache. - - .. versionadded:: 3.12 - - .. opcode:: IS_OP (invert) Performs ``is`` comparison, or ``is not`` if ``invert`` is 1. diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index bfda105c61d4dc..3586c292117459 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -244,7 +244,7 @@ extern void _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, PyObject *kwnames); extern void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, int oparg, PyObject **locals); -extern void _Py_Specialize_CompareAndBranch(PyObject *lhs, PyObject *rhs, +extern void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, int oparg); extern void _Py_Specialize_UnpackSequence(PyObject *seq, _Py_CODEUNIT *instr, int oparg); diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 4a3270dd11b2de..9884184df4d3d8 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -51,7 +51,6 @@ const uint8_t _PyOpcode_Caches[256] = { [LOAD_GLOBAL] = 4, [BINARY_OP] = 1, [SEND] = 1, - [COMPARE_AND_BRANCH] = 1, [CALL] = 4, }; @@ -109,11 +108,10 @@ const uint8_t _PyOpcode_Deopt[256] = { [CHECK_EG_MATCH] = CHECK_EG_MATCH, [CHECK_EXC_MATCH] = CHECK_EXC_MATCH, [CLEANUP_THROW] = CLEANUP_THROW, - [COMPARE_AND_BRANCH] = COMPARE_AND_BRANCH, - [COMPARE_AND_BRANCH_FLOAT] = COMPARE_AND_BRANCH, - [COMPARE_AND_BRANCH_INT] = COMPARE_AND_BRANCH, - [COMPARE_AND_BRANCH_STR] = COMPARE_AND_BRANCH, [COMPARE_OP] = COMPARE_OP, + [COMPARE_OP_FLOAT] = COMPARE_OP, + [COMPARE_OP_INT] = COMPARE_OP, + [COMPARE_OP_STR] = COMPARE_OP, [CONTAINS_OP] = CONTAINS_OP, [COPY] = COPY, [COPY_FREE_VARS] = COPY_FREE_VARS, @@ -292,9 +290,9 @@ static const char *const _PyOpcode_OpName[263] = { [END_ASYNC_FOR] = "END_ASYNC_FOR", [CLEANUP_THROW] = "CLEANUP_THROW", [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1", - [COMPARE_AND_BRANCH_FLOAT] = "COMPARE_AND_BRANCH_FLOAT", - [COMPARE_AND_BRANCH_INT] = "COMPARE_AND_BRANCH_INT", - [COMPARE_AND_BRANCH_STR] = "COMPARE_AND_BRANCH_STR", + [COMPARE_OP_FLOAT] = "COMPARE_OP_FLOAT", + [COMPARE_OP_INT] = "COMPARE_OP_INT", + [COMPARE_OP_STR] = "COMPARE_OP_STR", [STORE_SUBSCR] = "STORE_SUBSCR", [DELETE_SUBSCR] = "DELETE_SUBSCR", [FOR_ITER_LIST] = "FOR_ITER_LIST", @@ -376,9 +374,9 @@ static const char *const _PyOpcode_OpName[263] = { [STORE_DEREF] = "STORE_DEREF", [DELETE_DEREF] = "DELETE_DEREF", [JUMP_BACKWARD] = "JUMP_BACKWARD", - [COMPARE_AND_BRANCH] = "COMPARE_AND_BRANCH", - [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", + [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", + [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -388,29 +386,28 @@ static const char *const _PyOpcode_OpName[263] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", - [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", + [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", - [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", + [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", - [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", [SEND_GEN] = "SEND_GEN", [BB_BRANCH] = "BB_BRANCH", + [BB_BRANCH_IF_FLAG_UNSET] = "BB_BRANCH_IF_FLAG_UNSET", [CALL] = "CALL", [KW_NAMES] = "KW_NAMES", [CALL_INTRINSIC_1] = "CALL_INTRINSIC_1", [CALL_INTRINSIC_2] = "CALL_INTRINSIC_2", - [BB_BRANCH_IF_FLAG_UNSET] = "BB_BRANCH_IF_FLAG_UNSET", [BB_BRANCH_IF_FLAG_SET] = "BB_BRANCH_IF_FLAG_SET", [BB_JUMP_IF_FLAG_UNSET] = "BB_JUMP_IF_FLAG_UNSET", [BB_JUMP_IF_FLAG_SET] = "BB_JUMP_IF_FLAG_SET", @@ -434,6 +431,7 @@ static const char *const _PyOpcode_OpName[263] = { [STORE_FAST_BOXED_UNBOXED] = "STORE_FAST_BOXED_UNBOXED", [STORE_FAST_UNBOXED_BOXED] = "STORE_FAST_UNBOXED_BOXED", [STORE_FAST_UNBOXED_UNBOXED] = "STORE_FAST_UNBOXED_UNBOXED", + [198] = "<198>", [199] = "<199>", [200] = "<200>", [201] = "<201>", @@ -503,6 +501,7 @@ static const char *const _PyOpcode_OpName[263] = { #define EXTRA_CASES \ + case 198: \ case 199: \ case 200: \ case 201: \ diff --git a/Include/opcode.h b/Include/opcode.h index 6f02501b835718..ae70a273f41573 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -93,7 +93,6 @@ extern "C" { #define STORE_DEREF 138 #define DELETE_DEREF 139 #define JUMP_BACKWARD 140 -#define COMPARE_AND_BRANCH 141 #define CALL_FUNCTION_EX 142 #define EXTENDED_ARG 144 #define LIST_APPEND 145 @@ -155,9 +154,9 @@ extern "C" { #define CALL_NO_KW_STR_1 47 #define CALL_NO_KW_TUPLE_1 48 #define CALL_NO_KW_TYPE_1 56 -#define COMPARE_AND_BRANCH_FLOAT 57 -#define COMPARE_AND_BRANCH_INT 58 -#define COMPARE_AND_BRANCH_STR 59 +#define COMPARE_OP_FLOAT 57 +#define COMPARE_OP_INT 58 +#define COMPARE_OP_STR 59 #define FOR_ITER_LIST 62 #define FOR_ITER_TUPLE 63 #define FOR_ITER_RANGE 64 @@ -181,17 +180,17 @@ extern "C" { #define LOAD_FAST__LOAD_FAST 111 #define LOAD_GLOBAL_BUILTIN 112 #define LOAD_GLOBAL_MODULE 113 -#define STORE_ATTR_INSTANCE_VALUE 143 -#define STORE_ATTR_SLOT 153 -#define STORE_ATTR_WITH_HINT 154 -#define STORE_FAST__LOAD_FAST 158 -#define STORE_FAST__STORE_FAST 159 -#define STORE_SUBSCR_DICT 160 -#define STORE_SUBSCR_LIST_INT 161 -#define UNPACK_SEQUENCE_LIST 166 -#define UNPACK_SEQUENCE_TUPLE 167 -#define UNPACK_SEQUENCE_TWO_TUPLE 168 -#define SEND_GEN 169 +#define STORE_ATTR_INSTANCE_VALUE 141 +#define STORE_ATTR_SLOT 143 +#define STORE_ATTR_WITH_HINT 153 +#define STORE_FAST__LOAD_FAST 154 +#define STORE_FAST__STORE_FAST 158 +#define STORE_SUBSCR_DICT 159 +#define STORE_SUBSCR_LIST_INT 160 +#define UNPACK_SEQUENCE_LIST 161 +#define UNPACK_SEQUENCE_TUPLE 166 +#define UNPACK_SEQUENCE_TWO_TUPLE 167 +#define SEND_GEN 168 #define DO_TRACING 255 // Tier 2 interpreter ops #define RESUME_QUICK 5 @@ -225,9 +224,9 @@ extern "C" { #define CALL_NO_KW_STR_1 47 #define CALL_NO_KW_TUPLE_1 48 #define CALL_NO_KW_TYPE_1 56 -#define COMPARE_AND_BRANCH_FLOAT 57 -#define COMPARE_AND_BRANCH_INT 58 -#define COMPARE_AND_BRANCH_STR 59 +#define COMPARE_OP_FLOAT 57 +#define COMPARE_OP_INT 58 +#define COMPARE_OP_STR 59 #define FOR_ITER_LIST 62 #define FOR_ITER_TUPLE 63 #define FOR_ITER_RANGE 64 @@ -251,43 +250,43 @@ extern "C" { #define LOAD_FAST__LOAD_FAST 111 #define LOAD_GLOBAL_BUILTIN 112 #define LOAD_GLOBAL_MODULE 113 -#define STORE_ATTR_INSTANCE_VALUE 143 -#define STORE_ATTR_SLOT 153 -#define STORE_ATTR_WITH_HINT 154 -#define STORE_FAST__LOAD_FAST 158 -#define STORE_FAST__STORE_FAST 159 -#define STORE_SUBSCR_DICT 160 -#define STORE_SUBSCR_LIST_INT 161 -#define UNPACK_SEQUENCE_LIST 166 -#define UNPACK_SEQUENCE_TUPLE 167 -#define UNPACK_SEQUENCE_TWO_TUPLE 168 -#define SEND_GEN 169 +#define STORE_ATTR_INSTANCE_VALUE 141 +#define STORE_ATTR_SLOT 143 +#define STORE_ATTR_WITH_HINT 153 +#define STORE_FAST__LOAD_FAST 154 +#define STORE_FAST__STORE_FAST 158 +#define STORE_SUBSCR_DICT 159 +#define STORE_SUBSCR_LIST_INT 160 +#define UNPACK_SEQUENCE_LIST 161 +#define UNPACK_SEQUENCE_TUPLE 166 +#define UNPACK_SEQUENCE_TWO_TUPLE 167 +#define SEND_GEN 168 #define DO_TRACING 255 -#define BB_BRANCH 170 -#define BB_BRANCH_IF_FLAG_UNSET 175 -#define BB_BRANCH_IF_FLAG_SET 176 -#define BB_JUMP_IF_FLAG_UNSET 177 -#define BB_JUMP_IF_FLAG_SET 178 -#define BB_TEST_ITER 179 -#define BB_TEST_IF_FALSE_OR_POP 180 -#define BB_TEST_IF_TRUE_OR_POP 181 -#define BB_TEST_POP_IF_FALSE 182 -#define BB_TEST_POP_IF_TRUE 183 -#define BB_TEST_POP_IF_NOT_NONE 184 -#define BB_TEST_POP_IF_NONE 185 -#define BB_JUMP_BACKWARD_LAZY 186 -#define BINARY_CHECK_INT 187 -#define BINARY_CHECK_FLOAT 188 -#define UNARY_CHECK_FLOAT 189 -#define BINARY_OP_ADD_INT_REST 190 -#define BINARY_OP_ADD_FLOAT_UNBOXED 191 -#define POP_TOP_NO_DECREF 192 -#define UNBOX_FLOAT 193 -#define BOX_FLOAT 194 -#define LOAD_FAST_NO_INCREF 195 -#define STORE_FAST_BOXED_UNBOXED 196 -#define STORE_FAST_UNBOXED_BOXED 197 -#define STORE_FAST_UNBOXED_UNBOXED 198 +#define BB_BRANCH 169 +#define BB_BRANCH_IF_FLAG_UNSET 170 +#define BB_BRANCH_IF_FLAG_SET 175 +#define BB_JUMP_IF_FLAG_UNSET 176 +#define BB_JUMP_IF_FLAG_SET 177 +#define BB_TEST_ITER 178 +#define BB_TEST_IF_FALSE_OR_POP 179 +#define BB_TEST_IF_TRUE_OR_POP 180 +#define BB_TEST_POP_IF_FALSE 181 +#define BB_TEST_POP_IF_TRUE 182 +#define BB_TEST_POP_IF_NOT_NONE 183 +#define BB_TEST_POP_IF_NONE 184 +#define BB_JUMP_BACKWARD_LAZY 185 +#define BINARY_CHECK_INT 186 +#define BINARY_CHECK_FLOAT 187 +#define UNARY_CHECK_FLOAT 188 +#define BINARY_OP_ADD_INT_REST 189 +#define BINARY_OP_ADD_FLOAT_UNBOXED 190 +#define POP_TOP_NO_DECREF 191 +#define UNBOX_FLOAT 192 +#define BOX_FLOAT 193 +#define LOAD_FAST_NO_INCREF 194 +#define STORE_FAST_BOXED_UNBOXED 195 +#define STORE_FAST_UNBOXED_BOXED 196 +#define STORE_FAST_UNBOXED_UNBOXED 197 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 3f78300c226345..28e55fdc8b7d10 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -435,7 +435,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.12a6 3519 (Modify SEND instruction) # Python 3.12a6 3520 (Remove PREP_RERAISE_STAR, add CALL_INTRINSIC_2) # Python 3.12a7 3521 (Shrink the LOAD_GLOBAL caches) -# Python 3.12a7 3522 (Removed JUMP_IF_FALSE_OR_POP/JUMP_IF_TRUE_OR_POP) +# Python 3.12a7 3523 (Convert COMPARE_AND_BRANCH back to COMPARE_OP) # Python 3.13 will start with 3550 @@ -452,7 +452,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3522).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3523).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/opcode.py b/Lib/opcode.py index cacbdaf575039f..fba7f76cc279b7 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -191,8 +191,6 @@ def pseudo_op(name, op, real_ops): def_op('DELETE_DEREF', 139) hasfree.append(139) jrel_op('JUMP_BACKWARD', 140) # Number of words to skip (backwards) -def_op('COMPARE_AND_BRANCH', 141) # Comparison and jump -hascompare.append(141) def_op('CALL_FUNCTION_EX', 142) # Flags @@ -320,10 +318,10 @@ def pseudo_op(name, op, real_ops): "CALL_NO_KW_TUPLE_1", "CALL_NO_KW_TYPE_1", ], - "COMPARE_AND_BRANCH": [ - "COMPARE_AND_BRANCH_FLOAT", - "COMPARE_AND_BRANCH_INT", - "COMPARE_AND_BRANCH_STR", + "COMPARE_OP": [ + "COMPARE_OP_FLOAT", + "COMPARE_OP_INT", + "COMPARE_OP_STR", ], "FOR_ITER": [ "FOR_ITER_LIST", @@ -404,9 +402,6 @@ def pseudo_op(name, op, real_ops): "COMPARE_OP": { "counter": 1, }, - "COMPARE_AND_BRANCH": { - "counter": 1, - }, "BINARY_SUBSCR": { "counter": 1, "type_version": 2, diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index fe775779c50f50..dca38418935b76 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1283,7 +1283,7 @@ def test_multiline_boolean_expression(self): self.assertOpcodeSourcePositionIs(compiled_code, 'POP_JUMP_IF_FALSE', line=2, end_line=2, column=15, end_column=16, occurrence=2) # compare d and 0 - self.assertOpcodeSourcePositionIs(compiled_code, 'COMPARE_AND_BRANCH', + self.assertOpcodeSourcePositionIs(compiled_code, 'COMPARE_OP', line=4, end_line=4, column=8, end_column=13, occurrence=1) # jump if comparison it True self.assertOpcodeSourcePositionIs(compiled_code, 'POP_JUMP_IF_TRUE', diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index fa1de1c7ded1b3..ed66b362b08080 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -46,7 +46,7 @@ def cm(cls, x): %3d LOAD_FAST 1 (x) LOAD_CONST 1 (1) - COMPARE_OP 32 (==) + COMPARE_OP 40 (==) LOAD_FAST 0 (self) STORE_ATTR 0 (x) RETURN_CONST 0 (None) @@ -56,7 +56,7 @@ def cm(cls, x): RESUME 0 LOAD_FAST 1 LOAD_CONST 1 - COMPARE_OP 32 (==) + COMPARE_OP 40 (==) LOAD_FAST 0 STORE_ATTR 0 RETURN_CONST 0 @@ -67,7 +67,7 @@ def cm(cls, x): %3d LOAD_FAST 1 (x) LOAD_CONST 1 (1) - COMPARE_OP 32 (==) + COMPARE_OP 40 (==) LOAD_FAST 0 (cls) STORE_ATTR 0 (x) RETURN_CONST 0 (None) @@ -78,7 +78,7 @@ def cm(cls, x): %3d LOAD_FAST 0 (x) LOAD_CONST 1 (1) - COMPARE_OP 32 (==) + COMPARE_OP 40 (==) STORE_FAST 0 (x) RETURN_CONST 0 (None) """ % (_C.sm.__code__.co_firstlineno, _C.sm.__code__.co_firstlineno + 2,) @@ -1554,12 +1554,12 @@ def _prepare_test_cases(): Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=54, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=56, starts_line=5, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=58, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=13, argval='<', argrepr='<', offset=60, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=2, argval='<', argrepr='<', offset=60, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=68, argrepr='to 68', offset=64, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_BACKWARD', opcode=140, arg=21, argval=26, argrepr='to 26', offset=66, starts_line=6, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=68, starts_line=7, is_jump_target=True, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=70, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=68, argval='>', argrepr='>', offset=72, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=68, argval='>', argrepr='>', offset=72, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=1, argval=80, argrepr='to 80', offset=76, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_BACKWARD', opcode=140, arg=27, argval=26, argrepr='to 26', offset=78, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=80, starts_line=8, is_jump_target=True, positions=None), @@ -1581,12 +1581,12 @@ def _prepare_test_cases(): Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=146, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=148, starts_line=14, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=150, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=75, argval='>', argrepr='>', offset=152, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=68, argval='>', argrepr='>', offset=152, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=160, argrepr='to 160', offset=156, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_BACKWARD', opcode=140, arg=25, argval=110, argrepr='to 110', offset=158, starts_line=15, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=160, starts_line=16, is_jump_target=True, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=162, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='COMPARE_AND_BRANCH', opcode=141, arg=13, argval='<', argrepr='<', offset=164, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='COMPARE_OP', opcode=107, arg=2, argval='<', argrepr='<', offset=164, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=1, argval=172, argrepr='to 172', offset=168, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=15, argval=202, argrepr='to 202', offset=170, starts_line=17, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=172, starts_line=11, is_jump_target=True, positions=None), diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst new file mode 100644 index 00000000000000..31a8660836c759 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-17-12-09-45.gh-issue-100982.Pf_BI6.rst @@ -0,0 +1 @@ +Replace all occurrences of ``COMPARE_AND_BRANCH`` with :opcode:`COMPARE_OP`. diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 19bd4b10780b91..63590d58809e3e 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -347,14 +347,6 @@ mark_stacks(PyCodeObject *code_obj, int len) assert(stacks[j] == UNINITIALIZED || stacks[j] == next_stack); stacks[j] = next_stack; break; - case COMPARE_AND_BRANCH: - next_stack = pop_value(pop_value(next_stack)); - i++; - j = get_arg(code, i) + i + 1; - assert(j < len); - assert(stacks[j] == UNINITIALIZED || stacks[j] == next_stack); - stacks[j] = next_stack; - break; case GET_ITER: case GET_AITER: next_stack = push_value(pop_value(next_stack), Iterator); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index b9a6a9e2b61208..55ef034c9a9ff8 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1760,75 +1760,54 @@ dummy_func( Py_DECREF(owner); } - inst(COMPARE_OP, (unused/1, left, right -- res)) { - STAT_INC(COMPARE_OP, deferred); - assert((oparg >> 4) <= Py_GE); - res = PyObject_RichCompare(left, right, oparg>>4); - DECREF_INPUTS(); - ERROR_IF(res == NULL, error); - } - - // No cache size here, since this is a family of super-instructions. - family(compare_and_branch) = { - COMPARE_AND_BRANCH, - COMPARE_AND_BRANCH_FLOAT, - COMPARE_AND_BRANCH_INT, - COMPARE_AND_BRANCH_STR, + family(compare_op, INLINE_CACHE_ENTRIES_COMPARE_OP) = { + COMPARE_OP, + COMPARE_OP_FLOAT, + COMPARE_OP_INT, + COMPARE_OP_STR, }; - inst(COMPARE_AND_BRANCH, (unused/2, left, right -- )) { + inst(COMPARE_OP, (unused/1, left, right -- res)) { #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); next_instr--; - _Py_Specialize_CompareAndBranch(left, right, next_instr, oparg); + _Py_Specialize_CompareOp(left, right, next_instr, oparg); DISPATCH_SAME_OPARG(); } - STAT_INC(COMPARE_AND_BRANCH, deferred); + STAT_INC(COMPARE_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); - PyObject *cond = PyObject_RichCompare(left, right, oparg>>4); + res = PyObject_RichCompare(left, right, oparg>>4); DECREF_INPUTS(); - ERROR_IF(cond == NULL, error); - assert(next_instr[1].op.code == POP_JUMP_IF_FALSE || - next_instr[1].op.code == POP_JUMP_IF_TRUE); - bool jump_on_true = next_instr[1].op.code == POP_JUMP_IF_TRUE; - int offset = next_instr[1].op.arg; - int err = PyObject_IsTrue(cond); - Py_DECREF(cond); - ERROR_IF(err < 0, error); - if (jump_on_true == (err != 0)) { - JUMPBY(offset); - } + ERROR_IF(res == NULL, error); } - inst(COMPARE_AND_BRANCH_FLOAT, (unused/2, left, right -- )) { + inst(COMPARE_OP_FLOAT, (unused/1, left, right -- res)) { assert(cframe.use_tracing == 0); - DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); + DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); + STAT_INC(COMPARE_OP, hit); double dleft = PyFloat_AS_DOUBLE(left); double dright = PyFloat_AS_DOUBLE(right); // 1 if NaN, 2 if <, 4 if >, 8 if ==; this matches low four bits of the oparg int sign_ish = COMPARISON_BIT(dleft, dright); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); - if (sign_ish & oparg) { - int offset = next_instr[1].op.arg; - JUMPBY(offset); - } + res = (sign_ish & oparg) ? Py_True : Py_False; + Py_INCREF(res); } - // Similar to COMPARE_AND_BRANCH_FLOAT - inst(COMPARE_AND_BRANCH_INT, (unused/2, left, right -- )) { + // Similar to COMPARE_OP_FLOAT + inst(COMPARE_OP_INT, (unused/1, left, right -- res)) { assert(cframe.use_tracing == 0); - DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); - DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_AND_BRANCH); - DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); + DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_OP); + STAT_INC(COMPARE_OP, hit); assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 && _PyLong_DigitCount((PyLongObject *)right) <= 1); Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left); @@ -1837,29 +1816,25 @@ dummy_func( int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - if (sign_ish & oparg) { - int offset = next_instr[1].op.arg; - JUMPBY(offset); - } + res = (sign_ish & oparg) ? Py_True : Py_False; + Py_INCREF(res); } - // Similar to COMPARE_AND_BRANCH_FLOAT, but for ==, != only - inst(COMPARE_AND_BRANCH_STR, (unused/2, left, right -- )) { + // Similar to COMPARE_OP_FLOAT, but for ==, != only + inst(COMPARE_OP_STR, (unused/1, left, right -- res)) { assert(cframe.use_tracing == 0); - DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); - int res = _PyUnicode_Equal(left, right); + DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); + STAT_INC(COMPARE_OP, hit); + int eq = _PyUnicode_Equal(left, right); assert((oparg >>4) == Py_EQ || (oparg >>4) == Py_NE); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - assert(res == 0 || res == 1); + assert(eq == 0 || eq == 1); assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); - if ((res + COMPARISON_NOT_EQUALS) & oparg) { - int offset = next_instr[1].op.arg; - JUMPBY(offset); - } + res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; + Py_INCREF(res); } inst(IS_OP, (left, right -- b: PyBool_Type)) { diff --git a/Python/compile.c b/Python/compile.c index 33cd6ca07d3bb6..192deaa4b35f4d 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -2800,6 +2800,15 @@ check_compare(struct compiler *c, expr_ty e) return SUCCESS; } +static const int compare_masks[] = { + [Py_LT] = COMPARISON_LESS_THAN, + [Py_LE] = COMPARISON_LESS_THAN | COMPARISON_EQUALS, + [Py_EQ] = COMPARISON_EQUALS, + [Py_NE] = COMPARISON_NOT_EQUALS, + [Py_GT] = COMPARISON_GREATER_THAN, + [Py_GE] = COMPARISON_GREATER_THAN | COMPARISON_EQUALS, +}; + static int compiler_addcompare(struct compiler *c, location loc, cmpop_ty op) { @@ -2840,7 +2849,7 @@ static int compiler_addcompare(struct compiler *c, location loc, } /* cmp goes in top bits of the oparg, while the low bits are used by quickened * versions of this opcode to store the comparison mask. */ - ADDOP_I(c, loc, COMPARE_OP, cmp << 4); + ADDOP_I(c, loc, COMPARE_OP, (cmp << 4) | compare_masks[cmp]); return SUCCESS; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index e74ef78c3b0aeb..158116daaaddc4 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2271,87 +2271,65 @@ } TARGET(COMPARE_OP) { + PREDICTED(COMPARE_OP); + static_assert(INLINE_CACHE_ENTRIES_COMPARE_OP == 1, "incorrect cache size"); PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - STAT_INC(COMPARE_OP, deferred); - assert((oparg >> 4) <= Py_GE); - res = PyObject_RichCompare(left, right, oparg>>4); - Py_DECREF(left); - Py_DECREF(right); - if (res == NULL) goto pop_2_error; - STACK_SHRINK(1); - stack_pointer[-1] = res; - next_instr += 1; - DISPATCH(); - } - - TARGET(COMPARE_AND_BRANCH) { - PREDICTED(COMPARE_AND_BRANCH); - PyObject *right = stack_pointer[-1]; - PyObject *left = stack_pointer[-2]; #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); next_instr--; - _Py_Specialize_CompareAndBranch(left, right, next_instr, oparg); + _Py_Specialize_CompareOp(left, right, next_instr, oparg); DISPATCH_SAME_OPARG(); } - STAT_INC(COMPARE_AND_BRANCH, deferred); + STAT_INC(COMPARE_OP, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); - PyObject *cond = PyObject_RichCompare(left, right, oparg>>4); + res = PyObject_RichCompare(left, right, oparg>>4); Py_DECREF(left); Py_DECREF(right); - if (cond == NULL) goto pop_2_error; - assert(next_instr[1].op.code == POP_JUMP_IF_FALSE || - next_instr[1].op.code == POP_JUMP_IF_TRUE); - bool jump_on_true = next_instr[1].op.code == POP_JUMP_IF_TRUE; - int offset = next_instr[1].op.arg; - int err = PyObject_IsTrue(cond); - Py_DECREF(cond); - if (err < 0) goto pop_2_error; - if (jump_on_true == (err != 0)) { - JUMPBY(offset); - } - STACK_SHRINK(2); - next_instr += 2; + if (res == NULL) goto pop_2_error; + STACK_SHRINK(1); + stack_pointer[-1] = res; + next_instr += 1; DISPATCH(); } - TARGET(COMPARE_AND_BRANCH_FLOAT) { + TARGET(COMPARE_OP_FLOAT) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; + PyObject *res; assert(cframe.use_tracing == 0); - DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); + DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); + STAT_INC(COMPARE_OP, hit); double dleft = PyFloat_AS_DOUBLE(left); double dright = PyFloat_AS_DOUBLE(right); // 1 if NaN, 2 if <, 4 if >, 8 if ==; this matches low four bits of the oparg int sign_ish = COMPARISON_BIT(dleft, dright); _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); - if (sign_ish & oparg) { - int offset = next_instr[1].op.arg; - JUMPBY(offset); - } - STACK_SHRINK(2); - next_instr += 2; + res = (sign_ish & oparg) ? Py_True : Py_False; + Py_INCREF(res); + STACK_SHRINK(1); + stack_pointer[-1] = res; + next_instr += 1; DISPATCH(); } - TARGET(COMPARE_AND_BRANCH_INT) { + TARGET(COMPARE_OP_INT) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; + PyObject *res; assert(cframe.use_tracing == 0); - DEOPT_IF(!PyLong_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyLong_CheckExact(right), COMPARE_AND_BRANCH); - DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_AND_BRANCH); - DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); + DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); + DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)right), COMPARE_OP); + STAT_INC(COMPARE_OP, hit); assert(_PyLong_DigitCount((PyLongObject *)left) <= 1 && _PyLong_DigitCount((PyLongObject *)right) <= 1); Py_ssize_t ileft = _PyLong_CompactValue((PyLongObject *)left); @@ -2360,35 +2338,34 @@ int sign_ish = COMPARISON_BIT(ileft, iright); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); - if (sign_ish & oparg) { - int offset = next_instr[1].op.arg; - JUMPBY(offset); - } - STACK_SHRINK(2); - next_instr += 2; + res = (sign_ish & oparg) ? Py_True : Py_False; + Py_INCREF(res); + STACK_SHRINK(1); + stack_pointer[-1] = res; + next_instr += 1; DISPATCH(); } - TARGET(COMPARE_AND_BRANCH_STR) { + TARGET(COMPARE_OP_STR) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; + PyObject *res; assert(cframe.use_tracing == 0); - DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_AND_BRANCH); - DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_AND_BRANCH); - STAT_INC(COMPARE_AND_BRANCH, hit); - int res = _PyUnicode_Equal(left, right); + DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); + DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); + STAT_INC(COMPARE_OP, hit); + int eq = _PyUnicode_Equal(left, right); assert((oparg >>4) == Py_EQ || (oparg >>4) == Py_NE); _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); - assert(res == 0 || res == 1); + assert(eq == 0 || eq == 1); assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); - if ((res + COMPARISON_NOT_EQUALS) & oparg) { - int offset = next_instr[1].op.arg; - JUMPBY(offset); - } - STACK_SHRINK(2); - next_instr += 2; + res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; + Py_INCREF(res); + STACK_SHRINK(1); + stack_pointer[-1] = res; + next_instr += 1; DISPATCH(); } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 25463ced32d5d4..bc3aeba527d13b 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -241,13 +241,11 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 2; case COMPARE_OP: return 2; - case COMPARE_AND_BRANCH: + case COMPARE_OP_FLOAT: return 2; - case COMPARE_AND_BRANCH_FLOAT: + case COMPARE_OP_INT: return 2; - case COMPARE_AND_BRANCH_INT: - return 2; - case COMPARE_AND_BRANCH_STR: + case COMPARE_OP_STR: return 2; case IS_OP: return 2; @@ -637,14 +635,12 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case COMPARE_OP: return 1; - case COMPARE_AND_BRANCH: - return 0; - case COMPARE_AND_BRANCH_FLOAT: - return 0; - case COMPARE_AND_BRANCH_INT: - return 0; - case COMPARE_AND_BRANCH_STR: - return 0; + case COMPARE_OP_FLOAT: + return 1; + case COMPARE_OP_INT: + return 1; + case COMPARE_OP_STR: + return 1; case IS_OP: return 1; case CONTAINS_OP: @@ -795,7 +791,7 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { } #endif -enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC0, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; +enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 }; struct opcode_metadata { bool valid_entry; enum InstructionFormat instr_format; @@ -921,10 +917,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [STORE_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC000 }, [STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC000 }, [COMPARE_OP] = { true, INSTR_FMT_IBC }, - [COMPARE_AND_BRANCH] = { true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_FLOAT] = { true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_INT] = { true, INSTR_FMT_IBC0 }, - [COMPARE_AND_BRANCH_STR] = { true, INSTR_FMT_IBC0 }, + [COMPARE_OP_FLOAT] = { true, INSTR_FMT_IBC }, + [COMPARE_OP_INT] = { true, INSTR_FMT_IBC }, + [COMPARE_OP_STR] = { true, INSTR_FMT_IBC }, [IS_OP] = { true, INSTR_FMT_IB }, [CONTAINS_OP] = { true, INSTR_FMT_IB }, [CHECK_EG_MATCH] = { true, INSTR_FMT_IX }, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 38217d9e8f2ba9..48c858e0cd2d00 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -56,9 +56,9 @@ static void *opcode_targets[256] = { &&TARGET_END_ASYNC_FOR, &&TARGET_CLEANUP_THROW, &&TARGET_CALL_NO_KW_TYPE_1, - &&TARGET_COMPARE_AND_BRANCH_FLOAT, - &&TARGET_COMPARE_AND_BRANCH_INT, - &&TARGET_COMPARE_AND_BRANCH_STR, + &&TARGET_COMPARE_OP_FLOAT, + &&TARGET_COMPARE_OP_INT, + &&TARGET_COMPARE_OP_STR, &&TARGET_STORE_SUBSCR, &&TARGET_DELETE_SUBSCR, &&TARGET_FOR_ITER_LIST, @@ -140,9 +140,9 @@ static void *opcode_targets[256] = { &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, &&TARGET_JUMP_BACKWARD, - &&TARGET_COMPARE_AND_BRANCH, - &&TARGET_CALL_FUNCTION_EX, &&TARGET_STORE_ATTR_INSTANCE_VALUE, + &&TARGET_CALL_FUNCTION_EX, + &&TARGET_STORE_ATTR_SLOT, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,24 +152,24 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, - &&TARGET_STORE_ATTR_SLOT, &&TARGET_STORE_ATTR_WITH_HINT, + &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, - &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_STORE_FAST__STORE_FAST, &&TARGET_STORE_SUBSCR_DICT, &&TARGET_STORE_SUBSCR_LIST_INT, + &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, - &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&TARGET_SEND_GEN, &&_unknown_opcode, + &&_unknown_opcode, &&TARGET_CALL, &&TARGET_KW_NAMES, &&TARGET_CALL_INTRINSIC_1, diff --git a/Python/specialize.c b/Python/specialize.c index 2e93ab193990a1..dd5b22dd2346c5 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -264,15 +264,6 @@ do { \ #define SPECIALIZATION_FAIL(opcode, kind) ((void)0) #endif -static int compare_masks[] = { - [Py_LT] = COMPARISON_LESS_THAN, - [Py_LE] = COMPARISON_LESS_THAN | COMPARISON_EQUALS, - [Py_EQ] = COMPARISON_EQUALS, - [Py_NE] = COMPARISON_NOT_EQUALS, - [Py_GT] = COMPARISON_GREATER_THAN, - [Py_GE] = COMPARISON_GREATER_THAN | COMPARISON_EQUALS, -}; - // Initialize warmup counters and insert superinstructions. This cannot fail. void _PyCode_Quicken(PyCodeObject *code) @@ -305,19 +296,6 @@ _PyCode_Quicken(PyCodeObject *code) case STORE_FAST << 8 | STORE_FAST: instructions[i - 1].op.code = STORE_FAST__STORE_FAST; break; - case COMPARE_OP << 8 | POP_JUMP_IF_TRUE: - case COMPARE_OP << 8 | POP_JUMP_IF_FALSE: - { - int oparg = instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].op.arg; - assert((oparg >> 4) <= Py_GE); - int mask = compare_masks[oparg >> 4]; - if (opcode == POP_JUMP_IF_FALSE) { - mask = mask ^ 0xf; - } - instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].op.code = COMPARE_AND_BRANCH; - instructions[i - 1 - INLINE_CACHE_ENTRIES_COMPARE_OP].op.arg = (oparg & 0xf0) | mask; - break; - } } } #endif /* ENABLE_SPECIALIZATION */ @@ -436,19 +414,17 @@ _PyCode_Quicken(PyCodeObject *code) #define SPEC_FAIL_CALL_OPERATOR_WRAPPER 29 /* COMPARE_OP */ -#define SPEC_FAIL_COMPARE_DIFFERENT_TYPES 12 -#define SPEC_FAIL_COMPARE_STRING 13 -#define SPEC_FAIL_COMPARE_NOT_FOLLOWED_BY_COND_JUMP 14 -#define SPEC_FAIL_COMPARE_BIG_INT 15 -#define SPEC_FAIL_COMPARE_BYTES 16 -#define SPEC_FAIL_COMPARE_TUPLE 17 -#define SPEC_FAIL_COMPARE_LIST 18 -#define SPEC_FAIL_COMPARE_SET 19 -#define SPEC_FAIL_COMPARE_BOOL 20 -#define SPEC_FAIL_COMPARE_BASEOBJECT 21 -#define SPEC_FAIL_COMPARE_FLOAT_LONG 22 -#define SPEC_FAIL_COMPARE_LONG_FLOAT 23 -#define SPEC_FAIL_COMPARE_EXTENDED_ARG 24 +#define SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES 12 +#define SPEC_FAIL_COMPARE_OP_STRING 13 +#define SPEC_FAIL_COMPARE_OP_BIG_INT 14 +#define SPEC_FAIL_COMPARE_OP_BYTES 15 +#define SPEC_FAIL_COMPARE_OP_TUPLE 16 +#define SPEC_FAIL_COMPARE_OP_LIST 17 +#define SPEC_FAIL_COMPARE_OP_SET 18 +#define SPEC_FAIL_COMPARE_OP_BOOL 19 +#define SPEC_FAIL_COMPARE_OP_BASEOBJECT 20 +#define SPEC_FAIL_COMPARE_OP_FLOAT_LONG 21 +#define SPEC_FAIL_COMPARE_OP_LONG_FLOAT 22 /* FOR_ITER */ #define SPEC_FAIL_FOR_ITER_GENERATOR 10 @@ -1958,83 +1934,79 @@ compare_op_fail_kind(PyObject *lhs, PyObject *rhs) { if (Py_TYPE(lhs) != Py_TYPE(rhs)) { if (PyFloat_CheckExact(lhs) && PyLong_CheckExact(rhs)) { - return SPEC_FAIL_COMPARE_FLOAT_LONG; + return SPEC_FAIL_COMPARE_OP_FLOAT_LONG; } if (PyLong_CheckExact(lhs) && PyFloat_CheckExact(rhs)) { - return SPEC_FAIL_COMPARE_LONG_FLOAT; + return SPEC_FAIL_COMPARE_OP_LONG_FLOAT; } - return SPEC_FAIL_COMPARE_DIFFERENT_TYPES; + return SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES; } if (PyBytes_CheckExact(lhs)) { - return SPEC_FAIL_COMPARE_BYTES; + return SPEC_FAIL_COMPARE_OP_BYTES; } if (PyTuple_CheckExact(lhs)) { - return SPEC_FAIL_COMPARE_TUPLE; + return SPEC_FAIL_COMPARE_OP_TUPLE; } if (PyList_CheckExact(lhs)) { - return SPEC_FAIL_COMPARE_LIST; + return SPEC_FAIL_COMPARE_OP_LIST; } if (PySet_CheckExact(lhs) || PyFrozenSet_CheckExact(lhs)) { - return SPEC_FAIL_COMPARE_SET; + return SPEC_FAIL_COMPARE_OP_SET; } if (PyBool_Check(lhs)) { - return SPEC_FAIL_COMPARE_BOOL; + return SPEC_FAIL_COMPARE_OP_BOOL; } if (Py_TYPE(lhs)->tp_richcompare == PyBaseObject_Type.tp_richcompare) { - return SPEC_FAIL_COMPARE_BASEOBJECT; + return SPEC_FAIL_COMPARE_OP_BASEOBJECT; } return SPEC_FAIL_OTHER; } #endif void -_Py_Specialize_CompareAndBranch(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, +_Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, int oparg) { assert(ENABLE_SPECIALIZATION); - assert(_PyOpcode_Caches[COMPARE_AND_BRANCH] == INLINE_CACHE_ENTRIES_COMPARE_OP); + assert(_PyOpcode_Caches[COMPARE_OP] == INLINE_CACHE_ENTRIES_COMPARE_OP); _PyCompareOpCache *cache = (_PyCompareOpCache *)(instr + 1); -#ifndef NDEBUG - int next_opcode = instr[INLINE_CACHE_ENTRIES_COMPARE_OP + 1].op.code; - assert(next_opcode == POP_JUMP_IF_FALSE || next_opcode == POP_JUMP_IF_TRUE); -#endif if (Py_TYPE(lhs) != Py_TYPE(rhs)) { - SPECIALIZATION_FAIL(COMPARE_AND_BRANCH, compare_op_fail_kind(lhs, rhs)); + SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs)); goto failure; } if (PyFloat_CheckExact(lhs)) { - instr->op.code = COMPARE_AND_BRANCH_FLOAT; + instr->op.code = COMPARE_OP_FLOAT; goto success; } if (PyLong_CheckExact(lhs)) { if (_PyLong_IsCompact((PyLongObject *)lhs) && _PyLong_IsCompact((PyLongObject *)rhs)) { - instr->op.code = COMPARE_AND_BRANCH_INT; + instr->op.code = COMPARE_OP_INT; goto success; } else { - SPECIALIZATION_FAIL(COMPARE_AND_BRANCH, SPEC_FAIL_COMPARE_BIG_INT); + SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_COMPARE_OP_BIG_INT); goto failure; } } if (PyUnicode_CheckExact(lhs)) { int cmp = oparg >> 4; if (cmp != Py_EQ && cmp != Py_NE) { - SPECIALIZATION_FAIL(COMPARE_AND_BRANCH, SPEC_FAIL_COMPARE_STRING); + SPECIALIZATION_FAIL(COMPARE_OP, SPEC_FAIL_COMPARE_OP_STRING); goto failure; } else { - instr->op.code = COMPARE_AND_BRANCH_STR; + instr->op.code = COMPARE_OP_STR; goto success; } } - SPECIALIZATION_FAIL(COMPARE_AND_BRANCH, compare_op_fail_kind(lhs, rhs)); + SPECIALIZATION_FAIL(COMPARE_OP, compare_op_fail_kind(lhs, rhs)); failure: - STAT_INC(COMPARE_AND_BRANCH, failure); - instr->op.code = COMPARE_AND_BRANCH; + STAT_INC(COMPARE_OP, failure); + instr->op.code = COMPARE_OP; cache->counter = adaptive_counter_backoff(cache->counter); return; success: - STAT_INC(COMPARE_AND_BRANCH, success); + STAT_INC(COMPARE_OP, success); cache->counter = adaptive_counter_cooldown(); } diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index c50ae42092bfd5..46987cc6a07ed2 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -645,23 +645,21 @@ break; } - TARGET(COMPARE_AND_BRANCH) { - STACK_SHRINK(2); - break; - } - - TARGET(COMPARE_AND_BRANCH_FLOAT) { - STACK_SHRINK(2); + TARGET(COMPARE_OP_FLOAT) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } - TARGET(COMPARE_AND_BRANCH_INT) { - STACK_SHRINK(2); + TARGET(COMPARE_OP_INT) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } - TARGET(COMPARE_AND_BRANCH_STR) { - STACK_SHRINK(2); + TARGET(COMPARE_OP_STR) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 14fc32a07b4309..9203c1888149fb 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -350,7 +350,6 @@ Python/pylifecycle.c - INTERPRETER_TRAMPOLINE_CODEDEF - Python/pystate.c - initial - Python/specialize.c - adaptive_opcodes - Python/specialize.c - cache_requirements - -Python/specialize.c - compare_masks - Python/stdlib_module_names.h - _Py_stdlib_module_names - Python/sysmodule.c - _PySys_ImplCacheTag - Python/sysmodule.c - _PySys_ImplName - diff --git a/Tools/scripts/summarize_stats.py b/Tools/scripts/summarize_stats.py index 7789c4d3a17d38..ce25374f3a9a52 100644 --- a/Tools/scripts/summarize_stats.py +++ b/Tools/scripts/summarize_stats.py @@ -228,8 +228,6 @@ def kind_to_text(kind, defines, opname): return pretty(defines[kind][0]) if opname.endswith("ATTR"): opname = "ATTR" - if opname in ("COMPARE_OP", "COMPARE_AND_BRANCH"): - opname = "COMPARE" if opname.endswith("SUBSCR"): opname = "SUBSCR" for name in defines[kind]: From 6f57d0a57c801e55a3de2275a1c58ceee12e07e3 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Thu, 23 Mar 2023 23:27:46 +0000 Subject: [PATCH 207/280] gh-99726: Fix order of recently added fields for FILE_STAT_BASIC_INFORMATION (GH-102976) --- Include/internal/pycore_fileutils_windows.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/internal/pycore_fileutils_windows.h b/Include/internal/pycore_fileutils_windows.h index 44874903b092f3..9bc7feb8cecd01 100644 --- a/Include/internal/pycore_fileutils_windows.h +++ b/Include/internal/pycore_fileutils_windows.h @@ -25,8 +25,8 @@ typedef struct _FILE_STAT_BASIC_INFORMATION { ULONG DeviceType; ULONG DeviceCharacteristics; ULONG Reserved; - FILE_ID_128 FileId128; LARGE_INTEGER VolumeSerialNumber; + FILE_ID_128 FileId128; } FILE_STAT_BASIC_INFORMATION; typedef enum _FILE_INFO_BY_NAME_CLASS { From a67d94ab040700a62d47ad6b9272e7f43a59e9fa Mon Sep 17 00:00:00 2001 From: MonadChains Date: Fri, 24 Mar 2023 00:42:43 +0100 Subject: [PATCH 208/280] gh-94684: uuid: support bytes in the name argument to uuid3/5 (#94709) RFC 4122 does not specify that name should be a string, so for completness the functions should also support a name given as a raw byte sequence. --- Doc/library/uuid.rst | 6 ++-- Lib/test/test_uuid.py | 34 +++++++++++++++++-- Lib/uuid.py | 8 +++-- ...2-07-09-13-07-30.gh-issue-94684.nV5yno.rst | 1 + 4 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-07-09-13-07-30.gh-issue-94684.nV5yno.rst diff --git a/Doc/library/uuid.rst b/Doc/library/uuid.rst index 38b6434f467fd6..94b9a432372195 100644 --- a/Doc/library/uuid.rst +++ b/Doc/library/uuid.rst @@ -186,7 +186,8 @@ The :mod:`uuid` module defines the following functions: .. function:: uuid3(namespace, name) Generate a UUID based on the MD5 hash of a namespace identifier (which is a - UUID) and a name (which is a string). + UUID) and a name (which is a :class:`bytes` object or a string + that will be encoded using UTF-8). .. index:: single: uuid3 @@ -201,7 +202,8 @@ The :mod:`uuid` module defines the following functions: .. function:: uuid5(namespace, name) Generate a UUID based on the SHA-1 hash of a namespace identifier (which is a - UUID) and a name (which is a string). + UUID) and a name (which is a :class:`bytes` object or a string + that will be encoded using UTF-8). .. index:: single: uuid5 diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index b2c229cd634e31..a178e942ecda0f 100755 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -600,7 +600,22 @@ def test_uuid1_time(self): def test_uuid3(self): equal = self.assertEqual - # Test some known version-3 UUIDs. + # Test some known version-3 UUIDs with name passed as a byte object + for u, v in [(self.uuid.uuid3(self.uuid.NAMESPACE_DNS, b'python.org'), + '6fa459ea-ee8a-3ca4-894e-db77e160355e'), + (self.uuid.uuid3(self.uuid.NAMESPACE_URL, b'http://python.org/'), + '9fe8e8c4-aaa8-32a9-a55c-4535a88b748d'), + (self.uuid.uuid3(self.uuid.NAMESPACE_OID, b'1.3.6.1'), + 'dd1a1cef-13d5-368a-ad82-eca71acd4cd1'), + (self.uuid.uuid3(self.uuid.NAMESPACE_X500, b'c=ca'), + '658d3002-db6b-3040-a1d1-8ddd7d189a4d'), + ]: + equal(u.variant, self.uuid.RFC_4122) + equal(u.version, 3) + equal(u, self.uuid.UUID(v)) + equal(str(u), v) + + # Test some known version-3 UUIDs with name passed as a string for u, v in [(self.uuid.uuid3(self.uuid.NAMESPACE_DNS, 'python.org'), '6fa459ea-ee8a-3ca4-894e-db77e160355e'), (self.uuid.uuid3(self.uuid.NAMESPACE_URL, 'http://python.org/'), @@ -632,7 +647,22 @@ def test_uuid4(self): def test_uuid5(self): equal = self.assertEqual - # Test some known version-5 UUIDs. + # Test some known version-5 UUIDs with names given as byte objects + for u, v in [(self.uuid.uuid5(self.uuid.NAMESPACE_DNS, b'python.org'), + '886313e1-3b8a-5372-9b90-0c9aee199e5d'), + (self.uuid.uuid5(self.uuid.NAMESPACE_URL, b'http://python.org/'), + '4c565f0d-3f5a-5890-b41b-20cf47701c5e'), + (self.uuid.uuid5(self.uuid.NAMESPACE_OID, b'1.3.6.1'), + '1447fa61-5277-5fef-a9b3-fbc6e44f4af3'), + (self.uuid.uuid5(self.uuid.NAMESPACE_X500, b'c=ca'), + 'cc957dd1-a972-5349-98cd-874190002798'), + ]: + equal(u.variant, self.uuid.RFC_4122) + equal(u.version, 5) + equal(u, self.uuid.UUID(v)) + equal(str(u), v) + + # Test some known version-5 UUIDs with names given as strings for u, v in [(self.uuid.uuid5(self.uuid.NAMESPACE_DNS, 'python.org'), '886313e1-3b8a-5372-9b90-0c9aee199e5d'), (self.uuid.uuid5(self.uuid.NAMESPACE_URL, 'http://python.org/'), diff --git a/Lib/uuid.py b/Lib/uuid.py index 1c5578bf1f05c2..698be34873b9dc 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -711,9 +711,11 @@ def uuid1(node=None, clock_seq=None): def uuid3(namespace, name): """Generate a UUID from the MD5 hash of a namespace UUID and a name.""" + if isinstance(name, str): + name = bytes(name, "utf-8") from hashlib import md5 digest = md5( - namespace.bytes + bytes(name, "utf-8"), + namespace.bytes + name, usedforsecurity=False ).digest() return UUID(bytes=digest[:16], version=3) @@ -724,8 +726,10 @@ def uuid4(): def uuid5(namespace, name): """Generate a UUID from the SHA-1 hash of a namespace UUID and a name.""" + if isinstance(name, str): + name = bytes(name, "utf-8") from hashlib import sha1 - hash = sha1(namespace.bytes + bytes(name, "utf-8")).digest() + hash = sha1(namespace.bytes + name).digest() return UUID(bytes=hash[:16], version=5) diff --git a/Misc/NEWS.d/next/Library/2022-07-09-13-07-30.gh-issue-94684.nV5yno.rst b/Misc/NEWS.d/next/Library/2022-07-09-13-07-30.gh-issue-94684.nV5yno.rst new file mode 100644 index 00000000000000..1fa38c0044d36f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-07-09-13-07-30.gh-issue-94684.nV5yno.rst @@ -0,0 +1 @@ +Now :func:`uuid.uuid3` and :func:`uuid.uuid5` functions support :class:`bytes` objects as their *name* argument. From c945040ee6f0bc9cc8a3f927028f4d6e1ddb2243 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Thu, 23 Mar 2023 19:50:17 -0500 Subject: [PATCH 209/280] GH-100989: Revert Improve the accuracy of collections.deque docstrings (GH-102979) --- Modules/_collectionsmodule.c | 37 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index ba4a9760f7b906..68131f3b54d2ea 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -910,9 +910,7 @@ deque_rotate(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(rotate_doc, -"rotate(n)\n\n" -"Rotate the deque *n* steps to the right (default ``n=1``). " -"If *n* is negative, rotates left."); +"Rotate the deque n steps to the right (default n=1). If n is negative, rotates left."); static PyObject * deque_reverse(dequeobject *deque, PyObject *unused) @@ -953,8 +951,7 @@ deque_reverse(dequeobject *deque, PyObject *unused) } PyDoc_STRVAR(reverse_doc, -"reverse()\n\n" -"Reverse the elements of the deque *IN PLACE*."); +"D.reverse() -- reverse *IN PLACE*"); static PyObject * deque_count(dequeobject *deque, PyObject *v) @@ -993,8 +990,7 @@ deque_count(dequeobject *deque, PyObject *v) } PyDoc_STRVAR(count_doc, -"count(x) -> int\n\n" -"Count the number of deque elements equal to *x*."); +"D.count(value) -> integer -- return number of occurrences of value"); static int deque_contains(dequeobject *deque, PyObject *v) @@ -1102,10 +1098,8 @@ deque_index(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(index_doc, -"index(x, [start, [stop]]) -> int\n\n" -"Return the position of *x* in the deque " -"(at or after index *start* and before index *stop*). " -"Returns the first match or raises a ValueError if not found."); +"D.index(value, [start, [stop]]) -> integer -- return first index of value.\n" +"Raises ValueError if the value is not present."); /* insert(), remove(), and delitem() are implemented in terms of rotate() for simplicity and reasonable performance near the end @@ -1150,13 +1144,10 @@ deque_insert(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(insert_doc, -"insert(i, x)\n\n" -"Insert *x* into the deque at position *i*."); +"D.insert(index, object) -- insert object before index"); PyDoc_STRVAR(remove_doc, -"remove(x)\n\n" -"Remove the first occurrence of *x*." -"If not found, raises a ValueError."); +"D.remove(value) -- remove first occurrence of value."); static int valid_index(Py_ssize_t i, Py_ssize_t limit) @@ -1527,8 +1518,7 @@ deque_sizeof(dequeobject *deque, void *unused) } PyDoc_STRVAR(sizeof_doc, -"__sizeof__() -> int\n\n" -"Size of the deque in memory, in bytes."); +"D.__sizeof__() -- size of D in memory, in bytes"); static PyObject * deque_get_maxlen(dequeobject *deque, void *Py_UNUSED(ignored)) @@ -1563,8 +1553,7 @@ static PySequenceMethods deque_as_sequence = { static PyObject *deque_iter(dequeobject *deque); static PyObject *deque_reviter(dequeobject *deque, PyObject *Py_UNUSED(ignored)); PyDoc_STRVAR(reversed_doc, -"__reversed__()\n\n" -"Return a reverse iterator over the deque."); + "D.__reversed__() -- return a reverse iterator over the deque"); static PyMethodDef deque_methods[] = { {"append", (PyCFunction)deque_append, @@ -1609,8 +1598,9 @@ static PyMethodDef deque_methods[] = { }; PyDoc_STRVAR(deque_doc, -"deque([iterable[, maxlen]]) -> collections.deque\n\n" -"A list-like sequence optimized for data accesses near its endpoints."); +"deque([iterable[, maxlen]]) --> deque object\n\ +\n\ +A list-like sequence optimized for data accesses near its endpoints."); static PyTypeObject deque_type = { PyVarObject_HEAD_INIT(NULL, 0) @@ -1989,8 +1979,7 @@ new_defdict(defdictobject *dd, PyObject *arg) dd->default_factory ? dd->default_factory : Py_None, arg, NULL); } -PyDoc_STRVAR(defdict_copy_doc, "copy() -> collections.deque\n\n" -"A shallow copy of the deque."); +PyDoc_STRVAR(defdict_copy_doc, "D.copy() -> a shallow copy of D."); static PyObject * defdict_copy(defdictobject *dd, PyObject *Py_UNUSED(ignored)) From de24df7a9abdb03326e1bd7a31237c56e6bf1605 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Fri, 24 Mar 2023 00:39:12 -0500 Subject: [PATCH 210/280] GH-100989: remove annotation from docstring (GH-102991) --- Modules/_collectionsmodule.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 68131f3b54d2ea..9d8aef1e677157 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -990,7 +990,7 @@ deque_count(dequeobject *deque, PyObject *v) } PyDoc_STRVAR(count_doc, -"D.count(value) -> integer -- return number of occurrences of value"); +"D.count(value) -- return number of occurrences of value"); static int deque_contains(dequeobject *deque, PyObject *v) @@ -1098,7 +1098,7 @@ deque_index(dequeobject *deque, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(index_doc, -"D.index(value, [start, [stop]]) -> integer -- return first index of value.\n" +"D.index(value, [start, [stop]]) -- return first index of value.\n" "Raises ValueError if the value is not present."); /* insert(), remove(), and delitem() are implemented in terms of From bf3bfdb41a5949ad1923969244d73e539205ba69 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Fri, 24 Mar 2023 13:23:35 +0200 Subject: [PATCH 211/280] gh-101100: Test docs in nit-picky mode (#102513) Co-authored-by: C.A.M. Gerlach Co-authored-by: Petr Viktorin --- .github/workflows/doc.yml | 22 ++++++++ Doc/c-api/exceptions.rst | 2 +- Doc/c-api/weakref.rst | 10 ++++ Doc/library/asyncio-task.rst | 7 +++ Doc/library/gzip.rst | 6 ++ Doc/tools/warnings-to-gh-actions.py | 25 ++++++++ Doc/whatsnew/3.12.rst | 88 ++++++++++++++--------------- Misc/NEWS.d/3.10.0a2.rst | 2 +- 8 files changed, 116 insertions(+), 46 deletions(-) create mode 100644 Doc/tools/warnings-to-gh-actions.py diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 465da12fa1be80..9ec60c198eb3b6 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -53,6 +53,28 @@ jobs: - name: 'Build HTML documentation' run: make -C Doc/ SPHINXOPTS="-q" SPHINXERRORHANDLING="-W --keep-going" html + # Add pull request annotations for Sphinx nitpicks (missing references) + - name: 'Get list of changed files' + id: changed_files + uses: Ana06/get-changed-files@v2.2.0 + - name: 'Build changed files in nit-picky mode' + continue-on-error: true + run: | + # Mark files the pull request modified + touch ${{ steps.changed_files.outputs.added_modified }} + # Build docs with the '-n' (nit-picky) option; convert warnings to annotations + make -C Doc/ PYTHON=../python SPHINXOPTS="-q -n --keep-going" html 2>&1 | + python Doc/tools/warnings-to-gh-actions.py + + # Ensure some files always pass Sphinx nit-picky mode (no missing references) + - name: 'Build known-good files in nit-picky mode' + run: | + # Mark files that must pass nit-picky + touch Doc/whatsnew/3.12.rst + touch Doc/library/sqlite3.rst + # Build docs with the '-n' (nit-picky) option, convert warnings to errors (-W) + make -C Doc/ PYTHON=../python SPHINXOPTS="-q -n -W --keep-going" html 2>&1 + # Run "doctest" on HEAD as new syntax doesn't exist in the latest stable release doctest: name: 'Doctest' diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index ddf7dc780b2745..49d2f18d4573b0 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -86,7 +86,7 @@ Printing and clearing An exception must be set when calling this function. -.. c:function: void PyErr_DisplayException(PyObject *exc) +.. c:function:: void PyErr_DisplayException(PyObject *exc) Print the standard traceback display of ``exc`` to ``sys.stderr``, including chained exceptions and notes. diff --git a/Doc/c-api/weakref.rst b/Doc/c-api/weakref.rst index ace743ba01c5f5..f27ec4411b4a26 100644 --- a/Doc/c-api/weakref.rst +++ b/Doc/c-api/weakref.rst @@ -67,3 +67,13 @@ as much as it can. .. c:function:: PyObject* PyWeakref_GET_OBJECT(PyObject *ref) Similar to :c:func:`PyWeakref_GetObject`, but does no error checking. + + +.. c:function:: void PyObject_ClearWeakRefs(PyObject *object) + + This function is called by the :c:member:`~PyTypeObject.tp_dealloc` handler + to clear weak references. + + This iterates through the weak references for *object* and calls callbacks + for those references which have one. It returns when all callbacks have + been attempted. diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index c5a480ba20190a..41d09e1e79705c 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -960,6 +960,13 @@ Introspection .. versionadded:: 3.7 +.. function:: iscoroutine(obj) + + Return ``True`` if *obj* is a coroutine object. + + .. versionadded:: 3.4 + + Task Object =========== diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst index 1a2582d6a904b2..06cbd2567a0bc6 100644 --- a/Doc/library/gzip.rst +++ b/Doc/library/gzip.rst @@ -143,6 +143,12 @@ The module defines the following items: :func:`time.time` and the :attr:`~os.stat_result.st_mtime` attribute of the object returned by :func:`os.stat`. + .. attribute:: name + + The path to the gzip file on disk, as a :class:`str` or :class:`bytes`. + Equivalent to the output of :func:`os.fspath` on the original input path, + with no other normalization, resolution or expansion. + .. versionchanged:: 3.1 Support for the :keyword:`with` statement was added, along with the *mtime* constructor argument and :attr:`mtime` attribute. diff --git a/Doc/tools/warnings-to-gh-actions.py b/Doc/tools/warnings-to-gh-actions.py new file mode 100644 index 00000000000000..da33a4ede07abc --- /dev/null +++ b/Doc/tools/warnings-to-gh-actions.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 + +""" +Convert Sphinx warning messages to GitHub Actions. + +Converts lines like: + .../Doc/library/cgi.rst:98: WARNING: reference target not found +to: + ::warning file=.../Doc/library/cgi.rst,line=98::reference target not found + +Non-matching lines are echoed unchanged. + +see: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-warning-message +""" + +import re +import sys + +pattern = re.compile(r'(?P[^:]+):(?P\d+): WARNING: (?P.+)') + +for line in sys.stdin: + if match := pattern.fullmatch(line.strip()): + print('::warning file={file},line={line}::{msg}'.format_map(match)) + else: + print(line) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 06ea416d751354..e5bcfdecd9a487 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -248,7 +248,7 @@ inspect ------- * Add :func:`inspect.markcoroutinefunction` to mark sync functions that return - a :term:`coroutine` for use with :func:`iscoroutinefunction`. + a :term:`coroutine` for use with :func:`inspect.iscoroutinefunction`. (Contributed Carlton Gibson in :gh:`99247`.) * Add :func:`inspect.getasyncgenstate` and :func:`inspect.getasyncgenlocals` @@ -277,7 +277,7 @@ dis * Pseudo instruction opcodes (which are used by the compiler but do not appear in executable bytecode) are now exposed in the :mod:`dis` module. - :data:`~dis.HAVE_ARGUMENT` is still relevant to real opcodes, + :opcode:`HAVE_ARGUMENT` is still relevant to real opcodes, but it is not useful for pseudo instructions. Use the new :data:`~dis.hasarg` collection instead. (Contributed by Irit Katriel in :gh:`94216`.) @@ -422,7 +422,7 @@ Optimizations (Contributed by Kevin Modzelewski in :gh:`90536`.) * Speed up the regular expression substitution (functions :func:`re.sub` and - :func:`re.subn` and corresponding :class:`re.Pattern` methods) for + :func:`re.subn` and corresponding :class:`!re.Pattern` methods) for replacement strings containing group references by 2--3 times. (Contributed by Serhiy Storchaka in :gh:`91524`.) @@ -435,7 +435,7 @@ CPython bytecode changes :opcode:`LOAD_METHOD` instruction if the low bit of its oparg is set. (Contributed by Ken Jin in :gh:`93429`.) -* Removed the :opcode:`JUMP_IF_FALSE_OR_POP` and :opcode:`JUMP_IF_TRUE_OR_POP` +* Removed the :opcode:`!JUMP_IF_FALSE_OR_POP` and :opcode:`!JUMP_IF_TRUE_OR_POP` instructions. (Contributed by Irit Katriel in :gh:`102859`.) @@ -482,7 +482,7 @@ Deprecated :exc:`ImportWarning`). (Contributed by Brett Cannon in :gh:`65961`.) -* The :meth:`~asyncio.DefaultEventLoopPolicy.get_event_loop` method of the +* The :meth:`~asyncio.get_event_loop` method of the default event loop policy now emits a :exc:`DeprecationWarning` if there is no current event loop set and it decides to create one. (Contributed by Serhiy Storchaka and Guido van Rossum in :gh:`100160`.) @@ -541,13 +541,13 @@ Modules (see :pep:`594`): APIs: -* :class:`configparser.LegacyInterpolation` (:gh:`90765`) +* :class:`!configparser.LegacyInterpolation` (:gh:`90765`) * :func:`locale.getdefaultlocale` (:gh:`90817`) -* :meth:`turtle.RawTurtle.settiltangle` (:gh:`50096`) -* :func:`unittest.findTestCases` (:gh:`50096`) -* :func:`unittest.makeSuite` (:gh:`50096`) -* :func:`unittest.getTestCaseNames` (:gh:`50096`) -* :class:`webbrowser.MacOSX` (:gh:`86421`) +* :meth:`!turtle.RawTurtle.settiltangle` (:gh:`50096`) +* :func:`!unittest.findTestCases` (:gh:`50096`) +* :func:`!unittest.makeSuite` (:gh:`50096`) +* :func:`!unittest.getTestCaseNames` (:gh:`50096`) +* :class:`!webbrowser.MacOSX` (:gh:`86421`) Pending Removal in Python 3.14 ------------------------------ @@ -555,9 +555,9 @@ Pending Removal in Python 3.14 * Deprecated the following :mod:`importlib.abc` classes, scheduled for removal in Python 3.14: - * :class:`importlib.abc.ResourceReader` - * :class:`importlib.abc.Traversable` - * :class:`importlib.abc.TraversableResources` + * :class:`!importlib.abc.ResourceReader` + * :class:`!importlib.abc.Traversable` + * :class:`!importlib.abc.TraversableResources` Use :mod:`importlib.resources.abc` classes instead: @@ -566,7 +566,7 @@ Pending Removal in Python 3.14 (Contributed by Jason R. Coombs and Hugo van Kemenade in :gh:`93963`.) -* Creating :c:data:`immutable types ` with mutable +* Creating immutable types (:data:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable bases using the C API. * Deprecated the *isdst* parameter in :func:`email.utils.localtime`. @@ -701,11 +701,11 @@ Removed * Remove ``io.OpenWrapper`` and ``_pyio.OpenWrapper``, deprecated in Python 3.10: just use :func:`open` instead. The :func:`open` (:func:`io.open`) - function is a built-in function. Since Python 3.10, :func:`_pyio.open` is + function is a built-in function. Since Python 3.10, :func:`!_pyio.open` is also a static method. (Contributed by Victor Stinner in :gh:`94169`.) -* Remove the :func:`ssl.RAND_pseudo_bytes` function, deprecated in Python 3.6: +* Remove the :func:`!ssl.RAND_pseudo_bytes` function, deprecated in Python 3.6: use :func:`os.urandom` or :func:`ssl.RAND_bytes` instead. (Contributed by Victor Stinner in :gh:`94199`.) @@ -715,13 +715,13 @@ Removed extension if it was not present. (Contributed by Victor Stinner in :gh:`94196`.) -* Remove the :func:`ssl.match_hostname` function. The - :func:`ssl.match_hostname` was deprecated in Python 3.7. OpenSSL performs +* Remove the :func:`!ssl.match_hostname` function. + It was deprecated in Python 3.7. OpenSSL performs hostname matching since Python 3.7, Python no longer uses the - :func:`ssl.match_hostname` function. + :func:`!ssl.match_hostname` function. (Contributed by Victor Stinner in :gh:`94199`.) -* Remove the :func:`locale.format` function, deprecated in Python 3.7: +* Remove the :func:`!locale.format` function, deprecated in Python 3.7: use :func:`locale.format_string` instead. (Contributed by Victor Stinner in :gh:`94226`.) @@ -731,9 +731,9 @@ Removed a C implementation of :func:`~hashlib.pbkdf2_hmac()` which is faster. (Contributed by Victor Stinner in :gh:`94199`.) -* :mod:`xml.etree`: Remove the ``ElementTree.Element.copy()`` method of the +* :mod:`xml.etree.ElementTree`: Remove the ``ElementTree.Element.copy()`` method of the pure Python implementation, deprecated in Python 3.10, use the - :func:`copy.copy` function instead. The C implementation of :mod:`xml.etree` + :func:`copy.copy` function instead. The C implementation of :mod:`xml.etree.ElementTree` has no ``copy()`` method, only a ``__copy__()`` method. (Contributed by Victor Stinner in :gh:`94383`.) @@ -742,10 +742,10 @@ Removed :pep:`451` for the rationale. (Contributed by Victor Stinner in :gh:`94379`.) -* Remove the :func:`ssl.wrap_socket` function, deprecated in Python 3.7: +* Remove the :func:`!ssl.wrap_socket` function, deprecated in Python 3.7: instead, create a :class:`ssl.SSLContext` object and call its :class:`ssl.SSLContext.wrap_socket` method. Any package that still uses - :func:`ssl.wrap_socket` is broken and insecure. The function neither sends a + :func:`!ssl.wrap_socket` is broken and insecure. The function neither sends a SNI TLS extension nor validates server hostname. Code is subject to `CWE-295 `_: Improper Certificate Validation. @@ -912,7 +912,7 @@ New Features The :const:`Py_TPFLAGS_HAVE_VECTORCALL` flag is now removed from a class when the class's :py:meth:`~object.__call__` method is reassigned. This makes vectorcall safe to use with mutable types (i.e. heap types - without the :const:`immutable ` flag). + without the immutable flag, :const:`Py_TPFLAGS_IMMUTABLETYPE`). Mutable types that do not override :c:member:`~PyTypeObject.tp_call` now inherit the ``Py_TPFLAGS_HAVE_VECTORCALL`` flag. (Contributed by Petr Viktorin in :gh:`93274`.) @@ -945,7 +945,7 @@ New Features (Contributed by Andrew Frost in :gh:`92257`.) * The C API now permits registering callbacks via :c:func:`PyDict_AddWatcher`, - :c:func:`PyDict_AddWatch` and related APIs to be called whenever a dictionary + :c:func:`PyDict_Watch` and related APIs to be called whenever a dictionary is modified. This is intended for use by optimizing interpreters, JIT compilers, or debuggers. (Contributed by Carl Meyer in :gh:`91052`.) @@ -977,7 +977,7 @@ New Features (Contributed by Mark Shannon in :gh:`101578`.) * Add :c:func:`PyErr_DisplayException`, which takes an exception instance, - to replace the legacy-api :c:func:`PyErr_Display`. (Contributed by + to replace the legacy-api :c:func:`!PyErr_Display`. (Contributed by Irit Katriel in :gh:`102755`). Porting to Python 3.12 @@ -1024,7 +1024,7 @@ Porting to Python 3.12 supported, but does not fully support multiple inheritance (:gh:`95589`), and performance may be worse. Classes declaring :const:`Py_TPFLAGS_MANAGED_DICT` should call - :c:func:`_PyObject_VisitManagedDict` and :c:func:`_PyObject_ClearManagedDict` + :c:func:`!_PyObject_VisitManagedDict` and :c:func:`!_PyObject_ClearManagedDict` to traverse and clear their instance's dictionaries. To clear weakrefs, call :c:func:`PyObject_ClearWeakRefs`, as before. @@ -1069,17 +1069,17 @@ Deprecated * :c:var:`Py_HashRandomizationFlag`: use :c:member:`PyConfig.use_hash_seed` and :c:member:`PyConfig.hash_seed` * :c:var:`Py_IsolatedFlag`: use :c:member:`PyConfig.isolated` - * :c:var:`Py_LegacyWindowsFSEncodingFlag`: use :c:member:`PyConfig.legacy_windows_fs_encoding` + * :c:var:`Py_LegacyWindowsFSEncodingFlag`: use :c:member:`PyPreConfig.legacy_windows_fs_encoding` * :c:var:`Py_LegacyWindowsStdioFlag`: use :c:member:`PyConfig.legacy_windows_stdio` - * :c:var:`Py_FileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` - * :c:var:`Py_FileSystemDefaultEncodeErrors`: use :c:member:`PyConfig.filesystem_errors` - * :c:var:`Py_UTF8Mode`: use :c:member:`PyPreConfig.utf8_mode` (see :c:func:`Py_PreInitialize`) + * :c:var:`!Py_FileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` + * :c:var:`!Py_FileSystemDefaultEncodeErrors`: use :c:member:`PyConfig.filesystem_errors` + * :c:var:`!Py_UTF8Mode`: use :c:member:`PyPreConfig.utf8_mode` (see :c:func:`Py_PreInitialize`) The :c:func:`Py_InitializeFromConfig` API should be used with :c:type:`PyConfig` instead. (Contributed by Victor Stinner in :gh:`77782`.) -* Creating :c:data:`immutable types ` with mutable +* Creating immutable types (:const:`Py_TPFLAGS_IMMUTABLETYPE`) with mutable bases is deprecated and will be disabled in Python 3.14. * The ``structmember.h`` header is deprecated, though it continues to be @@ -1118,7 +1118,7 @@ Deprecated :c:func:`PyErr_SetRaisedException` instead. (Contributed by Mark Shannon in :gh:`101578`.) -* :c:func:`PyErr_Display` is deprecated. Use :c:func:`PyErr_DisplayException` +* :c:func:`!PyErr_Display` is deprecated. Use :c:func:`PyErr_DisplayException` instead. (Contributed by Irit Katriel in :gh:`102755`). @@ -1132,15 +1132,15 @@ Removed * Legacy Unicode APIs have been removed. See :pep:`623` for detail. - * :c:macro:`PyUnicode_WCHAR_KIND` - * :c:func:`PyUnicode_AS_UNICODE` - * :c:func:`PyUnicode_AsUnicode` - * :c:func:`PyUnicode_AsUnicodeAndSize` - * :c:func:`PyUnicode_AS_DATA` - * :c:func:`PyUnicode_FromUnicode` - * :c:func:`PyUnicode_GET_SIZE` - * :c:func:`PyUnicode_GetSize` - * :c:func:`PyUnicode_GET_DATA_SIZE` + * :c:macro:`!PyUnicode_WCHAR_KIND` + * :c:func:`!PyUnicode_AS_UNICODE` + * :c:func:`!PyUnicode_AsUnicode` + * :c:func:`!PyUnicode_AsUnicodeAndSize` + * :c:func:`!PyUnicode_AS_DATA` + * :c:func:`!PyUnicode_FromUnicode` + * :c:func:`!PyUnicode_GET_SIZE` + * :c:func:`!PyUnicode_GetSize` + * :c:func:`!PyUnicode_GET_DATA_SIZE` * Remove the ``PyUnicode_InternImmortal()`` function and the ``SSTATE_INTERNED_IMMORTAL`` macro. diff --git a/Misc/NEWS.d/3.10.0a2.rst b/Misc/NEWS.d/3.10.0a2.rst index 61a291914f9333..061a82e90afd6b 100644 --- a/Misc/NEWS.d/3.10.0a2.rst +++ b/Misc/NEWS.d/3.10.0a2.rst @@ -888,7 +888,7 @@ file descriptors. .. nonce: JUPE59 .. section: C API -:c:data:`Py_FileSystemDefaultEncodeErrors` and :c:data:`Py_UTF8Mode` are +:c:data:`!Py_FileSystemDefaultEncodeErrors` and :c:data:`!Py_UTF8Mode` are available again in limited API. .. From 387cc117fe611bbe40353e0bad09f25f99265f05 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 24 Mar 2023 09:04:30 -0400 Subject: [PATCH 212/280] gh-100372: Use BIO_eof to detect EOF for SSL_FILETYPE_ASN1 (GH-100373) In PEM, we need to parse until error and then suppress `PEM_R_NO_START_LINE`, because PEM allows arbitrary leading and trailing data. DER, however, does not. Parsing until error and suppressing `ASN1_R_HEADER_TOO_LONG` doesn't quite work because that error also covers some cases that should be rejected. Instead, check `BIO_eof` early and stop the loop that way. Automerge-Triggered-By: GH:Yhg1s --- Lib/test/test_ssl.py | 2 ++ .../2022-12-20-10-55-14.gh-issue-100372.utfP65.rst | 2 ++ Modules/_ssl.c | 10 ++++++---- 3 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 1317efb33c2306..abf024fb89d2f3 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -1289,6 +1289,8 @@ def test_load_verify_cadata(self): "not enough data: cadata does not contain a certificate" ): ctx.load_verify_locations(cadata=b"broken") + with self.assertRaises(ssl.SSLError): + ctx.load_verify_locations(cadata=cacert_der + b"A") @unittest.skipIf(Py_DEBUG_WIN32, "Avoid mixing debug/release CRT on Windows") def test_load_dh_params(self): diff --git a/Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst b/Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst new file mode 100644 index 00000000000000..ec37aff5092c3a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-12-20-10-55-14.gh-issue-100372.utfP65.rst @@ -0,0 +1,2 @@ +:meth:`ssl.SSLContext.load_verify_locations` no longer incorrectly accepts +some cases of trailing data when parsing DER. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 36b66cdb5310c6..3fbb37332f67d3 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -3930,7 +3930,7 @@ _add_ca_certs(PySSLContext *self, const void *data, Py_ssize_t len, { BIO *biobuf = NULL; X509_STORE *store; - int retval = -1, err, loaded = 0; + int retval = -1, err, loaded = 0, was_bio_eof = 0; assert(filetype == SSL_FILETYPE_ASN1 || filetype == SSL_FILETYPE_PEM); @@ -3958,6 +3958,10 @@ _add_ca_certs(PySSLContext *self, const void *data, Py_ssize_t len, int r; if (filetype == SSL_FILETYPE_ASN1) { + if (BIO_eof(biobuf)) { + was_bio_eof = 1; + break; + } cert = d2i_X509_bio(biobuf, NULL); } else { cert = PEM_read_bio_X509(biobuf, NULL, @@ -3993,9 +3997,7 @@ _add_ca_certs(PySSLContext *self, const void *data, Py_ssize_t len, } _setSSLError(get_state_ctx(self), msg, 0, __FILE__, __LINE__); retval = -1; - } else if ((filetype == SSL_FILETYPE_ASN1) && - (ERR_GET_LIB(err) == ERR_LIB_ASN1) && - (ERR_GET_REASON(err) == ASN1_R_HEADER_TOO_LONG)) { + } else if ((filetype == SSL_FILETYPE_ASN1) && was_bio_eof) { /* EOF ASN1 file, not an error */ ERR_clear_error(); retval = 0; From a11fcbbdcda48eb1f32d50c16b10496b5102703c Mon Sep 17 00:00:00 2001 From: Amin Alaee Date: Fri, 24 Mar 2023 16:00:32 +0100 Subject: [PATCH 213/280] gh-102873: logging.LogRecord docs: improve description of `msg` parameter (#102875) Co-authored-by: Alex Waygood --- Doc/library/logging.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index 34e98fc2577003..22412e1a2113bb 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -813,8 +813,9 @@ wire). :type lineno: int :param msg: The event description message, - which can be a %-format string with placeholders for variable data. - :type msg: str + which can be a %-format string with placeholders for variable data, + or an arbitrary object (see :ref:`arbitrary-object-messages`). + :type msg: typing.Any :param args: Variable data to merge into the *msg* argument to obtain the event description. From 6b4ce012340ccc44395fa34450c56c0cb2009ea3 Mon Sep 17 00:00:00 2001 From: gaogaotiantian Date: Fri, 24 Mar 2023 13:50:06 -0700 Subject: [PATCH 214/280] gh-102980: Add tests for pdf's display, alias and where commands (#102981) --- Lib/test/test_pdb.py | 150 ++++++++++++++++++ ...-03-23-23-25-18.gh-issue-102980.Zps4QF.rst | 1 + 2 files changed, 151 insertions(+) create mode 100644 Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index d91bd0b2f03a0f..e96dc7fa1cf6e7 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -574,6 +574,156 @@ def test_pdb_whatis_command(): (Pdb) continue """ +def test_pdb_display_command(): + """Test display command + + >>> def test_function(): + ... a = 0 + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... a = 1 + ... a = 2 + ... a = 3 + ... a = 4 + + >>> with PdbTestInput([ # doctest: +ELLIPSIS + ... 'display a', + ... 'n', + ... 'display', + ... 'undisplay a', + ... 'n', + ... 'display a', + ... 'undisplay', + ... 'display a < 1', + ... 'n', + ... 'continue', + ... ]): + ... test_function() + > (4)test_function() + -> a = 1 + (Pdb) display a + display a: 0 + (Pdb) n + > (5)test_function() + -> a = 2 + display a: 1 [old: 0] + (Pdb) display + Currently displaying: + a: 1 + (Pdb) undisplay a + (Pdb) n + > (6)test_function() + -> a = 3 + (Pdb) display a + display a: 2 + (Pdb) undisplay + (Pdb) display a < 1 + display a < 1: False + (Pdb) n + > (7)test_function() + -> a = 4 + (Pdb) continue + """ + +def test_pdb_alias_command(): + """Test alias command + + >>> class A: + ... def __init__(self): + ... self.attr1 = 10 + ... self.attr2 = 'str' + ... def method(self): + ... pass + + >>> def test_function(): + ... o = A() + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... o.method() + + >>> with PdbTestInput([ # doctest: +ELLIPSIS + ... 'alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}")', + ... 'alias ps pi self', + ... 'pi o', + ... 's', + ... 'ps', + ... 'continue', + ... ]): + ... test_function() + > (4)test_function() + -> o.method() + (Pdb) alias pi for k in %1.__dict__.keys(): print(f"%1.{k} = {%1.__dict__[k]}") + (Pdb) alias ps pi self + (Pdb) pi o + o.attr1 = 10 + o.attr2 = str + (Pdb) s + --Call-- + > (5)method() + -> def method(self): + (Pdb) ps + self.attr1 = 10 + self.attr2 = str + (Pdb) continue + """ + +def test_pdb_where_command(): + """Test where command + + >>> def g(): + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + + >>> def f(): + ... g(); + + >>> def test_function(): + ... f() + + >>> with PdbTestInput([ # doctest: +ELLIPSIS + ... 'w', + ... 'where', + ... 'u', + ... 'w', + ... 'continue', + ... ]): + ... test_function() + --Return-- + > (2)g()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) w + ... + (8)() + -> test_function() + (2)test_function() + -> f() + (2)f() + -> g(); + > (2)g()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) where + ... + (8)() + -> test_function() + (2)test_function() + -> f() + (2)f() + -> g(); + > (2)g()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) u + > (2)f() + -> g(); + (Pdb) w + ... + (8)() + -> test_function() + (2)test_function() + -> f() + > (2)f() + -> g(); + (2)g()->None + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) continue + """ + def test_post_mortem(): """Test post mortem traceback debugging. diff --git a/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst b/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst new file mode 100644 index 00000000000000..48277367fc8755 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2023-03-23-23-25-18.gh-issue-102980.Zps4QF.rst @@ -0,0 +1 @@ +Improve test coverage on :mod:`pdb`. From 28122123faa9a027972978037aba9fc2e9a879b8 Mon Sep 17 00:00:00 2001 From: JakobDev Date: Fri, 24 Mar 2023 22:52:06 +0100 Subject: [PATCH 215/280] gh-100131: Add optional delete parameter to tempfile.TemporaryDirectory() (#100132) Add optional delete parameter to tempfile.TemporaryDirectory(). Co-authored-by: Gregory P. Smith --- Doc/library/tempfile.rst | 11 +++++++- Lib/tempfile.py | 25 +++++++++++++------ Lib/test/test_tempfile.py | 6 +++++ ...-12-09-11-21-38.gh-issue-100131.v863yR.rst | 1 + 4 files changed, 35 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst index b6d4f5dd05bbfc..61358eb76925b2 100644 --- a/Doc/library/tempfile.rst +++ b/Doc/library/tempfile.rst @@ -173,7 +173,7 @@ The module defines the following user-callable items: or text *mode* was specified). -.. class:: TemporaryDirectory(suffix=None, prefix=None, dir=None, ignore_cleanup_errors=False) +.. class:: TemporaryDirectory(suffix=None, prefix=None, dir=None, ignore_cleanup_errors=False, *, delete=True) This class securely creates a temporary directory using the same rules as :func:`mkdtemp`. The resulting object can be used as a context manager (see @@ -195,6 +195,12 @@ The module defines the following user-callable items: (the :func:`cleanup` call, exiting the context manager, when the object is garbage-collected or during interpreter shutdown). + The *delete* parameter can be used to disable cleanup of the directory tree + upon exiting the context. While it may seem unusual for a context manager + to disable the action taken when exiting the context, it can be useful during + debugging or when you need your cleanup behavior to be conditional based on + other logic. + .. audit-event:: tempfile.mkdtemp fullpath tempfile.TemporaryDirectory .. versionadded:: 3.2 @@ -202,6 +208,9 @@ The module defines the following user-callable items: .. versionchanged:: 3.10 Added *ignore_cleanup_errors* parameter. + .. versionchanged:: 3.12 + Added the *delete* parameter. + .. function:: mkstemp(suffix=None, prefix=None, dir=None, text=False) diff --git a/Lib/tempfile.py b/Lib/tempfile.py index cf06092f826bcc..4732eb0efe1f76 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -850,17 +850,26 @@ class TemporaryDirectory: ... Upon exiting the context, the directory and everything contained - in it are removed. + in it are removed (unless delete=False is passed or an exception + is raised during cleanup and ignore_cleanup_errors is not True). + + Optional Arguments: + suffix - A str suffix for the directory name. (see mkdtemp) + prefix - A str prefix for the directory name. (see mkdtemp) + dir - A directory to create this temp dir in. (see mkdtemp) + ignore_cleanup_errors - False; ignore exceptions during cleanup? + delete - True; whether the directory is automatically deleted. """ def __init__(self, suffix=None, prefix=None, dir=None, - ignore_cleanup_errors=False): + ignore_cleanup_errors=False, *, delete=True): self.name = mkdtemp(suffix, prefix, dir) self._ignore_cleanup_errors = ignore_cleanup_errors + self._delete = delete self._finalizer = _weakref.finalize( self, self._cleanup, self.name, warn_message="Implicitly cleaning up {!r}".format(self), - ignore_errors=self._ignore_cleanup_errors) + ignore_errors=self._ignore_cleanup_errors, delete=self._delete) @classmethod def _rmtree(cls, name, ignore_errors=False): @@ -894,9 +903,10 @@ def resetperms(path): _shutil.rmtree(name, onexc=onexc) @classmethod - def _cleanup(cls, name, warn_message, ignore_errors=False): - cls._rmtree(name, ignore_errors=ignore_errors) - _warnings.warn(warn_message, ResourceWarning) + def _cleanup(cls, name, warn_message, ignore_errors=False, delete=True): + if delete: + cls._rmtree(name, ignore_errors=ignore_errors) + _warnings.warn(warn_message, ResourceWarning) def __repr__(self): return "<{} {!r}>".format(self.__class__.__name__, self.name) @@ -905,7 +915,8 @@ def __enter__(self): return self.name def __exit__(self, exc, value, tb): - self.cleanup() + if self._delete: + self.cleanup() def cleanup(self): if self._finalizer.detach() or _os.path.exists(self.name): diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index 7c2c8de7a2e6fc..90155487cff585 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -12,6 +12,7 @@ import types import weakref import gc +import shutil from unittest import mock import unittest @@ -1837,6 +1838,11 @@ def test_flags(self): d.cleanup() self.assertFalse(os.path.exists(d.name)) + def test_delete_false(self): + with tempfile.TemporaryDirectory(delete=False) as working_dir: + pass + self.assertTrue(os.path.exists(working_dir)) + shutil.rmtree(working_dir) if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst b/Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst new file mode 100644 index 00000000000000..07891f2c1e9eb6 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst @@ -0,0 +1 @@ +Added an optional ``delete`` keyword argument to :class:`tempfile.TemporaryDirectory`. From 6f2c3f0e387a1ef0f4b8187f6d51f1b35490f29b Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sat, 25 Mar 2023 09:15:02 +0200 Subject: [PATCH 216/280] gh-101100: Test only Doc/ files in nit-picky mode (#103019) gh-101100: Filter only Doc/ files --- .github/workflows/doc.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 9ec60c198eb3b6..29387d30d5a22f 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -57,6 +57,8 @@ jobs: - name: 'Get list of changed files' id: changed_files uses: Ana06/get-changed-files@v2.2.0 + with: + filter: "Doc/**" - name: 'Build changed files in nit-picky mode' continue-on-error: true run: | From faaaabd6318504891b3294a96314233c1e7f15be Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sat, 25 Mar 2023 02:19:20 -0500 Subject: [PATCH 217/280] GH-102833: Mention the key function in the docstrings (GH-103009) --- Lib/bisect.py | 8 ++++++++ Modules/_bisectmodule.c | 16 ++++++++++++---- Modules/clinic/_bisectmodule.c.h | 18 +++++++++++++----- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/Lib/bisect.py b/Lib/bisect.py index d37da74f7b4055..ca6ca7240840bb 100644 --- a/Lib/bisect.py +++ b/Lib/bisect.py @@ -8,6 +8,8 @@ def insort_right(a, x, lo=0, hi=None, *, key=None): Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. + + A custom key function can be supplied to customize the sort order. """ if key is None: lo = bisect_right(a, x, lo, hi) @@ -25,6 +27,8 @@ def bisect_right(a, x, lo=0, hi=None, *, key=None): Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. + + A custom key function can be supplied to customize the sort order. """ if lo < 0: @@ -57,6 +61,8 @@ def insort_left(a, x, lo=0, hi=None, *, key=None): Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. + + A custom key function can be supplied to customize the sort order. """ if key is None: @@ -74,6 +80,8 @@ def bisect_left(a, x, lo=0, hi=None, *, key=None): Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. + + A custom key function can be supplied to customize the sort order. """ if lo < 0: diff --git a/Modules/_bisectmodule.c b/Modules/_bisectmodule.c index d3bec535ee512d..30801c2f87eee7 100644 --- a/Modules/_bisectmodule.c +++ b/Modules/_bisectmodule.c @@ -162,12 +162,14 @@ insert just after the rightmost x already there. Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. + +A custom key function can be supplied to customize the sort order. [clinic start generated code]*/ static Py_ssize_t _bisect_bisect_right_impl(PyObject *module, PyObject *a, PyObject *x, Py_ssize_t lo, Py_ssize_t hi, PyObject *key) -/*[clinic end generated code: output=3a4bc09cc7c8a73d input=40fcc5afa06ae593]*/ +/*[clinic end generated code: output=3a4bc09cc7c8a73d input=43071869772dd53a]*/ { return internal_bisect_right(a, x, lo, hi, key); } @@ -188,12 +190,14 @@ If x is already in a, insert it to the right of the rightmost x. Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. + +A custom key function can be supplied to customize the sort order. [clinic start generated code]*/ static PyObject * _bisect_insort_right_impl(PyObject *module, PyObject *a, PyObject *x, Py_ssize_t lo, Py_ssize_t hi, PyObject *key) -/*[clinic end generated code: output=ac3bf26d07aedda2 input=44e1708e26b7b802]*/ +/*[clinic end generated code: output=ac3bf26d07aedda2 input=f60777d2b6ddb239]*/ { PyObject *result, *key_x; Py_ssize_t index; @@ -343,12 +347,14 @@ insert just before the leftmost x already there. Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. + +A custom key function can be supplied to customize the sort order. [clinic start generated code]*/ static Py_ssize_t _bisect_bisect_left_impl(PyObject *module, PyObject *a, PyObject *x, Py_ssize_t lo, Py_ssize_t hi, PyObject *key) -/*[clinic end generated code: output=70749d6e5cae9284 input=90dd35b50ceb05e3]*/ +/*[clinic end generated code: output=70749d6e5cae9284 input=f29c4fe7f9b797c7]*/ { return internal_bisect_left(a, x, lo, hi, key); } @@ -370,12 +376,14 @@ If x is already in a, insert it to the left of the leftmost x. Optional args lo (default 0) and hi (default len(a)) bound the slice of a to be searched. + +A custom key function can be supplied to customize the sort order. [clinic start generated code]*/ static PyObject * _bisect_insort_left_impl(PyObject *module, PyObject *a, PyObject *x, Py_ssize_t lo, Py_ssize_t hi, PyObject *key) -/*[clinic end generated code: output=b1d33e5e7ffff11e input=3ab65d8784f585b1]*/ +/*[clinic end generated code: output=b1d33e5e7ffff11e input=0a700a82edbd472c]*/ { PyObject *result, *key_x; Py_ssize_t index; diff --git a/Modules/clinic/_bisectmodule.c.h b/Modules/clinic/_bisectmodule.c.h index bbf456e4b0f411..7944f5219b02a3 100644 --- a/Modules/clinic/_bisectmodule.c.h +++ b/Modules/clinic/_bisectmodule.c.h @@ -19,7 +19,9 @@ PyDoc_STRVAR(_bisect_bisect_right__doc__, "insert just after the rightmost x already there.\n" "\n" "Optional args lo (default 0) and hi (default len(a)) bound the\n" -"slice of a to be searched."); +"slice of a to be searched.\n" +"\n" +"A custom key function can be supplied to customize the sort order."); #define _BISECT_BISECT_RIGHT_METHODDEF \ {"bisect_right", _PyCFunction_CAST(_bisect_bisect_right), METH_FASTCALL|METH_KEYWORDS, _bisect_bisect_right__doc__}, @@ -125,7 +127,9 @@ PyDoc_STRVAR(_bisect_insort_right__doc__, "If x is already in a, insert it to the right of the rightmost x.\n" "\n" "Optional args lo (default 0) and hi (default len(a)) bound the\n" -"slice of a to be searched."); +"slice of a to be searched.\n" +"\n" +"A custom key function can be supplied to customize the sort order."); #define _BISECT_INSORT_RIGHT_METHODDEF \ {"insort_right", _PyCFunction_CAST(_bisect_insort_right), METH_FASTCALL|METH_KEYWORDS, _bisect_insort_right__doc__}, @@ -228,7 +232,9 @@ PyDoc_STRVAR(_bisect_bisect_left__doc__, "insert just before the leftmost x already there.\n" "\n" "Optional args lo (default 0) and hi (default len(a)) bound the\n" -"slice of a to be searched."); +"slice of a to be searched.\n" +"\n" +"A custom key function can be supplied to customize the sort order."); #define _BISECT_BISECT_LEFT_METHODDEF \ {"bisect_left", _PyCFunction_CAST(_bisect_bisect_left), METH_FASTCALL|METH_KEYWORDS, _bisect_bisect_left__doc__}, @@ -334,7 +340,9 @@ PyDoc_STRVAR(_bisect_insort_left__doc__, "If x is already in a, insert it to the left of the leftmost x.\n" "\n" "Optional args lo (default 0) and hi (default len(a)) bound the\n" -"slice of a to be searched."); +"slice of a to be searched.\n" +"\n" +"A custom key function can be supplied to customize the sort order."); #define _BISECT_INSORT_LEFT_METHODDEF \ {"insort_left", _PyCFunction_CAST(_bisect_insort_left), METH_FASTCALL|METH_KEYWORDS, _bisect_insort_left__doc__}, @@ -425,4 +433,4 @@ _bisect_insort_left(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P exit: return return_value; } -/*[clinic end generated code: output=7dc87f7af75275a1 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5a7fa64bf9b262f3 input=a9049054013a1b77]*/ From 537a413dbc28a3fb96ce3c923b52286145f32b5d Mon Sep 17 00:00:00 2001 From: Peter Jiping Xie Date: Sat, 25 Mar 2023 17:12:00 +0800 Subject: [PATCH 218/280] gh-103025: fix two ctypes doc issues (#103026) --- Doc/library/ctypes.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 8fd681286b812d..d49d702e9e7999 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -375,8 +375,8 @@ that they can be converted to the required C data type:: .. _ctypes-calling-variadic-functions: -Calling varadic functions -^^^^^^^^^^^^^^^^^^^^^^^^^ +Calling variadic functions +^^^^^^^^^^^^^^^^^^^^^^^^^^ On a lot of platforms calling variadic functions through ctypes is exactly the same as calling functions with a fixed number of parameters. On some platforms, and in @@ -508,7 +508,7 @@ a string pointer and a char, and returns a pointer to a string:: If you want to avoid the ``ord("x")`` calls above, you can set the :attr:`argtypes` attribute, and the second argument will be converted from a -single character Python bytes object into a C char:: +single character Python bytes object into a C char: .. doctest:: From a61efbe930ac8317f14c42c242cf54b33eec2050 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Sat, 25 Mar 2023 22:36:38 +0300 Subject: [PATCH 219/280] gh-103027: Update `dataclass.make_dataclass` docstring (gh-103028) * gh-103027: Update `dataclass.make_dataclass` docstring --- Lib/dataclasses.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index e3fd0b3e380dd8..0e04469be3ca32 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1421,8 +1421,11 @@ class C(Base): For the bases and namespace parameters, see the builtin type() function. - The parameters init, repr, eq, order, unsafe_hash, and frozen are passed to - dataclass(). + The parameters init, repr, eq, order, unsafe_hash, frozen, match_args, kw_only, + slots, and weakref_slot are passed to dataclass(). + + If module parameter is defined, the '__module__' attribute of the dataclass is + set to that value. """ if namespace is None: From 86bc7345edfdc7908d525abdbabe4c9982517212 Mon Sep 17 00:00:00 2001 From: Liyang Zhang Date: Sat, 25 Mar 2023 16:27:02 -0500 Subject: [PATCH 220/280] Fix typos in faulthandler, testcapi error messages (#103020) --- Modules/_testcapi/heaptype.c | 4 ++-- Modules/faulthandler.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/_testcapi/heaptype.c b/Modules/_testcapi/heaptype.c index df2a061ed82b06..209cc182c0698d 100644 --- a/Modules/_testcapi/heaptype.c +++ b/Modules/_testcapi/heaptype.c @@ -174,7 +174,7 @@ test_from_spec_invalid_metatype_inheritance(PyObject *self, PyObject *Py_UNUSED( } if (res == 0) { PyErr_SetString(PyExc_AssertionError, - "TypeError did not inlclude expected message."); + "TypeError did not include expected message."); goto finally; } result = Py_NewRef(Py_None); @@ -265,7 +265,7 @@ test_type_from_ephemeral_spec(PyObject *self, PyObject *Py_UNUSED(ignored)) /* deallocate the spec (and all contents) */ - // (Explicitly ovewrite memory before freeing, + // (Explicitly overwrite memory before freeing, // so bugs show themselves even without the debug allocator's help.) memset(spec, 0xdd, sizeof(PyType_Spec)); PyMem_Del(spec); diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index bfe35fed7a450a..9b4e4199cdc20a 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -120,7 +120,7 @@ faulthandler_get_fileno(PyObject **file_ptr) return -1; if (fd < 0) { PyErr_SetString(PyExc_ValueError, - "file is not a valid file descripter"); + "file is not a valid file descriptor"); return -1; } *file_ptr = NULL; From 6f15ebd44e5b17a3b6de9533b853089c5657083e Mon Sep 17 00:00:00 2001 From: gaogaotiantian Date: Sat, 25 Mar 2023 14:31:45 -0700 Subject: [PATCH 221/280] Update pdb docs for arguments (#102965) --- Doc/library/pdb.rst | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 5988477af03abd..d80c5eebbf27a7 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -125,7 +125,7 @@ slightly different way: Evaluate the *expression* (given as a string or a code object) under debugger control. When :func:`runeval` returns, it returns the value of the - expression. Otherwise this function is similar to :func:`run`. + *expression*. Otherwise this function is similar to :func:`run`. .. function:: runcall(function, *args, **kwds) @@ -178,7 +178,7 @@ access further features, you have to do this yourself: that matches one of these patterns. [1]_ By default, Pdb sets a handler for the SIGINT signal (which is sent when the - user presses :kbd:`Ctrl-C` on the console) when you give a ``continue`` command. + user presses :kbd:`Ctrl-C` on the console) when you give a :pdbcmd:`continue` command. This allows you to break into the debugger again by pressing :kbd:`Ctrl-C`. If you want Pdb not to touch the SIGINT handler, set *nosigint* to true. @@ -328,9 +328,9 @@ can be overridden by the local file. .. pdbcommand:: ignore bpnumber [count] - Set the ignore count for the given breakpoint number. If count is omitted, + Set the ignore count for the given breakpoint number. If *count* is omitted, the ignore count is set to 0. A breakpoint becomes active when the ignore - count is zero. When non-zero, the count is decremented each time the + count is zero. When non-zero, the *count* is decremented each time the breakpoint is reached and the breakpoint is not disabled and any associated condition evaluates to true. @@ -369,7 +369,7 @@ can be overridden by the local file. breakpoint—which could have its own command list, leading to ambiguities about which list to execute. - If you use the 'silent' command in the command list, the usual message about + If you use the ``silent`` command in the command list, the usual message about stopping at a breakpoint is not printed. This may be desirable for breakpoints that are to print a specific message and then continue. If none of the other commands print anything, you see no sign that the breakpoint was reached. @@ -392,8 +392,8 @@ can be overridden by the local file. Without argument, continue execution until the line with a number greater than the current one is reached. - With a line number, continue execution until a line with a number greater or - equal to that is reached. In both cases, also stop when the current frame + With *lineno*, continue execution until a line with a number greater or + equal to *lineno* is reached. In both cases, also stop when the current frame returns. .. versionchanged:: 3.2 @@ -446,7 +446,7 @@ can be overridden by the local file. .. pdbcommand:: p expression - Evaluate the *expression* in the current context and print its value. + Evaluate *expression* in the current context and print its value. .. note:: @@ -456,32 +456,32 @@ can be overridden by the local file. .. pdbcommand:: pp expression - Like the :pdbcmd:`p` command, except the value of the expression is + Like the :pdbcmd:`p` command, except the value of *expression* is pretty-printed using the :mod:`pprint` module. .. pdbcommand:: whatis expression - Print the type of the *expression*. + Print the type of *expression*. .. pdbcommand:: source expression - Try to get source code for the given object and display it. + Try to get source code of *expression* and display it. .. versionadded:: 3.2 .. pdbcommand:: display [expression] - Display the value of the expression if it changed, each time execution stops + Display the value of *expression* if it changed, each time execution stops in the current frame. - Without expression, list all display expressions for the current frame. + Without *expression*, list all display expressions for the current frame. .. versionadded:: 3.2 .. pdbcommand:: undisplay [expression] - Do not display the expression any more in the current frame. Without - expression, clear all display expressions for the current frame. + Do not display *expression* anymore in the current frame. Without + *expression*, clear all display expressions for the current frame. .. versionadded:: 3.2 @@ -497,10 +497,10 @@ can be overridden by the local file. .. pdbcommand:: alias [name [command]] - Create an alias called *name* that executes *command*. The command must + Create an alias called *name* that executes *command*. The *command* must *not* be enclosed in quotes. Replaceable parameters can be indicated by ``%1``, ``%2``, and so on, while ``%*`` is replaced by all the parameters. - If no command is given, the current alias for *name* is shown. If no + If *command* is omitted, the current alias for *name* is shown. If no arguments are given, all aliases are listed. Aliases may be nested and can contain anything that can be legally typed at @@ -519,7 +519,7 @@ can be overridden by the local file. .. pdbcommand:: unalias name - Delete the specified alias. + Delete the specified alias *name*. .. pdbcommand:: ! statement @@ -535,7 +535,7 @@ can be overridden by the local file. .. pdbcommand:: run [args ...] restart [args ...] - Restart the debugged Python program. If an argument is supplied, it is split + Restart the debugged Python program. If *args* is supplied, it is split with :mod:`shlex` and the result is used as the new :data:`sys.argv`. History, breakpoints, actions and debugger options are preserved. :pdbcmd:`restart` is an alias for :pdbcmd:`run`. @@ -546,8 +546,8 @@ can be overridden by the local file. .. pdbcommand:: debug code - Enter a recursive debugger that steps through the code - argument (which is an arbitrary expression or statement to be + Enter a recursive debugger that steps through *code* + (which is an arbitrary expression or statement to be executed in the current environment). .. pdbcommand:: retval From 8e4f648fed57233b86ba3b3878fd9c0cc1f82d2a Mon Sep 17 00:00:00 2001 From: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Date: Sat, 25 Mar 2023 14:40:11 -0700 Subject: [PATCH 222/280] gh-98886: Fix issues with dataclass fields with special underscore names (#102032) This commit prefixes `__dataclass` to several things in the locals dict: - Names like `_dflt_` (which cause trouble, see first test) - Names like `_type_` (not known to be able to cause trouble) - `_return_type` (not known to able to cause trouble) - `_HAS_DEFAULT_FACTORY` (which causes trouble, see second test) In addition, this removes `MISSING` from the locals dict. As far as I can tell, this wasn't needed even in the initial implementation of dataclasses.py (and tests on that version passed with it removed). This makes me wary :-) This is basically a continuation of #96151, where fixing this was welcomed in https://github.com/python/cpython/pull/98143#issuecomment-1280306360 --- Lib/dataclasses.py | 19 +++++++++---------- Lib/test/test_dataclasses.py | 17 +++++++++++++++++ ...3-02-18-23-03-50.gh-issue-98886.LkKGWv.rst | 1 + 3 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-02-18-23-03-50.gh-issue-98886.LkKGWv.rst diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 0e04469be3ca32..7558287bad449e 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -432,8 +432,8 @@ def _create_fn(name, args, body, *, globals=None, locals=None, locals = {} return_annotation = '' if return_type is not MISSING: - locals['_return_type'] = return_type - return_annotation = '->_return_type' + locals['__dataclass_return_type__'] = return_type + return_annotation = '->__dataclass_return_type__' args = ','.join(args) body = '\n'.join(f' {b}' for b in body) @@ -467,14 +467,14 @@ def _field_init(f, frozen, globals, self_name, slots): # Return the text of the line in the body of __init__ that will # initialize this field. - default_name = f'_dflt_{f.name}' + default_name = f'__dataclass_dflt_{f.name}__' if f.default_factory is not MISSING: if f.init: # This field has a default factory. If a parameter is # given, use it. If not, call the factory. globals[default_name] = f.default_factory value = (f'{default_name}() ' - f'if {f.name} is _HAS_DEFAULT_FACTORY ' + f'if {f.name} is __dataclass_HAS_DEFAULT_FACTORY__ ' f'else {f.name}') else: # This is a field that's not in the __init__ params, but @@ -535,11 +535,11 @@ def _init_param(f): elif f.default is not MISSING: # There's a default, this will be the name that's used to look # it up. - default = f'=_dflt_{f.name}' + default = f'=__dataclass_dflt_{f.name}__' elif f.default_factory is not MISSING: # There's a factory function. Set a marker. - default = '=_HAS_DEFAULT_FACTORY' - return f'{f.name}:_type_{f.name}{default}' + default = '=__dataclass_HAS_DEFAULT_FACTORY__' + return f'{f.name}:__dataclass_type_{f.name}__{default}' def _init_fn(fields, std_fields, kw_only_fields, frozen, has_post_init, @@ -562,10 +562,9 @@ def _init_fn(fields, std_fields, kw_only_fields, frozen, has_post_init, raise TypeError(f'non-default argument {f.name!r} ' 'follows default argument') - locals = {f'_type_{f.name}': f.type for f in fields} + locals = {f'__dataclass_type_{f.name}__': f.type for f in fields} locals.update({ - 'MISSING': MISSING, - '_HAS_DEFAULT_FACTORY': _HAS_DEFAULT_FACTORY, + '__dataclass_HAS_DEFAULT_FACTORY__': _HAS_DEFAULT_FACTORY, '__dataclass_builtins_object__': object, }) diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index affd9cede19c99..6888680105c4fd 100644 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -285,6 +285,23 @@ class C: c = C(5) self.assertEqual(c.BUILTINS, 5) + def test_field_with_special_single_underscore_names(self): + # gh-98886 + + @dataclass + class X: + x: int = field(default_factory=lambda: 111) + _dflt_x: int = field(default_factory=lambda: 222) + + X() + + @dataclass + class Y: + y: int = field(default_factory=lambda: 111) + _HAS_DEFAULT_FACTORY: int = 222 + + assert Y(y=222).y == 222 + def test_field_named_like_builtin(self): # Attribute names can shadow built-in names # since code generation is used. diff --git a/Misc/NEWS.d/next/Library/2023-02-18-23-03-50.gh-issue-98886.LkKGWv.rst b/Misc/NEWS.d/next/Library/2023-02-18-23-03-50.gh-issue-98886.LkKGWv.rst new file mode 100644 index 00000000000000..64e4d6eed2f62d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-18-23-03-50.gh-issue-98886.LkKGWv.rst @@ -0,0 +1 @@ +Fix issues when defining dataclasses that have fields with specific underscore names that aren't clearly reserved by :mod:`dataclasses`. From 0831f21f2717317d71b7d6a1079ddd4f72cff161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20G=C3=B6rgens?= Date: Sun, 26 Mar 2023 07:38:24 +0800 Subject: [PATCH 223/280] Fix typo in _swappedbytes_ in ctypes comment (#102773) It's a minor typo, but it makes for a misleading comment. Let's fix it. --- Lib/ctypes/_endian.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/ctypes/_endian.py b/Lib/ctypes/_endian.py index 34dee64b1a65a6..b5446c049bc9dc 100644 --- a/Lib/ctypes/_endian.py +++ b/Lib/ctypes/_endian.py @@ -37,7 +37,7 @@ class _swapped_union_meta(_swapped_meta, type(Union)): pass ################################################################ # Note: The Structure metaclass checks for the *presence* (not the -# value!) of a _swapped_bytes_ attribute to determine the bit order in +# value!) of a _swappedbytes_ attribute to determine the bit order in # structures containing bit fields. if sys.byteorder == "little": From 0f312ec8af4132d422081f91215043d2352af72a Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Mon, 27 Mar 2023 03:05:06 +0300 Subject: [PATCH 224/280] =?UTF-8?q?gh-102941:=20Fix=20"=E2=80=98subobj?= =?UTF-8?q?=E2=80=99=20may=20be=20used=20uninitialized=20in=20this=20funct?= =?UTF-8?q?ion"=20warning=20in=20`bytes=5Fmethods.c`=20(#102942)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Objects/bytes_methods.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/bytes_methods.c b/Objects/bytes_methods.c index 6b8166385d375b..ef9e65e566ece9 100644 --- a/Objects/bytes_methods.c +++ b/Objects/bytes_methods.c @@ -774,7 +774,7 @@ _Py_bytes_tailmatch(const char *str, Py_ssize_t len, { Py_ssize_t start = 0; Py_ssize_t end = PY_SSIZE_T_MAX; - PyObject *subobj; + PyObject *subobj = NULL; int result; if (!stringlib_parse_args_finds(function_name, args, &subobj, &start, &end)) From c4306ba7fd60506afb8cb007cc3c35d3f85f3af0 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 27 Mar 2023 20:25:29 +0800 Subject: [PATCH 225/280] Finish merge --- Include/internal/pycore_code.h | 1 - Include/internal/pycore_opcode.h | 6 +- Include/opcode.h | 36 +++--- Lib/opcode.py | 3 - Python/bytecodes.c | 12 +- Python/ceval.c | 5 - Python/generated_cases.c.h | 12 +- Python/tier2.c | 33 +----- Tools/cases_generator/generate_cases.py | 143 ++++++++++++++++++++++++ 9 files changed, 176 insertions(+), 75 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 3586c292117459..143199a4a1bb5b 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -265,7 +265,6 @@ extern _Py_CODEUNIT *_PyTier2_GenerateNextBB( _Py_CODEUNIT *curr_executing_instr, int jumpby, _Py_CODEUNIT **tier1_fallback, - char gen_bb_requires_pop, char gen_bb_is_successor); extern _Py_CODEUNIT *_PyTier2_LocateJumpBackwardsBB( struct _PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 9884184df4d3d8..155f8461021686 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -412,8 +412,6 @@ static const char *const _PyOpcode_OpName[263] = { [BB_JUMP_IF_FLAG_UNSET] = "BB_JUMP_IF_FLAG_UNSET", [BB_JUMP_IF_FLAG_SET] = "BB_JUMP_IF_FLAG_SET", [BB_TEST_ITER] = "BB_TEST_ITER", - [BB_TEST_IF_FALSE_OR_POP] = "BB_TEST_IF_FALSE_OR_POP", - [BB_TEST_IF_TRUE_OR_POP] = "BB_TEST_IF_TRUE_OR_POP", [BB_TEST_POP_IF_FALSE] = "BB_TEST_POP_IF_FALSE", [BB_TEST_POP_IF_TRUE] = "BB_TEST_POP_IF_TRUE", [BB_TEST_POP_IF_NOT_NONE] = "BB_TEST_POP_IF_NOT_NONE", @@ -431,6 +429,8 @@ static const char *const _PyOpcode_OpName[263] = { [STORE_FAST_BOXED_UNBOXED] = "STORE_FAST_BOXED_UNBOXED", [STORE_FAST_UNBOXED_BOXED] = "STORE_FAST_UNBOXED_BOXED", [STORE_FAST_UNBOXED_UNBOXED] = "STORE_FAST_UNBOXED_UNBOXED", + [196] = "<196>", + [197] = "<197>", [198] = "<198>", [199] = "<199>", [200] = "<200>", @@ -501,6 +501,8 @@ static const char *const _PyOpcode_OpName[263] = { #define EXTRA_CASES \ + case 196: \ + case 197: \ case 198: \ case 199: \ case 200: \ diff --git a/Include/opcode.h b/Include/opcode.h index ae70a273f41573..6ae5375ed0dadc 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -268,25 +268,23 @@ extern "C" { #define BB_JUMP_IF_FLAG_UNSET 176 #define BB_JUMP_IF_FLAG_SET 177 #define BB_TEST_ITER 178 -#define BB_TEST_IF_FALSE_OR_POP 179 -#define BB_TEST_IF_TRUE_OR_POP 180 -#define BB_TEST_POP_IF_FALSE 181 -#define BB_TEST_POP_IF_TRUE 182 -#define BB_TEST_POP_IF_NOT_NONE 183 -#define BB_TEST_POP_IF_NONE 184 -#define BB_JUMP_BACKWARD_LAZY 185 -#define BINARY_CHECK_INT 186 -#define BINARY_CHECK_FLOAT 187 -#define UNARY_CHECK_FLOAT 188 -#define BINARY_OP_ADD_INT_REST 189 -#define BINARY_OP_ADD_FLOAT_UNBOXED 190 -#define POP_TOP_NO_DECREF 191 -#define UNBOX_FLOAT 192 -#define BOX_FLOAT 193 -#define LOAD_FAST_NO_INCREF 194 -#define STORE_FAST_BOXED_UNBOXED 195 -#define STORE_FAST_UNBOXED_BOXED 196 -#define STORE_FAST_UNBOXED_UNBOXED 197 +#define BB_TEST_POP_IF_FALSE 179 +#define BB_TEST_POP_IF_TRUE 180 +#define BB_TEST_POP_IF_NOT_NONE 181 +#define BB_TEST_POP_IF_NONE 182 +#define BB_JUMP_BACKWARD_LAZY 183 +#define BINARY_CHECK_INT 184 +#define BINARY_CHECK_FLOAT 185 +#define UNARY_CHECK_FLOAT 186 +#define BINARY_OP_ADD_INT_REST 187 +#define BINARY_OP_ADD_FLOAT_UNBOXED 188 +#define POP_TOP_NO_DECREF 189 +#define UNBOX_FLOAT 190 +#define BOX_FLOAT 191 +#define LOAD_FAST_NO_INCREF 192 +#define STORE_FAST_BOXED_UNBOXED 193 +#define STORE_FAST_UNBOXED_BOXED 194 +#define STORE_FAST_UNBOXED_UNBOXED 195 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/opcode.py b/Lib/opcode.py index fba7f76cc279b7..5277f47b457262 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -465,9 +465,6 @@ def pseudo_op(name, op, real_ops): # These tests correspond to the jump instructions # FOR_ITER's null (iterator) check 'BB_TEST_ITER', - # JUMP_IF_FALSE_OR_POP, JUMP_IF_TRUE_OR_POP - 'BB_TEST_IF_FALSE_OR_POP', - 'BB_TEST_IF_TRUE_OR_POP', # POP_JUMP_IF_FALSE, POP_JUMP_IF_TRUE 'BB_TEST_POP_IF_FALSE', 'BB_TEST_POP_IF_TRUE', diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 55ef034c9a9ff8..e974186853211e 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3166,8 +3166,7 @@ dummy_func( // Generate consequent. t2_nextinstr = _PyTier2_GenerateNextBB( frame, cache->bb_id_tagged, next_instr - 1, - 0, &tier1_fallback, gen_bb_requires_pop, bb_test); - gen_bb_requires_pop = false; + 0, &tier1_fallback, bb_test); if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; @@ -3180,8 +3179,7 @@ dummy_func( // Generate alternative. t2_nextinstr = _PyTier2_GenerateNextBB( frame, cache->bb_id_tagged, next_instr - 1, - oparg, &tier1_fallback, gen_bb_requires_pop, bb_test); - gen_bb_requires_pop = false; + oparg, &tier1_fallback, bb_test); if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback + oparg; @@ -3204,8 +3202,7 @@ dummy_func( t2_nextinstr = _PyTier2_GenerateNextBB( frame, cache->bb_id_tagged, next_instr - 1, - oparg, &tier1_fallback, gen_bb_requires_pop, bb_test); - gen_bb_requires_pop = false; + oparg, &tier1_fallback, bb_test); if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; @@ -3237,8 +3234,7 @@ dummy_func( t2_nextinstr = _PyTier2_GenerateNextBB( frame, cache->bb_id_tagged, next_instr - 1, - oparg, &tier1_fallback, gen_bb_requires_pop, bb_test); - gen_bb_requires_pop = false; + oparg, &tier1_fallback, bb_test); if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; diff --git a/Python/ceval.c b/Python/ceval.c index 9d7c6e058cf8e5..87d36f7cd14e16 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -727,11 +727,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int // true = successor // false = alternate char bb_test = true; - // For tier2 type propagation, handling of jump instructions with - // runtime-dependent stack effect. - // This flag is used to determine if the type context of a new bb - // requires a stack element to be popped. - char gen_bb_requires_pop = false; /* WARNING: Because the _PyCFrame lives on the C stack, * but can be accessed from a heap allocated object (tstate) diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 158116daaaddc4..a7c708a1a374be 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -4033,8 +4033,7 @@ // Generate consequent. t2_nextinstr = _PyTier2_GenerateNextBB( frame, cache->bb_id_tagged, next_instr - 1, - 0, &tier1_fallback, gen_bb_requires_pop, bb_test); - gen_bb_requires_pop = false; + 0, &tier1_fallback, bb_test); if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; @@ -4047,8 +4046,7 @@ // Generate alternative. t2_nextinstr = _PyTier2_GenerateNextBB( frame, cache->bb_id_tagged, next_instr - 1, - oparg, &tier1_fallback, gen_bb_requires_pop, bb_test); - gen_bb_requires_pop = false; + oparg, &tier1_fallback, bb_test); if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback + oparg; @@ -4071,8 +4069,7 @@ t2_nextinstr = _PyTier2_GenerateNextBB( frame, cache->bb_id_tagged, next_instr - 1, - oparg, &tier1_fallback, gen_bb_requires_pop, bb_test); - gen_bb_requires_pop = false; + oparg, &tier1_fallback, bb_test); if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; @@ -4108,8 +4105,7 @@ t2_nextinstr = _PyTier2_GenerateNextBB( frame, cache->bb_id_tagged, next_instr - 1, - oparg, &tier1_fallback, gen_bb_requires_pop, bb_test); - gen_bb_requires_pop = false; + oparg, &tier1_fallback, bb_test); if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; diff --git a/Python/tier2.c b/Python/tier2.c index fb04660cea3f05..a2d468b12b2ec0 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -682,9 +682,7 @@ IS_JREL_OPCODE(int opcode) switch (opcode) { case FOR_ITER: case JUMP_FORWARD: - case JUMP_IF_FALSE_OR_POP: - case JUMP_IF_TRUE_OR_POP: - // These two tend to be after a COMPARE_AND_BRANCH. + // These two tend to be after a COMPARE_OP case POP_JUMP_IF_FALSE: case POP_JUMP_IF_TRUE: case SEND: @@ -720,7 +718,7 @@ IS_JUMP_OPCODE(int opcode) static inline int IS_COMPARE_OPCODE(int opcode) { - return opcode == COMPARE_OP || opcode == COMPARE_AND_BRANCH; + return opcode == COMPARE_OP; } static inline int @@ -878,9 +876,9 @@ emit_type_guard(_Py_CODEUNIT *write_curr, int guard_opcode, int bb_id) // Converts the tier 1 branch bytecode to tier 2 branch bytecode. // This converts sequence of instructions like -// JUMP_IF_FALSE_OR_POP +// POP_JUMP_IF_FALSE // to -// BB_TEST_IF_FALSE_OR_POP +// BB_TEST_POP_IF_FALSE // BB_BRANCH // CACHE (bb_id of the current BB << 1 | is_type_branch) static inline _Py_CODEUNIT * @@ -903,16 +901,6 @@ emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, opcode = BB_TEST_ITER; type_propagate(opcode, oparg, type_context, NULL); break; - case JUMP_IF_FALSE_OR_POP: - opcode = BB_TEST_IF_FALSE_OR_POP; - // This inst has conditional stack effect according to whether the branch is taken. - // This inst sets the `gen_bb_requires_pop` flag to handle stack effect of this opcode in BB_BRANCH - break; - case JUMP_IF_TRUE_OR_POP: - opcode = BB_TEST_IF_TRUE_OR_POP; - // This inst has conditional stack effect according to whether the branch is taken. - // This inst sets the `gen_bb_requires_pop` flag to handle stack effect of this opcode in BB_BRANCH - break; case POP_JUMP_IF_FALSE: opcode = BB_TEST_POP_IF_FALSE; type_propagate(opcode, oparg, type_context, NULL); @@ -1241,9 +1229,6 @@ _PyTier2_Code_DetectAndEmitBB( case RESUME: opcode = RESUME_QUICK; DISPATCH(); - case COMPARE_AND_BRANCH: - opcode = specop = COMPARE_OP; - DISPATCH(); case END_FOR: // Assert that we are the start of a BB assert(t2_start == write_i); @@ -1822,7 +1807,6 @@ _PyTier2_GenerateNextBB( _Py_CODEUNIT *curr_executing_instr, int jumpby, _Py_CODEUNIT **tier1_fallback, - char gen_bb_requires_pop, char gen_bb_is_successor) { PyCodeObject *co = frame->f_code; @@ -1848,19 +1832,10 @@ _PyTier2_GenerateNextBB( if (type_context_copy == NULL) { return NULL; } - // If this flag is set, it means that either BB_TEST_IF_FALSE_OR_POP or - // BB_TEST_IF_TRUE_OR_POP was ran and the conditional stack effect was performed - // This means we have to pop an element from the type stack. - if (gen_bb_requires_pop) { - type_context_copy->type_stack_ptr--; - } // For type branches, they directly precede the bb branch instruction _Py_CODEUNIT *prev_type_guard = BB_IS_TYPE_BRANCH(bb_id_tagged) ? curr_executing_instr - 1 : NULL; if (gen_bb_is_successor && prev_type_guard != NULL) { - // Is a type branch, so the previous instruction shouldn't be - // one of those conditional pops. - assert(!gen_bb_requires_pop); // Propagate the type guard information. #if TYPEPROP_DEBUG && defined(Py_DEBUG) fprintf(stderr, diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index f9369f1ede897e..de704c1a59185d 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -640,6 +640,149 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None out.write_raw(extra + line.rstrip("\n") + out.postfix + "\n") out.reset_lineno() + def write_typeprop(self, out: Formatter) -> None: + """Write one instruction's type propagation rules""" + + if self.name in TYPE_PROPAGATOR_FORBIDDEN: + out.emit(f'fprintf(stderr, "Type propagation across `{self.name}` shouldn\'t be handled statically!\\n");') + out.emit("Py_UNREACHABLE();") + return + + need_to_declare = [] + # Stack input is used in local effect + if self.local_effects and \ + isinstance(val := self.local_effects.value, TypeSrcStackInput): + need_to_declare.append(val.name) + # Stack input is used in output effect + for oeffect in self.output_effects: + if not (typ := oeffect.type_annotation): continue + ops = typ.ops + for op in ops: + if not isinstance(src := op.src, TypeSrcStackInput): continue + if oeffect.name in self.unmoved_names and oeffect.name == src.name: + print( + f"Warn: {self.name} type annotation for {oeffect.name} will be ignored " + "as it is unmoved") + continue + need_to_declare.append(src.name) + + # Write input stack effect variable declarations and initializations + ieffects = list(reversed(self.input_effects)) + usable_for_local_effect = {} + all_input_effect_names = {} + for i, ieffect in enumerate(ieffects): + + if ieffect.name not in need_to_declare: continue + + isize = string_effect_size( + list_effect_size([ieff for ieff in ieffects[: i + 1]]) + ) + all_input_effect_names[ieffect.name] = (ieffect, i) + dst = StackEffect(ieffect.name, "_Py_TYPENODE_t *") + if ieffect.size: + # TODO: Support more cases as needed + raise Exception("Type propagation across sized input effect not implemented") + elif ieffect.cond: + src = StackEffect(f"({ieffect.cond}) ? TYPESTACK_PEEK({isize}) : NULL", "_Py_TYPENODE_t *") + else: + usable_for_local_effect[ieffect.name] = ieffect + src = StackEffect(f"TYPESTACK_PEEK({isize})", "_Py_TYPENODE_t *") + out.declare(dst, src) + + # Write localarr effect + if self.local_effects: + + idx = self.local_effects.index + val = self.local_effects.value + + typ_op = "TYPE_OVERWRITE" + dst = f"TYPELOCALS_GET({idx})" + match val: + case TypeSrcLiteral(name=valstr): + if valstr == "NULL": + src = "(_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT" + flag = "true" + else: + src = f"(_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&{valstr})" + flag = "true" + case TypeSrcStackInput(name=valstr): + assert valstr in usable_for_local_effect, \ + "`cond` and `size` stackvar not supported for localeffect" + src = valstr + flag = "false" + # TODO: Support more cases as needed + case TypeSrcConst(): + raise Exception("Not implemented") + case TypeSrcLocals(): + raise Exception("Not implemented") + case _: + typing.assert_never(val) + out.emit(f"{typ_op}({src}, {dst}, {flag});") + + # Update stack size + out.stack_adjust( + 0, + [ieff for ieff in self.input_effects], + [oeff for oeff in self.output_effects], + ) + + # Stack effect + oeffects = list(reversed(self.output_effects)) + for i, oeffect in enumerate(oeffects): + osize = string_effect_size( + list_effect_size([oeff for oeff in oeffects[: i + 1]]) + ) + dst = f"TYPESTACK_PEEK({osize})" + + # Check if it's even used + if oeffect.name == UNUSED: continue + + # Check if there's type info + if typ := oeffect.type_annotation: + for op in typ.ops: + match op.src: + case TypeSrcLiteral(literal=valstr): + if valstr == "NULL": + src = "(_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT" + flag = "true" + else: + src = f"(_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&{valstr})" + flag = "true" + case TypeSrcStackInput(name=valstr): + assert valstr in need_to_declare + assert oeffect.name not in self.unmoved_names + src = valstr + flag = "false" + case TypeSrcConst(index=idx): + src = f"(_Py_TYPENODE_t *)TYPECONST_GET({idx})" + flag = "true" + case TypeSrcLocals(index=idx): + src = f"TYPELOCALS_GET({idx})" + flag = "false" + case _: + typing.assert_never(op.src) + + opstr = f"{op.op}({src}, {dst}, {flag})" + if oeffect.cond: + out.emit(f"if ({oeffect.cond}) {{ {opstr}; }}") + else: + out.emit(f"{opstr};") + continue + + # Don't touch unmoved stack vars + if oeffect.name in self.unmoved_names: + continue + + # Just output null + typ_op = "TYPE_OVERWRITE" + src = "(_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT" + flag = "true" + opstr = f"{typ_op}({src}, {dst}, {flag})" + if oeffect.cond: + out.emit(f"if ({oeffect.cond}) {{ {opstr}; }}") + else: + out.emit(f"{opstr};") + InstructionOrCacheEffect = Instruction | parser.CacheEffect StackEffectMapping = list[tuple[StackEffect, StackEffect]] From 950cf29334c14a0d1d5a9932521aadffa323e0bd Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Mon, 27 Mar 2023 20:25:37 +0800 Subject: [PATCH 226/280] fix a bug --- Python/tier2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/tier2.c b/Python/tier2.c index a2d468b12b2ec0..a3218905706e7d 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -863,7 +863,7 @@ emit_type_guard(_Py_CODEUNIT *write_curr, int guard_opcode, int bb_id) _PyOpcode_OpName[guard_opcode]); #endif write_curr->op.code = guard_opcode; - write_curr->op.arg = type_guard_to_index[BINARY_CHECK_INT]; + write_curr->op.arg = type_guard_to_index[guard_opcode]; write_curr++; _py_set_opcode(write_curr, BB_BRANCH); write_curr->op.arg = 0; From 522725886d9cf34b65b7b3ad95accfc7b9116939 Mon Sep 17 00:00:00 2001 From: Julia Date: Tue, 28 Mar 2023 02:37:19 +0800 Subject: [PATCH 227/280] Fix: Improper handling of conditional stack effect for BB_TEST_ITER --- Include/internal/pycore_code.h | 16 +++++++- Python/bytecodes.c | 46 ++++++++++++----------- Python/ceval.c | 5 +-- Python/generated_cases.c.h | 50 +++++++++++++------------ Python/tier2.c | 22 +++++++---- Python/tier2_typepropagator.c.h | 8 ++-- Tools/cases_generator/generate_cases.py | 2 + 7 files changed, 90 insertions(+), 59 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 143199a4a1bb5b..6be4e9e7a66a48 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -257,6 +257,20 @@ extern void _PyStaticCode_Fini(PyCodeObject *co); extern int _PyStaticCode_Init(PyCodeObject *co); /* Tier 2 interpreter */ + +// gen_bb_is_successor: +// true = successor +// false = alternate +// gen_bb_requires_pop: +// For tier2 type propagation, handling of jump instructions with +// runtime-dependent stack effect. +// This flag is used to determine if the type context of a new bb +// requires a stack element to be popped. +#define BB_TEST(gen_bb_is_successor, gen_bb_requires_pop) \ + ((gen_bb_is_successor << 1) + gen_bb_requires_pop) +#define BB_TEST_IS_SUCCESSOR(bb_test) (bb_test >> 1) +#define BB_TEST_IS_REQUIRES_POP(bb_test) (bb_test & 1) + extern _Py_CODEUNIT *_PyCode_Tier2Warmup(struct _PyInterpreterFrame *, _Py_CODEUNIT *); extern _Py_CODEUNIT *_PyTier2_GenerateNextBB( @@ -265,7 +279,7 @@ extern _Py_CODEUNIT *_PyTier2_GenerateNextBB( _Py_CODEUNIT *curr_executing_instr, int jumpby, _Py_CODEUNIT **tier1_fallback, - char gen_bb_is_successor); + char bb_flag); extern _Py_CODEUNIT *_PyTier2_LocateJumpBackwardsBB( struct _PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, _Py_CODEUNIT **tier1_fallback); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index e974186853211e..38703d6c7825b6 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -124,7 +124,7 @@ dummy_func( } inst(LOAD_CONST, (-- value : consts[oparg])) { - value = GETITEM(consts, oparg); + value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); } @@ -307,18 +307,21 @@ dummy_func( right_unboxed: {<<= PyFloat_Type, PyRawFloat_Type}) ) { assert(cframe.use_tracing == 0); - bb_test = PyFloat_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); - left_unboxed = (bb_test + char is_successor = PyFloat_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); + bb_test = BB_TEST(is_successor ? 1 : 0, 0); + + left_unboxed = (is_successor ? *((PyObject **)(&(((PyFloatObject *)left)->ob_fval))) : left); - right_unboxed = (bb_test + right_unboxed = (is_successor ? *((PyObject **)(&(((PyFloatObject *)right)->ob_fval))) : right); } inst(UNARY_CHECK_FLOAT, (arg, unused[oparg] -- arg : PyFloat_Type, unused[oparg])) { assert(cframe.use_tracing == 0); - bb_test = PyFloat_CheckExact(arg); + char is_successor = PyFloat_CheckExact(arg); + bb_test = BB_TEST(is_successor ? 1 : 0, 0); } inst(BINARY_OP_ADD_FLOAT_UNBOXED, (left, right -- sum : PyRawFloat_Type)) { @@ -346,7 +349,8 @@ dummy_func( inst(BINARY_CHECK_INT, (left, right -- left : <<= PyLong_Type, right : <<= PyLong_Type)) { assert(cframe.use_tracing == 0); - bb_test = PyLong_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); + char is_successor = PyLong_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); + bb_test = BB_TEST(is_successor ? 1 : 0, 0); } u_inst(BINARY_OP_ADD_INT_REST, (left, right -- sum : PyLong_Type)) { @@ -1934,17 +1938,17 @@ dummy_func( inst(BB_TEST_POP_IF_FALSE, (cond -- )) { if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); - bb_test = true; + bb_test = BB_TEST(1, 0); } else if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); - bb_test = false; + bb_test = BB_TEST(0, 0); } else { int err = PyObject_IsTrue(cond); Py_DECREF(cond); if (err == 0) { - bb_test = false; + bb_test = BB_TEST(0, 0); } else { ERROR_IF(err < 0, error); @@ -1975,17 +1979,17 @@ dummy_func( inst(BB_TEST_POP_IF_TRUE, (cond -- )) { if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); - bb_test = true; + bb_test = BB_TEST(1, 0);; } else if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); - bb_test = false; + bb_test = BB_TEST(0, 0);; } else { int err = PyObject_IsTrue(cond); Py_DECREF(cond); if (err > 0) { - bb_test = false; + bb_test = BB_TEST(0, 0);; } else { ERROR_IF(err < 0, error); @@ -2007,11 +2011,11 @@ dummy_func( inst(BB_TEST_POP_IF_NOT_NONE, (value -- )) { if (!Py_IsNone(value)) { Py_DECREF(value); - bb_test = false; + bb_test = BB_TEST(0, 0);; } else { _Py_DECREF_NO_DEALLOC(value); - bb_test = true; + bb_test = BB_TEST(1, 0);; } } @@ -2175,11 +2179,11 @@ dummy_func( /* iterator ended normally */ Py_DECREF(iter); STACK_SHRINK(1); - bb_test = false; + bb_test = BB_TEST(0, 1); JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); DISPATCH(); } - bb_test = true; + bb_test = BB_TEST(1, 0); } inst(FOR_ITER_LIST, (unused/1, iter -- iter, next)) { @@ -3160,7 +3164,7 @@ dummy_func( _Py_CODEUNIT *t2_nextinstr = NULL; _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; _Py_CODEUNIT *tier1_fallback = NULL; - if (bb_test) { + if (BB_TEST_IS_SUCCESSOR(bb_test)) { // Rewrite self _py_set_opcode(next_instr - 1, BB_BRANCH_IF_FLAG_UNSET); // Generate consequent. @@ -3194,7 +3198,7 @@ dummy_func( } inst(BB_BRANCH_IF_FLAG_UNSET, (unused/1 --)) { - if (!bb_test) { + if (!BB_TEST_IS_SUCCESSOR(bb_test)) { _Py_CODEUNIT *curr = next_instr - 1; _Py_CODEUNIT *t2_nextinstr = NULL; _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; @@ -3216,7 +3220,7 @@ dummy_func( } inst(BB_JUMP_IF_FLAG_UNSET, (unused/1 --)) { - if (!bb_test) { + if (!BB_TEST_IS_SUCCESSOR(bb_test)) { JUMPBY(oparg); DISPATCH(); } @@ -3224,7 +3228,7 @@ dummy_func( } inst(BB_BRANCH_IF_FLAG_SET, (unused/1 --)) { - if (bb_test) { + if (BB_TEST_IS_SUCCESSOR(bb_test)) { _Py_CODEUNIT *curr = next_instr - 1; _Py_CODEUNIT *t2_nextinstr = NULL; _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; @@ -3248,7 +3252,7 @@ dummy_func( } inst(BB_JUMP_IF_FLAG_SET, (unused/1 --)) { - if (bb_test) { + if (BB_TEST_IS_SUCCESSOR(bb_test)) { JUMPBY(oparg); DISPATCH(); } diff --git a/Python/ceval.c b/Python/ceval.c index 87d36f7cd14e16..e09966d449f23e 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -724,9 +724,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int _PyCFrame cframe; _PyInterpreterFrame entry_frame; PyObject *kwnames = NULL; // Borrowed reference. Reset by CALL instructions. - // true = successor - // false = alternate - char bb_test = true; + + char bb_test = BB_TEST(0, 0); /* WARNING: Because the _PyCFrame lives on the C stack, * but can be accessed from a heap allocated object (tstate) diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index a7c708a1a374be..f9b0b8716cb20b 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -75,7 +75,7 @@ TARGET(LOAD_CONST) { PREDICTED(LOAD_CONST); PyObject *value; - value = GETITEM(consts, oparg); + value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); STACK_GROW(1); stack_pointer[-1] = value; @@ -149,7 +149,7 @@ oparg = (next_instr++)->op.arg; { PyObject *value; - value = GETITEM(consts, oparg); + value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); _tmp_1 = value; } @@ -198,7 +198,7 @@ PyObject *_tmp_2; { PyObject *value; - value = GETITEM(consts, oparg); + value = GETITEM(frame->f_code->co_consts, oparg); Py_INCREF(value); _tmp_2 = value; } @@ -433,11 +433,13 @@ PyObject *left_unboxed; PyObject *right_unboxed; assert(cframe.use_tracing == 0); - bb_test = PyFloat_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); - left_unboxed = (bb_test + char is_successor = PyFloat_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); + bb_test = BB_TEST(is_successor ? 1 : 0, 0); + + left_unboxed = (is_successor ? *((PyObject **)(&(((PyFloatObject *)left)->ob_fval))) : left); - right_unboxed = (bb_test + right_unboxed = (is_successor ? *((PyObject **)(&(((PyFloatObject *)right)->ob_fval))) : right); stack_pointer[-1] = right_unboxed; @@ -448,7 +450,8 @@ TARGET(UNARY_CHECK_FLOAT) { PyObject *arg = stack_pointer[-(1 + oparg)]; assert(cframe.use_tracing == 0); - bb_test = PyFloat_CheckExact(arg); + char is_successor = PyFloat_CheckExact(arg); + bb_test = BB_TEST(is_successor ? 1 : 0, 0); DISPATCH(); } @@ -500,7 +503,8 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; assert(cframe.use_tracing == 0); - bb_test = PyLong_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); + char is_successor = PyLong_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); + bb_test = BB_TEST(is_successor ? 1 : 0, 0); DISPATCH(); } @@ -2515,17 +2519,17 @@ PyObject *cond = stack_pointer[-1]; if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); - bb_test = true; + bb_test = BB_TEST(1, 0); } else if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); - bb_test = false; + bb_test = BB_TEST(0, 0); } else { int err = PyObject_IsTrue(cond); Py_DECREF(cond); if (err == 0) { - bb_test = false; + bb_test = BB_TEST(0, 0); } else { if (err < 0) goto pop_1_error; @@ -2562,17 +2566,17 @@ PyObject *cond = stack_pointer[-1]; if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); - bb_test = true; + bb_test = BB_TEST(1, 0);; } else if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); - bb_test = false; + bb_test = BB_TEST(0, 0);; } else { int err = PyObject_IsTrue(cond); Py_DECREF(cond); if (err > 0) { - bb_test = false; + bb_test = BB_TEST(0, 0);; } else { if (err < 0) goto pop_1_error; @@ -2599,11 +2603,11 @@ PyObject *value = stack_pointer[-1]; if (!Py_IsNone(value)) { Py_DECREF(value); - bb_test = false; + bb_test = BB_TEST(0, 0);; } else { _Py_DECREF_NO_DEALLOC(value); - bb_test = true; + bb_test = BB_TEST(1, 0);; } STACK_SHRINK(1); DISPATCH(); @@ -2806,11 +2810,11 @@ /* iterator ended normally */ Py_DECREF(iter); STACK_SHRINK(1); - bb_test = false; + bb_test = BB_TEST(0, 1); JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); DISPATCH(); } - bb_test = true; + bb_test = BB_TEST(1, 0); STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -4027,7 +4031,7 @@ _Py_CODEUNIT *t2_nextinstr = NULL; _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; _Py_CODEUNIT *tier1_fallback = NULL; - if (bb_test) { + if (BB_TEST_IS_SUCCESSOR(bb_test)) { // Rewrite self _py_set_opcode(next_instr - 1, BB_BRANCH_IF_FLAG_UNSET); // Generate consequent. @@ -4061,7 +4065,7 @@ } TARGET(BB_BRANCH_IF_FLAG_UNSET) { - if (!bb_test) { + if (!BB_TEST_IS_SUCCESSOR(bb_test)) { _Py_CODEUNIT *curr = next_instr - 1; _Py_CODEUNIT *t2_nextinstr = NULL; _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; @@ -4085,7 +4089,7 @@ } TARGET(BB_JUMP_IF_FLAG_UNSET) { - if (!bb_test) { + if (!BB_TEST_IS_SUCCESSOR(bb_test)) { JUMPBY(oparg); DISPATCH(); } @@ -4095,7 +4099,7 @@ } TARGET(BB_BRANCH_IF_FLAG_SET) { - if (bb_test) { + if (BB_TEST_IS_SUCCESSOR(bb_test)) { _Py_CODEUNIT *curr = next_instr - 1; _Py_CODEUNIT *t2_nextinstr = NULL; _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; @@ -4121,7 +4125,7 @@ } TARGET(BB_JUMP_IF_FLAG_SET) { - if (bb_test) { + if (BB_TEST_IS_SUCCESSOR(bb_test)) { JUMPBY(oparg); DISPATCH(); } diff --git a/Python/tier2.c b/Python/tier2.c index a3218905706e7d..2180fa7981f266 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -375,7 +375,7 @@ __type_propagate_TYPE_OVERWRITE( } static void -__type_stack_shrink(_PyTier2TypeContext *type_context, _Py_TYPENODE_t **type_stackptr, int idx) +__type_stack_shrink(_Py_TYPENODE_t **type_stackptr, int idx) { // TODO: // If we don't touch the stack elements @@ -491,7 +491,7 @@ type_propagate( #define STACK_GROW(idx) *type_stackptr += (idx) // Stack shrinking has to NULL the nodes -#define STACK_SHRINK(idx) __type_stack_shrink(type_context, type_stackptr, (idx)) +#define STACK_SHRINK(idx) __type_stack_shrink(type_stackptr, (idx)) #if TYPEPROP_DEBUG fprintf(stderr, " [-] Type stack bef: %llu\n", (uint64_t)(*type_stackptr - type_stack)); @@ -577,7 +577,7 @@ _PyTier2_BBSpaceCheckAndReallocIfNeeded(PyCodeObject *co, Py_ssize_t space_reque // Note: overallocate Py_ssize_t new_size = sizeof(_PyTier2BBSpace) + (curr->water_level + space_requested) * 2; #if BB_DEBUG - fprintf(stderr, "Allocating new BB of size %lld\n", new_size); + fprintf(stderr, "Allocating new BB of size %lld\n", (int64_t)new_size); #endif // @TODO We can't Realloc, we actually need to do the linked list method. _PyTier2BBSpace *new_space = PyMem_Realloc(curr, new_size); @@ -899,7 +899,8 @@ emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, break; case FOR_ITER: opcode = BB_TEST_ITER; - type_propagate(opcode, oparg, type_context, NULL); + // This inst has conditional stack effect according to whether the branch is taken. + // This inst sets the `gen_bb_requires_pop` flag to handle stack effect of this opcode in BB_BRANCH break; case POP_JUMP_IF_FALSE: opcode = BB_TEST_POP_IF_FALSE; @@ -1225,6 +1226,9 @@ _PyTier2_Code_DetectAndEmitBB( // We need to check whether we can eliminate the guard based on the current type context. dispatch_opcode: +#if TYPEPROP_DEBUG + fprintf(stderr, "offset: %Id\n", curr - _PyCode_CODE(co)); +#endif switch (opcode) { case RESUME: opcode = RESUME_QUICK; @@ -1378,7 +1382,7 @@ _PyTier2_Code_DetectAndEmitBB( write_i = rebox_stack(write_i, starting_type_context, 4); DISPATCH(); default: -#if BB_DEBUG || TYPEPROP_DEBUG +#if BB_DEBUG && !TYPEPROP_DEBUG fprintf(stderr, "offset: %Id\n", curr - _PyCode_CODE(co)); #endif if (IS_BACKWARDS_JUMP_TARGET(co, curr)) { @@ -1807,7 +1811,7 @@ _PyTier2_GenerateNextBB( _Py_CODEUNIT *curr_executing_instr, int jumpby, _Py_CODEUNIT **tier1_fallback, - char gen_bb_is_successor) + char bb_flag) { PyCodeObject *co = frame->f_code; assert(co->_tier2_info != NULL); @@ -1832,10 +1836,14 @@ _PyTier2_GenerateNextBB( if (type_context_copy == NULL) { return NULL; } + + if (BB_TEST_IS_REQUIRES_POP(bb_flag)) { + __type_stack_shrink(&(type_context_copy->type_stack_ptr), 1); + } // For type branches, they directly precede the bb branch instruction _Py_CODEUNIT *prev_type_guard = BB_IS_TYPE_BRANCH(bb_id_tagged) ? curr_executing_instr - 1 : NULL; - if (gen_bb_is_successor && prev_type_guard != NULL) { + if (BB_TEST_IS_SUCCESSOR(bb_flag) && prev_type_guard != NULL) { // Propagate the type guard information. #if TYPEPROP_DEBUG && defined(Py_DEBUG) fprintf(stderr, diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index 46987cc6a07ed2..4e2b95a615d360 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -790,14 +790,14 @@ } TARGET(FOR_ITER) { - STACK_GROW(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + fprintf(stderr, "Type propagation across `FOR_ITER` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } TARGET(BB_TEST_ITER) { - STACK_GROW(1); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + fprintf(stderr, "Type propagation across `BB_TEST_ITER` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index de704c1a59185d..f299d234993e55 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -55,6 +55,8 @@ # Type propagator shouldn't see these "JUMP_IF_FALSE_OR_POP", "JUMP_IF_TRUE_OR_POP", + "BB_TEST_ITER", + "FOR_ITER", "SEND", "SEND_GEN", "YIELD_VALUE", From 11609bf4e8314be42afb793b024f12e79900d68b Mon Sep 17 00:00:00 2001 From: Julia Date: Tue, 28 Mar 2023 02:54:36 +0800 Subject: [PATCH 228/280] Fix: Buggy macros --- Include/internal/pycore_code.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 6be4e9e7a66a48..e5e0fb971a67b5 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -267,9 +267,9 @@ extern int _PyStaticCode_Init(PyCodeObject *co); // This flag is used to determine if the type context of a new bb // requires a stack element to be popped. #define BB_TEST(gen_bb_is_successor, gen_bb_requires_pop) \ - ((gen_bb_is_successor << 1) + gen_bb_requires_pop) -#define BB_TEST_IS_SUCCESSOR(bb_test) (bb_test >> 1) -#define BB_TEST_IS_REQUIRES_POP(bb_test) (bb_test & 1) + (((gen_bb_is_successor) << 1) + (gen_bb_requires_pop)) +#define BB_TEST_IS_SUCCESSOR(bb_test) ((bb_test) >> 1) +#define BB_TEST_IS_REQUIRES_POP(bb_test) ((bb_test) & 1) extern _Py_CODEUNIT *_PyCode_Tier2Warmup(struct _PyInterpreterFrame *, _Py_CODEUNIT *); From 20f919ffbfb2a4368a10cff45c8a2d275cc11641 Mon Sep 17 00:00:00 2001 From: Julia Date: Tue, 28 Mar 2023 03:10:48 +0800 Subject: [PATCH 229/280] Fix: Added missing opcode --- Python/bytecodes.c | 21 ++++++++++++++++----- Python/generated_cases.c.h | 24 +++++++++++++++++++----- Python/opcode_metadata.h | 5 +++++ Python/tier2_typepropagator.c.h | 5 +++++ 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 38703d6c7825b6..5d3d23532a401e 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1979,17 +1979,17 @@ dummy_func( inst(BB_TEST_POP_IF_TRUE, (cond -- )) { if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); - bb_test = BB_TEST(1, 0);; + bb_test = BB_TEST(1, 0); } else if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); - bb_test = BB_TEST(0, 0);; + bb_test = BB_TEST(0, 0); } else { int err = PyObject_IsTrue(cond); Py_DECREF(cond); if (err > 0) { - bb_test = BB_TEST(0, 0);; + bb_test = BB_TEST(0, 0); } else { ERROR_IF(err < 0, error); @@ -2011,11 +2011,11 @@ dummy_func( inst(BB_TEST_POP_IF_NOT_NONE, (value -- )) { if (!Py_IsNone(value)) { Py_DECREF(value); - bb_test = BB_TEST(0, 0);; + bb_test = BB_TEST(0, 0); } else { _Py_DECREF_NO_DEALLOC(value); - bb_test = BB_TEST(1, 0);; + bb_test = BB_TEST(1, 0); } } @@ -2029,6 +2029,17 @@ dummy_func( } } + inst(BB_TEST_POP_IF_NONE, (value -- )) { + if (Py_IsNone(value)) { + Py_DECREF(value); + bb_test = BB_TEST(0, 0); + } + else { + _Py_DECREF_NO_DEALLOC(value); + bb_test = BB_TEST(1, 0); + } + } + inst(JUMP_BACKWARD_NO_INTERRUPT, (--)) { /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index f9b0b8716cb20b..829ff126293b34 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2566,17 +2566,17 @@ PyObject *cond = stack_pointer[-1]; if (Py_IsFalse(cond)) { _Py_DECREF_NO_DEALLOC(cond); - bb_test = BB_TEST(1, 0);; + bb_test = BB_TEST(1, 0); } else if (Py_IsTrue(cond)) { _Py_DECREF_NO_DEALLOC(cond); - bb_test = BB_TEST(0, 0);; + bb_test = BB_TEST(0, 0); } else { int err = PyObject_IsTrue(cond); Py_DECREF(cond); if (err > 0) { - bb_test = BB_TEST(0, 0);; + bb_test = BB_TEST(0, 0); } else { if (err < 0) goto pop_1_error; @@ -2603,11 +2603,11 @@ PyObject *value = stack_pointer[-1]; if (!Py_IsNone(value)) { Py_DECREF(value); - bb_test = BB_TEST(0, 0);; + bb_test = BB_TEST(0, 0); } else { _Py_DECREF_NO_DEALLOC(value); - bb_test = BB_TEST(1, 0);; + bb_test = BB_TEST(1, 0); } STACK_SHRINK(1); DISPATCH(); @@ -2626,6 +2626,20 @@ DISPATCH(); } + TARGET(BB_TEST_POP_IF_NONE) { + PyObject *value = stack_pointer[-1]; + if (Py_IsNone(value)) { + Py_DECREF(value); + bb_test = BB_TEST(0, 0); + } + else { + _Py_DECREF_NO_DEALLOC(value); + bb_test = BB_TEST(1, 0); + } + STACK_SHRINK(1); + DISPATCH(); + } + TARGET(JUMP_BACKWARD_NO_INTERRUPT) { /* This bytecode is used in the `yield from` or `await` loop. * If there is an interrupt, we want it handled in the innermost diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index bc3aeba527d13b..6f77f7c5d4e67c 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -279,6 +279,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 1; case POP_JUMP_IF_NONE: return 1; + case BB_TEST_POP_IF_NONE: + return 1; case JUMP_BACKWARD_NO_INTERRUPT: return 0; case GET_LEN: @@ -673,6 +675,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case POP_JUMP_IF_NONE: return 0; + case BB_TEST_POP_IF_NONE: + return 0; case JUMP_BACKWARD_NO_INTERRUPT: return 0; case GET_LEN: @@ -936,6 +940,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB }, [BB_TEST_POP_IF_NOT_NONE] = { true, INSTR_FMT_IX }, [POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB }, + [BB_TEST_POP_IF_NONE] = { true, INSTR_FMT_IX }, [JUMP_BACKWARD_NO_INTERRUPT] = { true, INSTR_FMT_IB }, [GET_LEN] = { true, INSTR_FMT_IX }, [MATCH_CLASS] = { true, INSTR_FMT_IB }, diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index 4e2b95a615d360..96b514cd096b1e 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -745,6 +745,11 @@ break; } + TARGET(BB_TEST_POP_IF_NONE) { + STACK_SHRINK(1); + break; + } + TARGET(JUMP_BACKWARD_NO_INTERRUPT) { break; } From b57665e2734018ae76b222c75c5e655ba53cd997 Mon Sep 17 00:00:00 2001 From: Julia Date: Tue, 28 Mar 2023 03:34:50 +0800 Subject: [PATCH 230/280] Fix: Bug in EXTENDED_ARG handling for _PyTier2_RewriteForwardJump --- Python/tier2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index 2180fa7981f266..5cb0edc9401836 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -77,6 +77,8 @@ _PyTier2TypeContext_Copy(const _PyTier2TypeContext *type_context) #if TYPEPROP_DEBUG fprintf(stderr, " [*] Copying type context\n"); + static void print_typestack(const _PyTier2TypeContext * type_context); + print_typestack(type_context); #endif _Py_TYPENODE_t *orig_type_locals = type_context->type_locals; @@ -1962,10 +1964,10 @@ _PyTier2_RewriteForwardJump(_Py_CODEUNIT *bb_branch, _Py_CODEUNIT *target) assert(oparg <= 0xFFFF); if (requires_extended) { _py_set_opcode(write_curr, EXTENDED_ARG); - write_curr->op.arg = (oparg >> 8) & 0xFF; - write_curr++; // -1 to oparg because now the jump instruction moves one unit forward. oparg--; + write_curr->op.arg = (oparg >> 8) & 0xFF; + write_curr++; } _py_set_opcode(write_curr, branch == BB_BRANCH_IF_FLAG_SET ? BB_JUMP_IF_FLAG_SET : BB_JUMP_IF_FLAG_UNSET); From 88c27eb4379e8f4187f7eeee0473bad29bb9d4e4 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 28 Mar 2023 10:45:25 +0800 Subject: [PATCH 231/280] Apply review comments --- Include/internal/pycore_code.h | 2 +- Python/bytecodes.c | 6 +++--- Python/generated_cases.c.h | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index e5e0fb971a67b5..70c6be0038d6d7 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -267,7 +267,7 @@ extern int _PyStaticCode_Init(PyCodeObject *co); // This flag is used to determine if the type context of a new bb // requires a stack element to be popped. #define BB_TEST(gen_bb_is_successor, gen_bb_requires_pop) \ - (((gen_bb_is_successor) << 1) + (gen_bb_requires_pop)) + (((gen_bb_is_successor) << 1) | (gen_bb_requires_pop)) #define BB_TEST_IS_SUCCESSOR(bb_test) ((bb_test) >> 1) #define BB_TEST_IS_REQUIRES_POP(bb_test) ((bb_test) & 1) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 5d3d23532a401e..b86e4c98adfa69 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -308,7 +308,7 @@ dummy_func( ) { assert(cframe.use_tracing == 0); char is_successor = PyFloat_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); - bb_test = BB_TEST(is_successor ? 1 : 0, 0); + bb_test = BB_TEST(is_successor, 0); left_unboxed = (is_successor ? *((PyObject **)(&(((PyFloatObject *)left)->ob_fval))) @@ -321,7 +321,7 @@ dummy_func( inst(UNARY_CHECK_FLOAT, (arg, unused[oparg] -- arg : PyFloat_Type, unused[oparg])) { assert(cframe.use_tracing == 0); char is_successor = PyFloat_CheckExact(arg); - bb_test = BB_TEST(is_successor ? 1 : 0, 0); + bb_test = BB_TEST(is_successor, 0); } inst(BINARY_OP_ADD_FLOAT_UNBOXED, (left, right -- sum : PyRawFloat_Type)) { @@ -350,7 +350,7 @@ dummy_func( inst(BINARY_CHECK_INT, (left, right -- left : <<= PyLong_Type, right : <<= PyLong_Type)) { assert(cframe.use_tracing == 0); char is_successor = PyLong_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); - bb_test = BB_TEST(is_successor ? 1 : 0, 0); + bb_test = BB_TEST(is_successor, 0); } u_inst(BINARY_OP_ADD_INT_REST, (left, right -- sum : PyLong_Type)) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 829ff126293b34..7a2121a20b2144 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -434,7 +434,7 @@ PyObject *right_unboxed; assert(cframe.use_tracing == 0); char is_successor = PyFloat_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); - bb_test = BB_TEST(is_successor ? 1 : 0, 0); + bb_test = BB_TEST(is_successor, 0); left_unboxed = (is_successor ? *((PyObject **)(&(((PyFloatObject *)left)->ob_fval))) @@ -451,7 +451,7 @@ PyObject *arg = stack_pointer[-(1 + oparg)]; assert(cframe.use_tracing == 0); char is_successor = PyFloat_CheckExact(arg); - bb_test = BB_TEST(is_successor ? 1 : 0, 0); + bb_test = BB_TEST(is_successor, 0); DISPATCH(); } @@ -504,7 +504,7 @@ PyObject *left = stack_pointer[-2]; assert(cframe.use_tracing == 0); char is_successor = PyLong_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); - bb_test = BB_TEST(is_successor ? 1 : 0, 0); + bb_test = BB_TEST(is_successor, 0); DISPATCH(); } From d6a7b9792d4e2839123b536039ac04b1f8653a32 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 28 Mar 2023 18:15:13 +0800 Subject: [PATCH 232/280] Some cleanup --- Include/internal/pycore_code.h | 2 +- Python/bytecodes.c | 2 -- Python/ceval_macros.h | 2 +- Python/tier2.c | 12 +++--------- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 70c6be0038d6d7..55c8bd9cd4227a 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -269,7 +269,7 @@ extern int _PyStaticCode_Init(PyCodeObject *co); #define BB_TEST(gen_bb_is_successor, gen_bb_requires_pop) \ (((gen_bb_is_successor) << 1) | (gen_bb_requires_pop)) #define BB_TEST_IS_SUCCESSOR(bb_test) ((bb_test) >> 1) -#define BB_TEST_IS_REQUIRES_POP(bb_test) ((bb_test) & 1) +#define BB_TEST_IS_REQUIRES_POP(bb_test) ((bb_test) & 1) extern _Py_CODEUNIT *_PyCode_Tier2Warmup(struct _PyInterpreterFrame *, _Py_CODEUNIT *); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index b86e4c98adfa69..0aa87a4a93d16a 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3245,8 +3245,6 @@ dummy_func( _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; _Py_CODEUNIT *tier1_fallback = NULL; - // @TODO: Rewrite TEST intruction above to a JUMP above.. - t2_nextinstr = _PyTier2_GenerateNextBB( frame, cache->bb_id_tagged, next_instr - 1, oparg, &tier1_fallback, bb_test); diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 2a7f35e8e43ece..1d3f15735a031a 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -68,7 +68,7 @@ lastopcode = op; \ } while (0) #else -#define INSTRUCTION_START(op) (frame->prev_instr = next_instr++) +#define INSTRUCTION_START(op) (frame->prev_instr = next_instr++); /* fprintf(stderr, "%d: %s\n", INSTR_OFFSET(), _PyOpcode_OpName[op]); */ #endif #if USE_COMPUTED_GOTOS diff --git a/Python/tier2.c b/Python/tier2.c index 5cb0edc9401836..f285c1305b4138 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -1942,13 +1942,6 @@ BB_TEST_POP_IF_TRUE BB_JUMP_IF_FLAG_SET CACHE (will be converted to EXTENDED_ARGS if we need a bigger jump) -Some instructions will be special since they need CACHE entries. E.g. FOR_ITER - -BB_TEST_ITER -CACHE -BB_BRANCH_IF_FLAG_SET -CACHE - Backwards jumps are handled by another function. */ @@ -1958,6 +1951,7 @@ _PyTier2_RewriteForwardJump(_Py_CODEUNIT *bb_branch, _Py_CODEUNIT *target) _Py_CODEUNIT *write_curr = bb_branch; // -1 because the PC is auto incremented int oparg = (int)(target - bb_branch - 1); + assert(oparg > 0); int branch = _Py_OPCODE(*bb_branch); assert(branch == BB_BRANCH_IF_FLAG_SET || branch == BB_BRANCH_IF_FLAG_UNSET); bool requires_extended = oparg > 0xFF; @@ -1985,14 +1979,14 @@ _PyTier2_RewriteForwardJump(_Py_CODEUNIT *bb_branch, _Py_CODEUNIT *target) Before: EXTENDED_ARG/NOP -JUMP_BACKWARD_LAZY +BB_JUMP_BACKWARD_LAZY CACHE After: EXTENDED_ARG (if needed, else NOP) -JUMP_BACKWARD_LAZY +JUMP_BACKWARD_QUICK END_FOR */ From 4b7137c8242bb13b6ac83dedbb4c5ecdf2731555 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 28 Mar 2023 18:26:00 +0800 Subject: [PATCH 233/280] Revert "Merge remote-tracking branch 'upstream/main' into tier2_interpreter_no_separate_eval_no_tracer_contiguous_bbs" This reverts commit fae3104c8de52a13fced2e425e978cd0db5f5057, reversing changes made to d6a7b9792d4e2839123b536039ac04b1f8653a32. --- Lib/dis.py | 7 +---- Lib/enum.py | 15 +++------ Lib/pdb.py | 31 ++++++++----------- Lib/tarfile.py | 6 ++-- Lib/test/test_dis.py | 29 ----------------- Lib/test/test_enum.py | 18 +---------- Lib/test/test_pdb.py | 6 ---- Lib/test/test_tarfile.py | 7 ----- ...3-03-04-20-58-29.gh-issue-74468.Ac5Ew_.rst | 3 -- ...-03-25-02-08-05.gh-issue-103023.Qfn7Hl.rst | 2 -- ...-03-26-20-54-57.gh-issue-103046.xBlA2l.rst | 1 - ...-03-27-15-01-16.gh-issue-103056.-Efh5Q.rst | 1 - Objects/unicodeobject.c | 9 +----- Python/bytecodes.c | 2 +- Python/generated_cases.c.h | 4 ++- 15 files changed, 28 insertions(+), 113 deletions(-) delete mode 100644 Misc/NEWS.d/next/Library/2023-03-04-20-58-29.gh-issue-74468.Ac5Ew_.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-03-25-02-08-05.gh-issue-103023.Qfn7Hl.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-03-26-20-54-57.gh-issue-103046.xBlA2l.rst delete mode 100644 Misc/NEWS.d/next/Library/2023-03-27-15-01-16.gh-issue-103056.-Efh5Q.rst diff --git a/Lib/dis.py b/Lib/dis.py index accace858fab99..844acd56f84ff0 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -605,12 +605,7 @@ def _disassemble_bytes(code, lasti=-1, varname_from_oparg=None, instr.offset > 0) if new_source_line: print(file=file) - if show_caches: - is_current_instr = instr.offset == lasti - else: - # Each CACHE takes 2 bytes - is_current_instr = instr.offset <= lasti \ - <= instr.offset + 2 * _inline_cache_entries[_deoptop(instr.opcode)] + is_current_instr = instr.offset == lasti print(instr._disassemble(lineno_width, is_current_instr, offset_width), file=file) if exception_entries: diff --git a/Lib/enum.py b/Lib/enum.py index a9fb50606290fb..ba927662a43b13 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -518,13 +518,8 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k # # adjust the sunders _order_ = classdict.pop('_order_', None) - _gnv = classdict.get('_generate_next_value_') - if _gnv is not None and type(_gnv) is not staticmethod: - _gnv = staticmethod(_gnv) # convert to normal dict classdict = dict(classdict.items()) - if _gnv is not None: - classdict['_generate_next_value_'] = _gnv # # data type of member and the controlling Enum class member_type, first_enum = metacls._get_mixins_(cls, bases) @@ -928,7 +923,7 @@ def _convert_(cls, name, module, filter, source=None, *, boundary=None, as_globa def _check_for_existing_members_(mcls, class_name, bases): for chain in bases: for base in chain.__mro__: - if isinstance(base, EnumType) and base._member_names_: + if issubclass(base, Enum) and base._member_names_: raise TypeError( " cannot extend %r" % (class_name, base) @@ -947,7 +942,7 @@ def _get_mixins_(mcls, class_name, bases): # ensure final parent class is an Enum derivative, find any concrete # data type, and check that Enum has no members first_enum = bases[-1] - if not isinstance(first_enum, EnumType): + if not issubclass(first_enum, Enum): raise TypeError("new enumerations should be created as " "`EnumName([mixin_type, ...] [data_type,] enum_type)`") member_type = mcls._find_data_type_(class_name, bases) or object @@ -959,7 +954,7 @@ def _find_data_repr_(mcls, class_name, bases): for base in chain.__mro__: if base is object: continue - elif isinstance(base, EnumType): + elif issubclass(base, Enum): # if we hit an Enum, use it's _value_repr_ return base._value_repr_ elif '__repr__' in base.__dict__: @@ -985,12 +980,12 @@ def _find_data_type_(mcls, class_name, bases): base_chain.add(base) if base is object: continue - elif isinstance(base, EnumType): + elif issubclass(base, Enum): if base._member_type_ is not object: data_types.add(base._member_type_) break elif '__new__' in base.__dict__ or '__init__' in base.__dict__: - if isinstance(base, EnumType): + if issubclass(base, Enum): continue data_types.add(candidate or base) break diff --git a/Lib/pdb.py b/Lib/pdb.py index d402de1192f9e2..3543f53282db15 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -399,7 +399,7 @@ def preloop(self): displaying = self.displaying.get(self.curframe) if displaying: for expr, oldvalue in displaying.items(): - newvalue, _ = self._getval_except(expr) + newvalue = self._getval_except(expr) # check for identity first; this prevents custom __eq__ to # be called at every loop, and also prevents instances whose # fields are changed to be displayed @@ -1246,12 +1246,13 @@ def _getval(self, arg): def _getval_except(self, arg, frame=None): try: if frame is None: - return eval(arg, self.curframe.f_globals, self.curframe_locals), None + return eval(arg, self.curframe.f_globals, self.curframe_locals) else: - return eval(arg, frame.f_globals, frame.f_locals), None - except BaseException as exc: - err = traceback.format_exception_only(exc)[-1].strip() - return _rstr('** raised %s **' % err), exc + return eval(arg, frame.f_globals, frame.f_locals) + except: + exc_info = sys.exc_info()[:2] + err = traceback.format_exception_only(*exc_info)[-1].strip() + return _rstr('** raised %s **' % err) def _error_exc(self): exc_info = sys.exc_info()[:2] @@ -1436,19 +1437,13 @@ def do_display(self, arg): Without expression, list all display expressions for the current frame. """ if not arg: - if self.displaying: - self.message('Currently displaying:') - for item in self.displaying.get(self.curframe, {}).items(): - self.message('%s: %r' % item) - else: - self.message('No expression is being displayed') + self.message('Currently displaying:') + for item in self.displaying.get(self.curframe, {}).items(): + self.message('%s: %r' % item) else: - val, exc = self._getval_except(arg) - if isinstance(exc, SyntaxError): - self.message('Unable to display %s: %r' % (arg, val)) - else: - self.displaying.setdefault(self.curframe, {})[arg] = val - self.message('display %s: %r' % (arg, val)) + val = self._getval_except(arg) + self.displaying.setdefault(self.curframe, {})[arg] = val + self.message('display %s: %r' % (arg, val)) complete_display = _complete_expression diff --git a/Lib/tarfile.py b/Lib/tarfile.py index b733195c9c5636..d686435d90ad1b 100755 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -601,12 +601,12 @@ class _FileInFile(object): object. """ - def __init__(self, fileobj, offset, size, name, blockinfo=None): + def __init__(self, fileobj, offset, size, blockinfo=None): self.fileobj = fileobj self.offset = offset self.size = size self.position = 0 - self.name = name + self.name = getattr(fileobj, "name", None) self.closed = False if blockinfo is None: @@ -703,7 +703,7 @@ class ExFileObject(io.BufferedReader): def __init__(self, tarfile, tarinfo): fileobj = _FileInFile(tarfile.fileobj, tarinfo.offset_data, - tarinfo.size, tarinfo.name, tarinfo.sparse) + tarinfo.size, tarinfo.sparse) super().__init__(fileobj) #class ExFileObject diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 7cad8d1bfe13ae..ed66b362b08080 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1198,35 +1198,6 @@ def test_show_caches(self): self.assertEqual(caches.count(""), empty_caches) self.assertEqual(len(caches), total_caches) - @cpython_only - def test_show_currinstr_with_cache(self): - """ - Make sure that with lasti pointing to CACHE, it still shows the current - line correctly - """ - def f(): - print(a) - # The code above should generate a LOAD_GLOBAL which has CACHE instr after - # However, this might change in the future. So we explicitly try to find - # a CACHE entry in the instructions. If we can't do that, fail the test - - for inst in dis.get_instructions(f, show_caches=True): - if inst.opname == "CACHE": - op_offset = inst.offset - 2 - cache_offset = inst.offset - break - else: - self.fail("Can't find a CACHE entry in the function provided to do the test") - - assem_op = self.get_disassembly(f.__code__, lasti=op_offset, wrapper=False) - assem_cache = self.get_disassembly(f.__code__, lasti=cache_offset, wrapper=False) - - # Make sure --> exists and points to the correct offset - self.assertRegex(assem_op, fr"-->\s+{op_offset}") - # Make sure when lasti points to cache, it shows the same disassembly - self.assertEqual(assem_op, assem_cache) - - class DisWithFileTests(DisTests): # Run the tests again, using the file arg instead of print diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index bea19542705dc4..bb163c46481a42 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -270,17 +270,6 @@ class NewSubEnum(NewBaseEnum): first = auto() self.NewSubEnum = NewSubEnum # - class LazyGNV(self.enum_type): - def _generate_next_value_(name, start, last, values): - pass - self.LazyGNV = LazyGNV - # - class BusyGNV(self.enum_type): - @staticmethod - def _generate_next_value_(name, start, last, values): - pass - self.BusyGNV = BusyGNV - # self.is_flag = False self.names = ['first', 'second', 'third'] if issubclass(MainEnum, StrEnum): @@ -477,12 +466,6 @@ def test_enum_in_enum_out(self): Main = self.MainEnum self.assertIs(Main(Main.first), Main.first) - def test_gnv_is_static(self): - lazy = self.LazyGNV - busy = self.BusyGNV - self.assertTrue(type(lazy.__dict__['_generate_next_value_']) is staticmethod) - self.assertTrue(type(busy.__dict__['_generate_next_value_']) is staticmethod) - def test_hash(self): MainEnum = self.MainEnum mapping = {} @@ -1386,6 +1369,7 @@ def repr(self): class Huh(MyStr, MyInt, Enum): One = 1 + def test_pickle_enum(self): if isinstance(Stooges, Exception): raise Stooges diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index ae9c5d73e2daa7..e96dc7fa1cf6e7 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -586,8 +586,6 @@ def test_pdb_display_command(): ... a = 4 >>> with PdbTestInput([ # doctest: +ELLIPSIS - ... 'display +', - ... 'display', ... 'display a', ... 'n', ... 'display', @@ -602,10 +600,6 @@ def test_pdb_display_command(): ... test_function() > (4)test_function() -> a = 1 - (Pdb) display + - Unable to display +: ** raised SyntaxError: invalid syntax ** - (Pdb) display - No expression is being displayed (Pdb) display a display a: 0 (Pdb) n diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 39f6f499c818ef..75b60e9a50e78a 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -479,13 +479,6 @@ def test_length_zero_header(self): with tarfile.open(support.findfile('recursion.tar')) as tar: pass - def test_extractfile_name(self): - # gh-74468: TarFile.name must name a file, not a parent archive. - file = self.tar.getmember('ustar/regtype') - with self.tar.extractfile(file) as fobj: - self.assertEqual(fobj.name, 'ustar/regtype') - - class MiscReadTestBase(CommonReadTest): def requires_name_attribute(self): pass diff --git a/Misc/NEWS.d/next/Library/2023-03-04-20-58-29.gh-issue-74468.Ac5Ew_.rst b/Misc/NEWS.d/next/Library/2023-03-04-20-58-29.gh-issue-74468.Ac5Ew_.rst deleted file mode 100644 index 8fad551f3a4ece..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-04-20-58-29.gh-issue-74468.Ac5Ew_.rst +++ /dev/null @@ -1,3 +0,0 @@ -Attribute name of the extracted :mod:`tarfile` file object now holds -filename of itself rather than of the archive it is contained in. -Patch by Oleg Iarygin. diff --git a/Misc/NEWS.d/next/Library/2023-03-25-02-08-05.gh-issue-103023.Qfn7Hl.rst b/Misc/NEWS.d/next/Library/2023-03-25-02-08-05.gh-issue-103023.Qfn7Hl.rst deleted file mode 100644 index e7958f6f002055..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-25-02-08-05.gh-issue-103023.Qfn7Hl.rst +++ /dev/null @@ -1,2 +0,0 @@ -It's no longer possible to register expressions to display in -:class:`~pdb.Pdb` that raise :exc:`SyntaxError`. Patch by Tian Gao. diff --git a/Misc/NEWS.d/next/Library/2023-03-26-20-54-57.gh-issue-103046.xBlA2l.rst b/Misc/NEWS.d/next/Library/2023-03-26-20-54-57.gh-issue-103046.xBlA2l.rst deleted file mode 100644 index f9bd0a10056ef1..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-26-20-54-57.gh-issue-103046.xBlA2l.rst +++ /dev/null @@ -1 +0,0 @@ -Display current line label correctly in :mod:`dis` when ``show_caches`` is False and ``lasti`` points to a CACHE entry. diff --git a/Misc/NEWS.d/next/Library/2023-03-27-15-01-16.gh-issue-103056.-Efh5Q.rst b/Misc/NEWS.d/next/Library/2023-03-27-15-01-16.gh-issue-103056.-Efh5Q.rst deleted file mode 100644 index c892d8376503f8..00000000000000 --- a/Misc/NEWS.d/next/Library/2023-03-27-15-01-16.gh-issue-103056.-Efh5Q.rst +++ /dev/null @@ -1 +0,0 @@ -Ensure final ``_generate_next_value_`` is a ``staticmethod``. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 4cb035ce6f9641..891a65576ee29b 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14609,14 +14609,7 @@ PyUnicode_InternInPlace(PyObject **p) } PyObject *interned = get_interned_dict(); - assert(interned != NULL); - - PyObject *t = PyDict_SetDefault(interned, s, s); - if (t == NULL) { - PyErr_Clear(); - return; - } - + PyObject *t = _Py_AddToGlobalDict(interned, s, s); if (t != s) { if (t != NULL) { Py_SETREF(*p, Py_NewRef(t)); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index b3076ee9142239..0aa87a4a93d16a 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2035,7 +2035,7 @@ dummy_func( bb_test = BB_TEST(0, 0); } else { - DECREF_INPUTS(); + _Py_DECREF_NO_DEALLOC(value); bb_test = BB_TEST(1, 0); } } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 6874b03ac9b8bc..7a2121a20b2144 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2633,7 +2633,7 @@ bb_test = BB_TEST(0, 0); } else { - Py_DECREF(value); + _Py_DECREF_NO_DEALLOC(value); bb_test = BB_TEST(1, 0); } STACK_SHRINK(1); @@ -4119,6 +4119,8 @@ _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; _Py_CODEUNIT *tier1_fallback = NULL; + // @TODO: Rewrite TEST intruction above to a JUMP above.. + t2_nextinstr = _PyTier2_GenerateNextBB( frame, cache->bb_id_tagged, next_instr - 1, oparg, &tier1_fallback, bb_test); From 632305b0673d9ce943a8ce7beb11505513ae46fe Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 28 Mar 2023 18:31:40 +0800 Subject: [PATCH 234/280] Fix bad merge --- Include/internal/pycore_global_objects.h | 4 - Include/internal/pycore_interp.h | 1 - Include/internal/pycore_pystate.h | 5 - Include/internal/pycore_runtime_init.h | 3 - Include/internal/pycore_unicodeobject.h | 1 - Lib/enum.py | 17 +- Lib/pdb.py | 31 +-- Lib/tarfile.py | 6 +- Lib/test/test_dis.py | 29 +++ Lib/test/test_enum.py | 18 +- Lib/test/test_pdb.py | 6 + Lib/test/test_tarfile.py | 7 + ...3-03-04-20-58-29.gh-issue-74468.Ac5Ew_.rst | 3 + ...-03-25-02-08-05.gh-issue-103023.Qfn7Hl.rst | 2 + ...-03-26-20-54-57.gh-issue-103046.xBlA2l.rst | 1 + ...-03-27-15-01-16.gh-issue-103056.-Efh5Q.rst | 1 + Objects/unicodeobject.c | 13 +- Python/pylifecycle.c | 4 - Python/pystate.c | 204 ++---------------- 19 files changed, 127 insertions(+), 229 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-03-04-20-58-29.gh-issue-74468.Ac5Ew_.rst create mode 100644 Misc/NEWS.d/next/Library/2023-03-25-02-08-05.gh-issue-103023.Qfn7Hl.rst create mode 100644 Misc/NEWS.d/next/Library/2023-03-26-20-54-57.gh-issue-103046.xBlA2l.rst create mode 100644 Misc/NEWS.d/next/Library/2023-03-27-15-01-16.gh-issue-103056.-Efh5Q.rst diff --git a/Include/internal/pycore_global_objects.h b/Include/internal/pycore_global_objects.h index 858321d67df481..9957da1fc5f22a 100644 --- a/Include/internal/pycore_global_objects.h +++ b/Include/internal/pycore_global_objects.h @@ -28,10 +28,6 @@ extern "C" { struct _Py_cached_objects { PyObject *interned_strings; - /* A thread state tied to the main interpreter, - used exclusively for when a global object (e.g. interned strings) - is resized (i.e. deallocated + allocated) from an arbitrary thread. */ - PyThreadState main_tstate; }; #define _Py_GLOBAL_OBJECT(NAME) \ diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index fcdf8d2f2c8e15..1f2c0db2eb5f27 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -164,7 +164,6 @@ struct _is { struct _Py_interp_cached_objects cached_objects; struct _Py_interp_static_objects static_objects; - /* The following fields are here to avoid allocation during init. The data is exposed through PyInterpreterState pointer fields. These fields should not be accessed directly outside of init. diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h index f159b516e66b18..7046ec8d9adaaf 100644 --- a/Include/internal/pycore_pystate.h +++ b/Include/internal/pycore_pystate.h @@ -127,11 +127,6 @@ PyAPI_FUNC(void) _PyThreadState_Init( PyThreadState *tstate); PyAPI_FUNC(void) _PyThreadState_DeleteExcept(PyThreadState *tstate); -extern void _PyThreadState_InitDetached(PyThreadState *, PyInterpreterState *); -extern void _PyThreadState_ClearDetached(PyThreadState *); - -extern PyObject * _Py_AddToGlobalDict(PyObject *, PyObject *, PyObject *); - static inline void _PyThreadState_UpdateTracingState(PyThreadState *tstate) diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index fd358b2da6ccff..7cfa7c0c02494a 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -59,9 +59,6 @@ extern PyTypeObject _PyExc_MemoryError; .types = { \ .next_version_tag = 1, \ }, \ - .cached_objects = { \ - .main_tstate = _PyThreadState_INIT, \ - }, \ .static_objects = { \ .singletons = { \ .small_ints = _Py_small_ints_INIT, \ diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h index ed4feb603d6f38..19faceebf1d8ee 100644 --- a/Include/internal/pycore_unicodeobject.h +++ b/Include/internal/pycore_unicodeobject.h @@ -34,7 +34,6 @@ struct _Py_unicode_runtime_ids { struct _Py_unicode_runtime_state { struct _Py_unicode_runtime_ids ids; - /* The interned dict is at _PyRuntime.cached_objects.interned_strings. */ }; /* fs_codec.encoding is initialized to NULL. diff --git a/Lib/enum.py b/Lib/enum.py index ba927662a43b13..8c77117ce6acb4 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -518,8 +518,13 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k # # adjust the sunders _order_ = classdict.pop('_order_', None) + _gnv = classdict.get('_generate_next_value_') + if _gnv is not None and type(_gnv) is not staticmethod: + _gnv = staticmethod(_gnv) # convert to normal dict classdict = dict(classdict.items()) + if _gnv is not None: + classdict['_generate_next_value_'] = _gnv # # data type of member and the controlling Enum class member_type, first_enum = metacls._get_mixins_(cls, bases) @@ -923,7 +928,7 @@ def _convert_(cls, name, module, filter, source=None, *, boundary=None, as_globa def _check_for_existing_members_(mcls, class_name, bases): for chain in bases: for base in chain.__mro__: - if issubclass(base, Enum) and base._member_names_: + if isinstance(base, EnumType) and base._member_names_: raise TypeError( " cannot extend %r" % (class_name, base) @@ -942,7 +947,7 @@ def _get_mixins_(mcls, class_name, bases): # ensure final parent class is an Enum derivative, find any concrete # data type, and check that Enum has no members first_enum = bases[-1] - if not issubclass(first_enum, Enum): + if not isinstance(first_enum, EnumType): raise TypeError("new enumerations should be created as " "`EnumName([mixin_type, ...] [data_type,] enum_type)`") member_type = mcls._find_data_type_(class_name, bases) or object @@ -954,7 +959,7 @@ def _find_data_repr_(mcls, class_name, bases): for base in chain.__mro__: if base is object: continue - elif issubclass(base, Enum): + elif isinstance(base, EnumType): # if we hit an Enum, use it's _value_repr_ return base._value_repr_ elif '__repr__' in base.__dict__: @@ -980,12 +985,12 @@ def _find_data_type_(mcls, class_name, bases): base_chain.add(base) if base is object: continue - elif issubclass(base, Enum): + elif isinstance(base, EnumType): if base._member_type_ is not object: data_types.add(base._member_type_) break elif '__new__' in base.__dict__ or '__init__' in base.__dict__: - if issubclass(base, Enum): + if isinstance(base, EnumType): continue data_types.add(candidate or base) break @@ -1186,8 +1191,6 @@ def _missing_(cls, value): return None def __repr__(self): - if not isinstance(self, Enum): - return repr(self) v_repr = self.__class__._value_repr_ or repr return "<%s.%s: %s>" % (self.__class__.__name__, self._name_, v_repr(self._value_)) diff --git a/Lib/pdb.py b/Lib/pdb.py index 3543f53282db15..d402de1192f9e2 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -399,7 +399,7 @@ def preloop(self): displaying = self.displaying.get(self.curframe) if displaying: for expr, oldvalue in displaying.items(): - newvalue = self._getval_except(expr) + newvalue, _ = self._getval_except(expr) # check for identity first; this prevents custom __eq__ to # be called at every loop, and also prevents instances whose # fields are changed to be displayed @@ -1246,13 +1246,12 @@ def _getval(self, arg): def _getval_except(self, arg, frame=None): try: if frame is None: - return eval(arg, self.curframe.f_globals, self.curframe_locals) + return eval(arg, self.curframe.f_globals, self.curframe_locals), None else: - return eval(arg, frame.f_globals, frame.f_locals) - except: - exc_info = sys.exc_info()[:2] - err = traceback.format_exception_only(*exc_info)[-1].strip() - return _rstr('** raised %s **' % err) + return eval(arg, frame.f_globals, frame.f_locals), None + except BaseException as exc: + err = traceback.format_exception_only(exc)[-1].strip() + return _rstr('** raised %s **' % err), exc def _error_exc(self): exc_info = sys.exc_info()[:2] @@ -1437,13 +1436,19 @@ def do_display(self, arg): Without expression, list all display expressions for the current frame. """ if not arg: - self.message('Currently displaying:') - for item in self.displaying.get(self.curframe, {}).items(): - self.message('%s: %r' % item) + if self.displaying: + self.message('Currently displaying:') + for item in self.displaying.get(self.curframe, {}).items(): + self.message('%s: %r' % item) + else: + self.message('No expression is being displayed') else: - val = self._getval_except(arg) - self.displaying.setdefault(self.curframe, {})[arg] = val - self.message('display %s: %r' % (arg, val)) + val, exc = self._getval_except(arg) + if isinstance(exc, SyntaxError): + self.message('Unable to display %s: %r' % (arg, val)) + else: + self.displaying.setdefault(self.curframe, {})[arg] = val + self.message('display %s: %r' % (arg, val)) complete_display = _complete_expression diff --git a/Lib/tarfile.py b/Lib/tarfile.py index d686435d90ad1b..b733195c9c5636 100755 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -601,12 +601,12 @@ class _FileInFile(object): object. """ - def __init__(self, fileobj, offset, size, blockinfo=None): + def __init__(self, fileobj, offset, size, name, blockinfo=None): self.fileobj = fileobj self.offset = offset self.size = size self.position = 0 - self.name = getattr(fileobj, "name", None) + self.name = name self.closed = False if blockinfo is None: @@ -703,7 +703,7 @@ class ExFileObject(io.BufferedReader): def __init__(self, tarfile, tarinfo): fileobj = _FileInFile(tarfile.fileobj, tarinfo.offset_data, - tarinfo.size, tarinfo.sparse) + tarinfo.size, tarinfo.name, tarinfo.sparse) super().__init__(fileobj) #class ExFileObject diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index ed66b362b08080..7cad8d1bfe13ae 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1198,6 +1198,35 @@ def test_show_caches(self): self.assertEqual(caches.count(""), empty_caches) self.assertEqual(len(caches), total_caches) + @cpython_only + def test_show_currinstr_with_cache(self): + """ + Make sure that with lasti pointing to CACHE, it still shows the current + line correctly + """ + def f(): + print(a) + # The code above should generate a LOAD_GLOBAL which has CACHE instr after + # However, this might change in the future. So we explicitly try to find + # a CACHE entry in the instructions. If we can't do that, fail the test + + for inst in dis.get_instructions(f, show_caches=True): + if inst.opname == "CACHE": + op_offset = inst.offset - 2 + cache_offset = inst.offset + break + else: + self.fail("Can't find a CACHE entry in the function provided to do the test") + + assem_op = self.get_disassembly(f.__code__, lasti=op_offset, wrapper=False) + assem_cache = self.get_disassembly(f.__code__, lasti=cache_offset, wrapper=False) + + # Make sure --> exists and points to the correct offset + self.assertRegex(assem_op, fr"-->\s+{op_offset}") + # Make sure when lasti points to cache, it shows the same disassembly + self.assertEqual(assem_op, assem_cache) + + class DisWithFileTests(DisTests): # Run the tests again, using the file arg instead of print diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index bb163c46481a42..bea19542705dc4 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -270,6 +270,17 @@ class NewSubEnum(NewBaseEnum): first = auto() self.NewSubEnum = NewSubEnum # + class LazyGNV(self.enum_type): + def _generate_next_value_(name, start, last, values): + pass + self.LazyGNV = LazyGNV + # + class BusyGNV(self.enum_type): + @staticmethod + def _generate_next_value_(name, start, last, values): + pass + self.BusyGNV = BusyGNV + # self.is_flag = False self.names = ['first', 'second', 'third'] if issubclass(MainEnum, StrEnum): @@ -466,6 +477,12 @@ def test_enum_in_enum_out(self): Main = self.MainEnum self.assertIs(Main(Main.first), Main.first) + def test_gnv_is_static(self): + lazy = self.LazyGNV + busy = self.BusyGNV + self.assertTrue(type(lazy.__dict__['_generate_next_value_']) is staticmethod) + self.assertTrue(type(busy.__dict__['_generate_next_value_']) is staticmethod) + def test_hash(self): MainEnum = self.MainEnum mapping = {} @@ -1369,7 +1386,6 @@ def repr(self): class Huh(MyStr, MyInt, Enum): One = 1 - def test_pickle_enum(self): if isinstance(Stooges, Exception): raise Stooges diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index e96dc7fa1cf6e7..ae9c5d73e2daa7 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -586,6 +586,8 @@ def test_pdb_display_command(): ... a = 4 >>> with PdbTestInput([ # doctest: +ELLIPSIS + ... 'display +', + ... 'display', ... 'display a', ... 'n', ... 'display', @@ -600,6 +602,10 @@ def test_pdb_display_command(): ... test_function() > (4)test_function() -> a = 1 + (Pdb) display + + Unable to display +: ** raised SyntaxError: invalid syntax ** + (Pdb) display + No expression is being displayed (Pdb) display a display a: 0 (Pdb) n diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index 75b60e9a50e78a..39f6f499c818ef 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -479,6 +479,13 @@ def test_length_zero_header(self): with tarfile.open(support.findfile('recursion.tar')) as tar: pass + def test_extractfile_name(self): + # gh-74468: TarFile.name must name a file, not a parent archive. + file = self.tar.getmember('ustar/regtype') + with self.tar.extractfile(file) as fobj: + self.assertEqual(fobj.name, 'ustar/regtype') + + class MiscReadTestBase(CommonReadTest): def requires_name_attribute(self): pass diff --git a/Misc/NEWS.d/next/Library/2023-03-04-20-58-29.gh-issue-74468.Ac5Ew_.rst b/Misc/NEWS.d/next/Library/2023-03-04-20-58-29.gh-issue-74468.Ac5Ew_.rst new file mode 100644 index 00000000000000..8fad551f3a4ece --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-04-20-58-29.gh-issue-74468.Ac5Ew_.rst @@ -0,0 +1,3 @@ +Attribute name of the extracted :mod:`tarfile` file object now holds +filename of itself rather than of the archive it is contained in. +Patch by Oleg Iarygin. diff --git a/Misc/NEWS.d/next/Library/2023-03-25-02-08-05.gh-issue-103023.Qfn7Hl.rst b/Misc/NEWS.d/next/Library/2023-03-25-02-08-05.gh-issue-103023.Qfn7Hl.rst new file mode 100644 index 00000000000000..e7958f6f002055 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-25-02-08-05.gh-issue-103023.Qfn7Hl.rst @@ -0,0 +1,2 @@ +It's no longer possible to register expressions to display in +:class:`~pdb.Pdb` that raise :exc:`SyntaxError`. Patch by Tian Gao. diff --git a/Misc/NEWS.d/next/Library/2023-03-26-20-54-57.gh-issue-103046.xBlA2l.rst b/Misc/NEWS.d/next/Library/2023-03-26-20-54-57.gh-issue-103046.xBlA2l.rst new file mode 100644 index 00000000000000..f9bd0a10056ef1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-26-20-54-57.gh-issue-103046.xBlA2l.rst @@ -0,0 +1 @@ +Display current line label correctly in :mod:`dis` when ``show_caches`` is False and ``lasti`` points to a CACHE entry. diff --git a/Misc/NEWS.d/next/Library/2023-03-27-15-01-16.gh-issue-103056.-Efh5Q.rst b/Misc/NEWS.d/next/Library/2023-03-27-15-01-16.gh-issue-103056.-Efh5Q.rst new file mode 100644 index 00000000000000..c892d8376503f8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-03-27-15-01-16.gh-issue-103056.-Efh5Q.rst @@ -0,0 +1 @@ +Ensure final ``_generate_next_value_`` is a ``staticmethod``. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 891a65576ee29b..b9fb53147b9b51 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -14609,11 +14609,16 @@ PyUnicode_InternInPlace(PyObject **p) } PyObject *interned = get_interned_dict(); - PyObject *t = _Py_AddToGlobalDict(interned, s, s); + assert(interned != NULL); + + PyObject *t = PyDict_SetDefault(interned, s, s); + if (t == NULL) { + PyErr_Clear(); + return; + } + if (t != s) { - if (t != NULL) { - Py_SETREF(*p, Py_NewRef(t)); - } + Py_SETREF(*p, Py_NewRef(t)); return; } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 5d7f8621833040..8110d94ba17526 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -636,8 +636,6 @@ pycore_create_interpreter(_PyRuntimeState *runtime, return status; } - _PyThreadState_InitDetached(&runtime->cached_objects.main_tstate, interp); - *tstate_p = tstate; return _PyStatus_OK(); } @@ -1934,8 +1932,6 @@ Py_FinalizeEx(void) // XXX Do this sooner during finalization. // XXX Ensure finalizer errors are handled properly. - _PyThreadState_ClearDetached(&runtime->cached_objects.main_tstate); - finalize_interp_clear(tstate); finalize_interp_delete(tstate->interp); diff --git a/Python/pystate.c b/Python/pystate.c index 394b12d24065f2..b17efdbefd124c 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -565,124 +565,6 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime) #endif -//--------------- -// global objects -//--------------- - -/* The global objects thread state is meant to be used in a very limited - way and should not be used to actually run any Python code. */ - -static PyThreadState * -bind_global_objects_state(_PyRuntimeState *runtime) -{ - PyThreadState *main_tstate = &runtime->cached_objects.main_tstate; - - bind_tstate(main_tstate); - /* Unlike _PyThreadState_Bind(), we do not modify gilstate TSS. */ - - return main_tstate; -} - -static void -unbind_global_objects_state(_PyRuntimeState *runtime) -{ - PyThreadState *main_tstate = &runtime->cached_objects.main_tstate; - assert(tstate_is_alive(main_tstate)); - assert(!main_tstate->_status.active); - assert(gilstate_tss_get(runtime) != main_tstate); - - unbind_tstate(main_tstate); - - /* This thread state may be bound/unbound repeatedly, - so we must erase evidence that it was ever bound (or unbound). */ - main_tstate->_status.bound = 0; - main_tstate->_status.unbound = 0; - - /* We must fully unlink the thread state from any OS thread, - to allow it to be bound more than once. */ - main_tstate->thread_id = 0; -#ifdef PY_HAVE_THREAD_NATIVE_ID - main_tstate->native_thread_id = 0; -#endif -} - -static inline void -acquire_global_objects_lock(_PyRuntimeState *runtime) -{ - /* For now we can rely on the GIL, so we don't actually - acquire a global lock here. */ - assert(current_fast_get(runtime) != NULL); -} - -static inline void -release_global_objects_lock(_PyRuntimeState *runtime) -{ - /* For now we can rely on the GIL, so we don't actually - release a global lock here. */ - assert(current_fast_get(runtime) != NULL); -} - -PyObject * -_Py_AddToGlobalDict(PyObject *dict, PyObject *key, PyObject *value) -{ - assert(dict != NULL); - assert(PyDict_CheckExact(dict)); - - /* All global objects are stored in _PyRuntime - and owned by the main interpreter. */ - _PyRuntimeState *runtime = &_PyRuntime; - PyThreadState *curts = current_fast_get(runtime); - PyInterpreterState *interp = curts->interp; - assert(interp != NULL); // The GIL must be held. - - /* Due to interpreter isolation we must hold a global lock, - starting at this point and ending before we return. - Note that the operations in this function are very fucused - and we should not expect any reentrancy. */ - acquire_global_objects_lock(runtime); - - /* Swap to the main interpreter, if necessary. */ - PyThreadState *oldts = NULL; - if (!_Py_IsMainInterpreter(interp)) { - PyThreadState *main_tstate = bind_global_objects_state(runtime); - - oldts = _PyThreadState_Swap(runtime, main_tstate); - assert(oldts != NULL); - assert(!_Py_IsMainInterpreter(oldts->interp)); - - /* The limitations of the global objects thread state apply - from this point to the point we swap back to oldts. */ - } - - /* This might trigger a resize, which is why we must "acquire" - the global object state. Also note that PyDict_SetDefault() - must be compatible with our reentrancy and global objects state - constraints. */ - PyObject *actual = PyDict_SetDefault(dict, key, value); - if (actual == NULL) { - /* Raising an exception from one interpreter in another - is problematic, so we clear it and let the caller deal - with the returned NULL. */ - assert(PyErr_ExceptionMatches(PyExc_MemoryError)); - PyErr_Clear(); - } - - /* Swap back, it it wasn't in the main interpreter already. */ - if (oldts != NULL) { - // The returned tstate should be _PyRuntime.cached_objects.main_tstate. - _PyThreadState_Swap(runtime, oldts); - - unbind_global_objects_state(runtime); - } - - release_global_objects_lock(runtime); - - // XXX Immortalize the key and value. - - return actual; -} - - /*************************************/ /* the per-interpreter runtime state */ /*************************************/ @@ -1335,7 +1217,8 @@ free_threadstate(PyThreadState *tstate) static void init_threadstate(PyThreadState *tstate, - PyInterpreterState *interp, uint64_t id) + PyInterpreterState *interp, uint64_t id, + PyThreadState *next) { if (tstate->_status.initialized) { Py_FatalError("thread state already initialized"); @@ -1344,13 +1227,18 @@ init_threadstate(PyThreadState *tstate, assert(interp != NULL); tstate->interp = interp; - // next/prev are set in add_threadstate(). - assert(tstate->next == NULL); - assert(tstate->prev == NULL); - assert(id > 0); tstate->id = id; + assert(interp->threads.head == tstate); + assert((next != NULL && id != 1) || (next == NULL && id == 1)); + if (next != NULL) { + assert(next->prev == NULL || next->prev == tstate); + next->prev = tstate; + } + tstate->next = next; + assert(tstate->prev == NULL); + // thread_id and native_thread_id are set in bind_tstate(). tstate->py_recursion_limit = interp->ceval.recursion_limit, @@ -1371,22 +1259,6 @@ init_threadstate(PyThreadState *tstate, tstate->_status.initialized = 1; } -static void -add_threadstate(PyInterpreterState *interp, PyThreadState *tstate, - PyThreadState *next) -{ - assert(interp->threads.head != tstate); - assert((next != NULL && tstate->id != 1) || - (next == NULL && tstate->id == 1)); - if (next != NULL) { - assert(next->prev == NULL || next->prev == tstate); - next->prev = tstate; - } - tstate->next = next; - assert(tstate->prev == NULL); - interp->threads.head = tstate; -} - static PyThreadState * new_threadstate(PyInterpreterState *interp) { @@ -1426,9 +1298,9 @@ new_threadstate(PyInterpreterState *interp) &initial._main_interpreter._initial_thread, sizeof(*tstate)); } + interp->threads.head = tstate; - init_threadstate(tstate, interp, id); - add_threadstate(interp, tstate, old_head); + init_threadstate(tstate, interp, id, old_head); HEAD_UNLOCK(runtime); if (!used_newtstate) { @@ -1475,33 +1347,6 @@ _PyThreadState_Init(PyThreadState *tstate) Py_FatalError("_PyThreadState_Init() is for internal use only"); } -void -_PyThreadState_InitDetached(PyThreadState *tstate, PyInterpreterState *interp) -{ - _PyRuntimeState *runtime = interp->runtime; - - HEAD_LOCK(runtime); - interp->threads.next_unique_id += 1; - uint64_t id = interp->threads.next_unique_id; - HEAD_UNLOCK(runtime); - - init_threadstate(tstate, interp, id); - // We do not call add_threadstate(). -} - - -static void -clear_datastack(PyThreadState *tstate) -{ - _PyStackChunk *chunk = tstate->datastack_chunk; - tstate->datastack_chunk = NULL; - while (chunk != NULL) { - _PyStackChunk *prev = chunk->previous; - _PyObject_VirtualFree(chunk, chunk->size); - chunk = prev; - } -} - void PyThreadState_Clear(PyThreadState *tstate) { @@ -1576,6 +1421,7 @@ PyThreadState_Clear(PyThreadState *tstate) // XXX Do it as early in the function as possible. } + /* Common code for PyThreadState_Delete() and PyThreadState_DeleteCurrent() */ static void tstate_delete_common(PyThreadState *tstate) @@ -1608,25 +1454,17 @@ tstate_delete_common(PyThreadState *tstate) unbind_tstate(tstate); // XXX Move to PyThreadState_Clear()? - clear_datastack(tstate); + _PyStackChunk *chunk = tstate->datastack_chunk; + tstate->datastack_chunk = NULL; + while (chunk != NULL) { + _PyStackChunk *prev = chunk->previous; + _PyObject_VirtualFree(chunk, chunk->size); + chunk = prev; + } tstate->_status.finalized = 1; } -void -_PyThreadState_ClearDetached(PyThreadState *tstate) -{ - assert(!tstate->_status.bound); - assert(!tstate->_status.bound_gilstate); - assert(tstate->datastack_chunk == NULL); - assert(tstate->thread_id == 0); - assert(tstate->native_thread_id == 0); - assert(tstate->next == NULL); - assert(tstate->prev == NULL); - - PyThreadState_Clear(tstate); - clear_datastack(tstate); -} static void zapthreads(PyInterpreterState *interp) From 98e96aff33f80c5f1dc29900f10c1a626b7e6814 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 28 Mar 2023 18:34:56 +0800 Subject: [PATCH 235/280] remove extraneous print --- Lib/dis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/dis.py b/Lib/dis.py index 844acd56f84ff0..5475c404858991 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -498,7 +498,6 @@ def _get_instructions_bytes(code, varname_from_oparg=None, argval = arg*2 argrepr = "to " + repr(argval) elif deop in _bb_jumps: - print("HI") signed_arg = -arg if _is_backward_jump(deop) else arg argval = offset + 2 + signed_arg*2 argval += 2 * caches From 6a8e23094b8ebd12d6026487a1aa6409cc782c37 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 28 Mar 2023 20:39:25 +0800 Subject: [PATCH 236/280] Fix bug in forward jump rewrites --- Python/generated_cases.c.h | 2 -- Python/specialize.c | 10 ++++----- Python/tier2.c | 46 +++++++++++++++++++++----------------- 3 files changed, 31 insertions(+), 27 deletions(-) diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 7a2121a20b2144..c2d46d5e4dcab6 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -4119,8 +4119,6 @@ _PyBBBranchCache *cache = (_PyBBBranchCache *)next_instr; _Py_CODEUNIT *tier1_fallback = NULL; - // @TODO: Rewrite TEST intruction above to a JUMP above.. - t2_nextinstr = _PyTier2_GenerateNextBB( frame, cache->bb_id_tagged, next_instr - 1, oparg, &tier1_fallback, bb_test); diff --git a/Python/specialize.c b/Python/specialize.c index dd5b22dd2346c5..f27951613bfc7a 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -2153,11 +2153,11 @@ _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg) instr->op.code = FOR_ITER_RANGE; goto success; } - else if (tp == &PyGen_Type && oparg <= SHRT_MAX) { - assert(instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1].op.code == END_FOR); - instr->op.code = FOR_ITER_GEN; - goto success; - } + //else if (tp == &PyGen_Type && oparg <= SHRT_MAX) { + // assert(instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1].op.code == END_FOR); + // instr->op.code = FOR_ITER_GEN; + // goto success; + //} SPECIALIZATION_FAIL(FOR_ITER, _PySpecialization_ClassifyIterator(iter)); STAT_INC(FOR_ITER, failure); diff --git a/Python/tier2.c b/Python/tier2.c index f285c1305b4138..d7759e36e23110 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -582,13 +582,14 @@ _PyTier2_BBSpaceCheckAndReallocIfNeeded(PyCodeObject *co, Py_ssize_t space_reque fprintf(stderr, "Allocating new BB of size %lld\n", (int64_t)new_size); #endif // @TODO We can't Realloc, we actually need to do the linked list method. - _PyTier2BBSpace *new_space = PyMem_Realloc(curr, new_size); - if (new_space == NULL) { - return NULL; - } - co->_tier2_info->_bb_space = new_space; - new_space->max_capacity = new_size; - return new_space; + Py_UNREACHABLE(); + //_PyTier2BBSpace *new_space = PyMem_Realloc(curr, new_size); + //if (new_space == NULL) { + // return NULL; + //} + //co->_tier2_info->_bb_space = new_space; + //new_space->max_capacity = new_size; + //return new_space; } // We have enouogh space. Don't do anything, j return curr; @@ -936,8 +937,8 @@ emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, fprintf(stderr, "emitted backwards jump %p %d\n", write_curr, _Py_OPCODE(branch)); #endif - // Just in case - _py_set_opcode(write_curr, EXTENDED_ARG); + // Just in case, can be swapped out with an EXTENDED_ARG + _py_set_opcode(write_curr, NOP); write_curr->op.arg = 0; write_curr++; // We don't need to recalculate the backward jump, because that only needs to be done @@ -966,6 +967,9 @@ emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, write_curr->op.arg = oparg; write_curr++; write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_FOR_ITER); + // Just in case, can be swapped out with an EXTENDED_ARG + _py_set_opcode(write_curr, NOP); + write_curr++; _py_set_opcode(write_curr, BB_BRANCH); write_curr->op.arg = oparg; write_curr++; @@ -983,6 +987,9 @@ emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, _py_set_opcode(write_curr, opcode); write_curr->op.arg = oparg; write_curr++; + _py_set_opcode(write_curr, NOP); + // Just in case, can be swapped out with an EXTENDED_ARG + write_curr++; _py_set_opcode(write_curr, BB_BRANCH); write_curr->op.arg = oparg & 0xFF; write_curr++; @@ -1948,30 +1955,28 @@ Backwards jumps are handled by another function. void _PyTier2_RewriteForwardJump(_Py_CODEUNIT *bb_branch, _Py_CODEUNIT *target) { - _Py_CODEUNIT *write_curr = bb_branch; + int branch = _Py_OPCODE(*bb_branch); + assert(branch == BB_BRANCH_IF_FLAG_SET || + branch == BB_BRANCH_IF_FLAG_UNSET); + _Py_CODEUNIT *write_curr = bb_branch - 1; // -1 because the PC is auto incremented int oparg = (int)(target - bb_branch - 1); assert(oparg > 0); - int branch = _Py_OPCODE(*bb_branch); - assert(branch == BB_BRANCH_IF_FLAG_SET || branch == BB_BRANCH_IF_FLAG_UNSET); bool requires_extended = oparg > 0xFF; assert(oparg <= 0xFFFF); if (requires_extended) { _py_set_opcode(write_curr, EXTENDED_ARG); - // -1 to oparg because now the jump instruction moves one unit forward. - oparg--; write_curr->op.arg = (oparg >> 8) & 0xFF; write_curr++; } + else { + _py_set_opcode(write_curr, NOP); + write_curr++; + } _py_set_opcode(write_curr, branch == BB_BRANCH_IF_FLAG_SET ? BB_JUMP_IF_FLAG_SET : BB_JUMP_IF_FLAG_UNSET); write_curr->op.arg = oparg & 0xFF; write_curr++; - if (!requires_extended) { - _py_set_opcode(write_curr, NOP); - write_curr++; - } - } @@ -1996,7 +2001,8 @@ _PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *tar _Py_CODEUNIT *write_curr = jump_backward_lazy - 1; _Py_CODEUNIT *prev = jump_backward_lazy - 1; assert(_Py_OPCODE(*jump_backward_lazy) == BB_JUMP_BACKWARD_LAZY); - assert(_Py_OPCODE(*prev) == EXTENDED_ARG); + assert(_Py_OPCODE(*prev) == EXTENDED_ARG || + _Py_OPCODE(*prev) == NOP); // +1 because we increment the PC before JUMPBY int oparg = (int)(target - (jump_backward_lazy + 1)); From 590e99a4bde98f00d82dcd6f0b4461a5f6164296 Mon Sep 17 00:00:00 2001 From: Jules <57632293+JuliaPoo@users.noreply.github.com> Date: Wed, 29 Mar 2023 01:51:48 +0800 Subject: [PATCH 237/280] Added EXTENDED_ARG to type prop (#29) --- Python/tier2_typepropagator.c.h | 2 -- Tools/cases_generator/generate_cases.py | 1 - 2 files changed, 3 deletions(-) diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index 96b514cd096b1e..357cc74c4e46c2 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -1054,8 +1054,6 @@ } TARGET(EXTENDED_ARG) { - fprintf(stderr, "Type propagation across `EXTENDED_ARG` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); break; } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index f299d234993e55..1ac6962e00cc20 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -70,7 +70,6 @@ "MATCH_MAPPING", "MATCH_SEQUENCE", "MATCH_KEYS", - "EXTENDED_ARG", "WITH_EXCEPT_START", # Type propagation across these instructions are forbidden # due to conditional effects that can't be determined statically From 47d10293302878d2c06af7c89b2dcff7761d8c31 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 29 Mar 2023 01:52:47 +0800 Subject: [PATCH 238/280] Revert "Added EXTENDED_ARG to type prop (#29)" This reverts commit 590e99a4bde98f00d82dcd6f0b4461a5f6164296. --- Python/tier2_typepropagator.c.h | 2 ++ Tools/cases_generator/generate_cases.py | 1 + 2 files changed, 3 insertions(+) diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index 357cc74c4e46c2..96b514cd096b1e 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -1054,6 +1054,8 @@ } TARGET(EXTENDED_ARG) { + fprintf(stderr, "Type propagation across `EXTENDED_ARG` shouldn't be handled statically!\n"); + Py_UNREACHABLE(); break; } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 1ac6962e00cc20..f299d234993e55 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -70,6 +70,7 @@ "MATCH_MAPPING", "MATCH_SEQUENCE", "MATCH_KEYS", + "EXTENDED_ARG", "WITH_EXCEPT_START", # Type propagation across these instructions are forbidden # due to conditional effects that can't be determined statically From 1b8fb915408949c531a8dd1535ba902ec8966b6a Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 29 Mar 2023 02:47:42 +0800 Subject: [PATCH 239/280] Handle EXTENDED_ARG in tier 1 --- Python/tier2.c | 64 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index d7759e36e23110..1d364590513b60 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -749,7 +749,7 @@ IS_TERMINATOR_OPCODE(int opcode) // Opcodes that we can't handle at the moment. If we see them, // ditch tier 2 attempts. static inline int -IS_FORBIDDEN_OPCODE(int opcode) +IS_FORBIDDEN_OPCODE(int opcode, int nextop) { switch (opcode) { // Modifying containers @@ -788,11 +788,10 @@ IS_FORBIDDEN_OPCODE(int opcode) case MATCH_MAPPING: case MATCH_SEQUENCE: case MATCH_KEYS: - // Too large arguments, we can handle this, just - // increases complexity - case EXTENDED_ARG: return 1; - + // Two simultaneous EXTENDED_ARG + case EXTENDED_ARG: + return nextop == EXTENDED_ARG; default: return 0; } @@ -885,10 +884,10 @@ emit_type_guard(_Py_CODEUNIT *write_curr, int guard_opcode, int bb_id) // BB_BRANCH // CACHE (bb_id of the current BB << 1 | is_type_branch) static inline _Py_CODEUNIT * -emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id) +emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, + _Py_CODEUNIT branch, int bb_id, int oparg) { int opcode; - int oparg = _Py_OPARG(branch); // @TODO handle JUMP_BACKWARDS and JUMP_BACKWARDS_NO_INTERRUPT switch (_PyOpcode_Deopt[_Py_OPCODE(branch)]) { case JUMP_BACKWARD_QUICK: @@ -930,7 +929,8 @@ emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, #endif Py_UNREACHABLE(); } - assert(oparg <= 0XFF); + assert(oparg <= 0XFFFF); + bool requires_extended_arg = oparg > 0xFF; // Backwards jumps should be handled specially. if (opcode == BB_JUMP_BACKWARD_LAZY) { #if BB_DEBUG @@ -938,13 +938,13 @@ emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, _Py_OPCODE(branch)); #endif // Just in case, can be swapped out with an EXTENDED_ARG - _py_set_opcode(write_curr, NOP); - write_curr->op.arg = 0; + _py_set_opcode(write_curr, requires_extended_arg ? EXTENDED_ARG : NOP); + write_curr->op.arg = (oparg >> 8) & 0xFF; write_curr++; // We don't need to recalculate the backward jump, because that only needs to be done // when it locates the next BB in JUMP_BACKWARD_LAZY. _py_set_opcode(write_curr, BB_JUMP_BACKWARD_LAZY); - write_curr->op.arg = oparg; + write_curr->op.arg = oparg & 0xFF; write_curr++; _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_BB_BRANCH); @@ -963,15 +963,19 @@ emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, // NOTE: IF YOU CHANGE ANY OF THE INSTRUCTIONS BELOW, MAKE SURE // TO UPDATE THE CALCULATION OF OPARG. THIS IS EXTREMELY IMPORTANT. oparg = INLINE_CACHE_ENTRIES_FOR_ITER + oparg; + requires_extended_arg = oparg > 0xFF; + _py_set_opcode(write_curr, requires_extended_arg ? EXTENDED_ARG : NOP); + write_curr->op.arg = (oparg >> 8) & 0xFF; + write_curr++; _py_set_opcode(write_curr, BB_TEST_ITER); - write_curr->op.arg = oparg; + write_curr->op.arg = oparg & 0xFF; write_curr++; write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_FOR_ITER); - // Just in case, can be swapped out with an EXTENDED_ARG - _py_set_opcode(write_curr, NOP); + _py_set_opcode(write_curr, requires_extended_arg ? EXTENDED_ARG : NOP); + write_curr->op.arg = (oparg >> 8) & 0xFF; write_curr++; _py_set_opcode(write_curr, BB_BRANCH); - write_curr->op.arg = oparg; + write_curr->op.arg = oparg & 0xFF; write_curr++; _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_BB_BRANCH); @@ -983,12 +987,14 @@ emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, fprintf(stderr, "emitted logical branch %p %d\n", write_curr, _Py_OPCODE(branch)); #endif - //_Py_CODEUNIT *start = write_curr; + _py_set_opcode(write_curr, requires_extended_arg ? EXTENDED_ARG : NOP); + write_curr->op.arg = (oparg >> 8) & 0xFF; + write_curr++; _py_set_opcode(write_curr, opcode); - write_curr->op.arg = oparg; + write_curr->op.arg = oparg & 0xFF; write_curr++; - _py_set_opcode(write_curr, NOP); - // Just in case, can be swapped out with an EXTENDED_ARG + _py_set_opcode(write_curr, requires_extended_arg ? EXTENDED_ARG : NOP); + write_curr->op.arg = (oparg >> 8) & 0xFF; write_curr++; _py_set_opcode(write_curr, BB_BRANCH); write_curr->op.arg = oparg & 0xFF; @@ -1239,8 +1245,16 @@ _PyTier2_Code_DetectAndEmitBB( fprintf(stderr, "offset: %Id\n", curr - _PyCode_CODE(co)); #endif switch (opcode) { + case EXTENDED_ARG: + specop = next_instr->op.code; + opcode = _PyOpcode_Deopt[specop]; + oparg = oparg << 8 | next_instr->op.arg; + curr++; + next_instr++; + i+=2; + DISPATCH_GOTO(); case RESUME: - opcode = RESUME_QUICK; + opcode = specop = RESUME_QUICK; DISPATCH(); case END_FOR: // Assert that we are the start of a BB @@ -1359,7 +1373,8 @@ _PyTier2_Code_DetectAndEmitBB( write_i, starting_type_context, co->_tier2_info->bb_data_curr); if (possible_next == NULL) { - DISPATCH(); + write_i = rebox_stack(write_i, starting_type_context, 2); + DISPATCH() } write_i = possible_next; if (needs_guard) { @@ -1452,7 +1467,7 @@ _PyTier2_Code_DetectAndEmitBB( // Get the BB ID without incrementing it. // AllocateBBMetaData will increment. write_i = emit_logical_branch(starting_type_context, write_i, *curr, - co->_tier2_info->bb_data_curr); + co->_tier2_info->bb_data_curr, oparg); i += caches; END(); } @@ -1714,7 +1729,10 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) for (Py_ssize_t curr = 0; curr < Py_SIZE(co); curr++) { _Py_CODEUNIT *curr_instr = _PyCode_CODE(co) + curr; int deopt = _PyOpcode_Deopt[_Py_OPCODE(*curr_instr)]; - if (IS_FORBIDDEN_OPCODE(deopt)) { + int next = curr < Py_SIZE(co) - 1 + ? _PyOpcode_Deopt[(curr_instr + 1)->op.code] + : 255; + if (IS_FORBIDDEN_OPCODE(deopt, next)) { #if BB_DEBUG #ifdef Py_DEBUG fprintf(stderr, "FORBIDDEN OPCODE %s\n", _PyOpcode_OpName[_Py_OPCODE(*curr_instr)]); From e8f9f981e97fae7863383477f12fbcfe6413e0dd Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 29 Mar 2023 17:36:23 +0800 Subject: [PATCH 240/280] Diff function for backwards jump Also supports "loop unrolling" --- Python/tier2.c | 244 ++++++++++++++++++++---- Python/tier2_typepropagator.c.h | 4 +- Tools/cases_generator/generate_cases.py | 25 ++- 3 files changed, 220 insertions(+), 53 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index 1d364590513b60..2bd8d756539259 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -647,6 +647,9 @@ write_bb_metadata(PyCodeObject *co, _PyTier2BBMetadata *metadata) co->_tier2_info->bb_data[id] = metadata; metadata->id = id; co->_tier2_info->bb_data_curr++; +#if BB_DEBUG + fprintf(stderr, "Creating a BB Metadata with ID %d\n", id); +#endif return 0; } @@ -825,21 +828,18 @@ emit_cache_entries(_Py_CODEUNIT *write_curr, int cache_entries) return write_curr; } +#define BB_ID(bb_id_raw) (bb_id_raw >> 1) +#define BB_IS_TYPE_BRANCH(bb_id_raw) (bb_id_raw & 1) +#define MAKE_TAGGED_BB_ID(bb_id, type_branch) (bb_id << 1 | type_branch) + static inline void write_bb_id(_PyBBBranchCache *cache, int bb_id, bool is_type_guard) { assert((uint16_t)(bb_id) == bb_id); - uint16_t bb_id16 = (uint16_t)bb_id; // Make sure MSB is unset, because we need to shift it. - assert((bb_id16 & 0x8000) == 0); - bb_id16 <<= 1; - bb_id16 |= is_type_guard; - cache->bb_id_tagged = bb_id16; + assert((bb_id & 0x8000) == 0); + cache->bb_id_tagged = MAKE_TAGGED_BB_ID((uint16_t)bb_id, is_type_guard); } -#define BB_ID(bb_id_raw) (bb_id_raw >> 1) -#define BB_IS_TYPE_BRANCH(bb_id_raw) (bb_id_raw & 1) - - // The order/hierarchy to emit type guards // NEED TO ADD TO THIS EVERY TIME WE ADD A NEW ONE. static int type_guard_ladder[256] = { @@ -971,6 +971,7 @@ emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, write_curr->op.arg = oparg & 0xFF; write_curr++; write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_FOR_ITER); + type_propagate(BB_TEST_ITER, oparg, type_context, NULL); _py_set_opcode(write_curr, requires_extended_arg ? EXTENDED_ARG : NOP); write_curr->op.arg = (oparg >> 8) & 0xFF; write_curr++; @@ -1215,6 +1216,7 @@ _PyTier2_Code_DetectAndEmitBB( _PyTier2BBMetadata *meta = NULL; _PyTier2BBMetadata *temp_meta = NULL; + _PyTier2BBMetadata *jump_end_meta = NULL; _PyTier2Info *t2_info = co->_tier2_info; PyObject *consts = co->co_consts; @@ -1424,6 +1426,9 @@ _PyTier2_Code_DetectAndEmitBB( virtual_start = false; goto fall_through; } +#if TYPEPROP_DEBUG + print_typestack(starting_type_context); +#endif // Else, create a virtual end to the basic block. // But generate the block after that so it can fall through. i--; @@ -1432,7 +1437,7 @@ _PyTier2_Code_DetectAndEmitBB( if (type_context_copy == NULL) { return NULL; } - meta = _PyTier2_AllocateBBMetaData(co, + jump_end_meta = meta = _PyTier2_AllocateBBMetaData(co, t2_start, _PyCode_CODE(co) + i, type_context_copy); if (meta == NULL) { _PyTier2TypeContext_Free(type_context_copy); @@ -1443,7 +1448,6 @@ _PyTier2_Code_DetectAndEmitBB( t2_start = write_i; i++; virtual_start = true; - starting_type_context = type_context_copy; // Don't change opcode or oparg, let us handle it again. DISPATCH_GOTO(); @@ -1498,7 +1502,8 @@ _PyTier2_Code_DetectAndEmitBB( } if (starts_with_backwards_jump_target) { // Add the basic block to the jump ids - if (add_metadata_to_jump_2d_array(t2_info, temp_meta, + assert(jump_end_meta != NULL); + if (add_metadata_to_jump_2d_array(t2_info, jump_end_meta, backwards_jump_target_offset) < 0) { PyMem_Free(meta); if (meta != temp_meta) { @@ -1828,17 +1833,15 @@ _PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) return next_instr; } -// Lazily generates successive BBs when required. -// The first basic block created will always be directly after the current tier 2 code. -// The second basic block created will always require a jump. -_Py_CODEUNIT * -_PyTier2_GenerateNextBB( +_PyTier2BBMetadata * +_PyTier2_GenerateNextBBMetaWithTypeContext( _PyInterpreterFrame *frame, uint16_t bb_id_tagged, _Py_CODEUNIT *curr_executing_instr, int jumpby, _Py_CODEUNIT **tier1_fallback, - char bb_flag) + char bb_flag, + _PyTier2TypeContext *type_context_copy) { PyCodeObject *co = frame->f_code; assert(co->_tier2_info != NULL); @@ -1856,14 +1859,6 @@ _PyTier2_GenerateNextBB( // DEOPTIMIZE TO TIER 1? return NULL; } - // Get type_context of previous BB - _PyTier2TypeContext *type_context = meta->type_context; - // Make a copy of the type context - _PyTier2TypeContext *type_context_copy = _PyTier2TypeContext_Copy(type_context); - if (type_context_copy == NULL) { - return NULL; - } - if (BB_TEST_IS_REQUIRES_POP(bb_flag)) { __type_stack_shrink(&(type_context_copy->type_stack_ptr), 1); } @@ -1889,9 +1884,132 @@ _PyTier2_GenerateNextBB( _PyTier2TypeContext_Free(type_context_copy); return NULL; } + return metadata; +} + +// Lazily generates successive BBs when required. +// The first basic block created will always be directly after the current tier 2 code. +// The second basic block created will always require a jump. +_PyTier2BBMetadata * +_PyTier2_GenerateNextBBMeta( + _PyInterpreterFrame *frame, + uint16_t bb_id_tagged, + _Py_CODEUNIT *curr_executing_instr, + int jumpby, + _Py_CODEUNIT **tier1_fallback, + char bb_flag) +{ + _PyTier2BBMetadata *meta = frame->f_code->_tier2_info->bb_data[BB_ID(bb_id_tagged)]; + + // Get type_context of previous BB + _PyTier2TypeContext *type_context = meta->type_context; + // Make a copy of the type context + _PyTier2TypeContext *type_context_copy = _PyTier2TypeContext_Copy(type_context); + if (type_context_copy == NULL) { + return NULL; + } + + _PyTier2BBMetadata *next = _PyTier2_GenerateNextBBMetaWithTypeContext( + frame, + bb_id_tagged, + curr_executing_instr, + jumpby, + tier1_fallback, + bb_flag, + type_context_copy + ); + + if (next == NULL) { + PyMem_Free(type_context_copy); + return NULL; + } + return next; +} + +_Py_CODEUNIT * +_PyTier2_GenerateNextBB( + _PyInterpreterFrame *frame, + uint16_t bb_id_tagged, + _Py_CODEUNIT *curr_executing_instr, + int jumpby, + _Py_CODEUNIT **tier1_fallback, + char bb_flag) +{ + _PyTier2BBMetadata *metadata = _PyTier2_GenerateNextBBMeta( + frame, + bb_id_tagged, + curr_executing_instr, + jumpby, + tier1_fallback, + bb_flag); + if (metadata == NULL) { + return NULL; + } return metadata->tier2_start; } +// Calculates the difference between two type contexts. +// A positive number indicating the distance is returned. +// Incompatible type contexts return INT_MAX. +static int +diff_typecontext(_PyTier2TypeContext *ctx1, _PyTier2TypeContext *ctx2) +{ +#if BB_DEBUG + fprintf(stderr, " [*] Diffing type contexts\n"); + static void print_typestack(const _PyTier2TypeContext * type_context); + print_typestack(ctx1); + print_typestack(ctx2); +#endif + assert(ctx1->type_locals_len == ctx2->type_locals_len); + assert(ctx1->type_stack_len == ctx2->type_stack_len); + int stack_elems1 = (int)(ctx1->type_stack_ptr - ctx1->type_stack); + int stack_elems2 = (int)(ctx2->type_stack_ptr - ctx2->type_stack); + assert(stack_elems1 == stack_elems2); + + int diff = 0; + // Check the difference in the type locals + for (int i = 0; i < ctx1->type_locals_len; i++) { + PyTypeObject *a = typenode_get_type(ctx1->type_locals[i]); + PyTypeObject *b = typenode_get_type(ctx2->type_locals[i]); + // We allow type widening but not narrowing or conversion/casts. + // 1. Int -> Int (bueno, diff + 0) + // 2. Int -> Unknown/NULL (bueno, diff + 1) + // 3. Unknown -> Int (no bueno) + // 4. Int -> Float (no bueno) + + // Case 3. Widening operation. + if (a == NULL && b != NULL) { + return INT_MAX; + } + + // Case 4. Incompatible type conversion. + if (a != b && b != NULL) { + return INT_MAX; + } + + // Case 1 and 2. Diff increases if 2. + diff += (a != b); + } + + // Check the difference in the type stack. + for (int i = 0; i < stack_elems1; i++) { + // Exact same as above. + PyTypeObject *a = typenode_get_type(ctx1->type_locals[i]); + PyTypeObject *b = typenode_get_type(ctx2->type_locals[i]); + + if (a == NULL && b != NULL) { + return INT_MAX; + } + + if (a != b && b != NULL) { + return INT_MAX; + } + + diff += (a != b); + } + return diff; +} + _Py_CODEUNIT * _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id_tagged, int jumpby, _Py_CODEUNIT **tier1_fallback) @@ -1915,11 +2033,14 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id_tagged } // Get type_context of previous BB - _PyTier2TypeContext *type_context = meta->type_context; + _PyTier2TypeContext *curr_type_context = meta->type_context; // Now, find the matching BB _PyTier2Info *t2_info = co->_tier2_info; int jump_offset = (int)(tier1_jump_target - _PyCode_CODE(co)); int matching_bb_id = -1; + int candidate_bb_id = -1; + int min_diff = INT_MAX; + int jump_offset_id = -1; #if BB_DEBUG fprintf(stderr, "finding jump target: %d\n", jump_offset); @@ -1929,22 +2050,62 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id_tagged fprintf(stderr, "jump offset checked: %d\n", t2_info->backward_jump_offsets[i]); #endif if (t2_info->backward_jump_offsets[i] == jump_offset) { + jump_offset_id = i; for (int x = 0; x < MAX_BB_VERSIONS; x++) { + int target_bb_id = t2_info->backward_jump_target_bb_ids[i][x]; + if (target_bb_id >= 0) { + candidate_bb_id = target_bb_id; #if BB_DEBUG - fprintf(stderr, "jump target BB ID: %d\n", - t2_info->backward_jump_target_bb_ids[i][x]); + fprintf(stderr, "candidate jump target BB ID: %d\n", + candidate_bb_id); #endif - // @TODO, this is where the diff function is supposed to be - // it will calculate the closest type context BB - // For now just any valid BB (>= 0) is used. - if (t2_info->backward_jump_target_bb_ids[i][x] >= 0) { - matching_bb_id = t2_info->backward_jump_target_bb_ids[i][x]; - break; + int diff = diff_typecontext(curr_type_context, + co->_tier2_info->bb_data[target_bb_id]->type_context); + if (diff < min_diff) { + min_diff = diff; + matching_bb_id = target_bb_id; + } } } break; } } + assert(jump_offset_id >= 0); + assert(candidate_bb_id >= 0); + // We couldn't find a matching BB to jump to. Time to generate our own. + // This also requires rewriting our backwards jump to a forward jump later. + if (matching_bb_id == -1) { + // We should use the type context occuring at the end of the loop. + _PyTier2TypeContext *copied = _PyTier2TypeContext_Copy(curr_type_context); + if (copied == NULL) { + return NULL; + } + _PyTier2BBMetadata *meta = _PyTier2_GenerateNextBBMetaWithTypeContext( + frame, MAKE_TAGGED_BB_ID(candidate_bb_id, 0), + NULL, + 1, + tier1_fallback, + 0, + copied); + if (meta == NULL) { + PyMem_Free(copied); + return NULL; + } + // Store the metadata in the jump ids. + assert(t2_info->backward_jump_offsets[jump_offset_id] == jump_offset); + bool found = false; + for (int x = 0; x < MAX_BB_VERSIONS; x++) { + int target_bb_id = t2_info->backward_jump_target_bb_ids[jump_offset_id][x]; + // Write to an available space + if (target_bb_id < 0) { + t2_info->backward_jump_target_bb_ids[jump_offset_id][x] = meta->id; + found = true; + break; + } + } + assert(found); + return meta->tier2_start; + } assert(matching_bb_id >= 0); assert(matching_bb_id <= t2_info->bb_data_curr); #if BB_DEBUG @@ -2024,8 +2185,12 @@ _PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *tar // +1 because we increment the PC before JUMPBY int oparg = (int)(target - (jump_backward_lazy + 1)); - assert(oparg < 0); - oparg = -oparg; + assert(oparg != 0); + // Is backwards jump. + bool is_backwards_jump = oparg < 0; + if (is_backwards_jump) { + oparg = -oparg; + } assert(oparg > 0); assert(oparg <= 0xFFFF); @@ -2039,11 +2204,14 @@ _PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *tar _py_set_opcode(write_curr, NOP); write_curr++; } - _py_set_opcode(write_curr, JUMP_BACKWARD_QUICK); + _py_set_opcode(write_curr, is_backwards_jump + ? JUMP_BACKWARD_QUICK + : JUMP_FORWARD); write_curr->op.arg = oparg & 0xFF; write_curr++; _py_set_opcode(write_curr, END_FOR); write_curr++; + return; } #undef TYPESTACK_PEEK diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index 96b514cd096b1e..1f2cfddd0378b2 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -801,8 +801,8 @@ } TARGET(BB_TEST_ITER) { - fprintf(stderr, "Type propagation across `BB_TEST_ITER` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index f299d234993e55..35207912ab2abb 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -55,7 +55,6 @@ # Type propagator shouldn't see these "JUMP_IF_FALSE_OR_POP", "JUMP_IF_TRUE_OR_POP", - "BB_TEST_ITER", "FOR_ITER", "SEND", "SEND_GEN", @@ -361,7 +360,7 @@ def write_typeprop(self, out: Formatter) -> None: ops = typ.ops for op in ops: if not isinstance(src := op.src, TypeSrcStackInput): continue - if oeffect.name in self.unmoved_names and oeffect.name == src.name: + if oeffect.name in self.unmoved_names and oeffect.name == src.name: print( f"Warn: {self.name} type annotation for {oeffect.name} will be ignored " "as it is unmoved") @@ -400,7 +399,7 @@ def write_typeprop(self, out: Formatter) -> None: typ_op = "TYPE_OVERWRITE" dst = f"TYPELOCALS_GET({idx})" match val: - case TypeSrcLiteral(name=valstr): + case TypeSrcLiteral(name=valstr): if valstr == "NULL": src = "(_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT" flag = "true" @@ -438,7 +437,7 @@ def write_typeprop(self, out: Formatter) -> None: # Check if it's even used if oeffect.name == UNUSED: continue - + # Check if there's type info if typ := oeffect.type_annotation: for op in typ.ops: @@ -463,7 +462,7 @@ def write_typeprop(self, out: Formatter) -> None: flag = "false" case _: typing.assert_never(op.src) - + opstr = f"{op.op}({src}, {dst}, {flag})" if oeffect.cond: out.emit(f"if ({oeffect.cond}) {{ {opstr}; }}") @@ -474,7 +473,7 @@ def write_typeprop(self, out: Formatter) -> None: # Don't touch unmoved stack vars if oeffect.name in self.unmoved_names: continue - + # Just output null typ_op = "TYPE_OVERWRITE" src = "(_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT" @@ -661,7 +660,7 @@ def write_typeprop(self, out: Formatter) -> None: ops = typ.ops for op in ops: if not isinstance(src := op.src, TypeSrcStackInput): continue - if oeffect.name in self.unmoved_names and oeffect.name == src.name: + if oeffect.name in self.unmoved_names and oeffect.name == src.name: print( f"Warn: {self.name} type annotation for {oeffect.name} will be ignored " "as it is unmoved") @@ -700,7 +699,7 @@ def write_typeprop(self, out: Formatter) -> None: typ_op = "TYPE_OVERWRITE" dst = f"TYPELOCALS_GET({idx})" match val: - case TypeSrcLiteral(name=valstr): + case TypeSrcLiteral(name=valstr): if valstr == "NULL": src = "(_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT" flag = "true" @@ -738,7 +737,7 @@ def write_typeprop(self, out: Formatter) -> None: # Check if it's even used if oeffect.name == UNUSED: continue - + # Check if there's type info if typ := oeffect.type_annotation: for op in typ.ops: @@ -763,7 +762,7 @@ def write_typeprop(self, out: Formatter) -> None: flag = "false" case _: typing.assert_never(op.src) - + opstr = f"{op.op}({src}, {dst}, {flag})" if oeffect.cond: out.emit(f"if ({oeffect.cond}) {{ {opstr}; }}") @@ -774,7 +773,7 @@ def write_typeprop(self, out: Formatter) -> None: # Don't touch unmoved stack vars if oeffect.name in self.unmoved_names: continue - + # Just output null typ_op = "TYPE_OVERWRITE" src = "(_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT" @@ -1315,7 +1314,7 @@ def write_function( write_function("popped", popped_data) write_function("pushed", pushed_data) self.out.emit("") - + def write_typepropagator(self) -> None: """Write the type propagator""" @@ -1574,7 +1573,7 @@ def write_super_typeprop(self, sup: SuperInstruction) -> None: ... def write_macro_typeprop(self, mac: MacroInstruction) -> None: - # TODO: Make the code emitted more efficient by + # TODO: Make the code emitted more efficient by # combining stack effect name = mac.name self.out.emit("") From d95cdb6aebe875b4b6432137949be2e9fa8e13e9 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed, 29 Mar 2023 21:33:54 +0800 Subject: [PATCH 241/280] Fix backwards jump generation (again) --- Include/cpython/code.h | 9 ++- Python/tier2.c | 164 ++++++++++++++++++++++++++--------------- 2 files changed, 114 insertions(+), 59 deletions(-) diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 4079cd565cfb74..02898cec582f91 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -108,6 +108,13 @@ typedef struct _PyTier2BBSpace { _Py_CODEUNIT u_code[1]; } _PyTier2BBSpace; +typedef struct _PyTier2BBStartTypeContextTriplet { + int id; + _Py_CODEUNIT *tier1_start; + // This is a strong reference. So during cleanup we need to free this. + _PyTier2TypeContext *start_type_context; +} _PyTier2BBStartTypeContextTriplet; + // Tier 2 info stored in the code object. Lazily allocated. typedef struct _PyTier2Info { /* the tier 2 basic block to execute (if any) */ @@ -122,7 +129,7 @@ typedef struct _PyTier2Info { // So backward jump offset [1, 2, 3 ,4] // will have [[BB_ID1, BB_ID2], [BB_ID3,], [], []] // etc. - int **backward_jump_target_bb_ids; + _PyTier2BBStartTypeContextTriplet **backward_jump_target_bb_pairs; // Max len of bb_data int bb_data_len; // Current index to write into in bb_data. Incremented after each write. diff --git a/Python/tier2.c b/Python/tier2.c index 2bd8d756539259..58547035d9fea4 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -614,12 +614,6 @@ allocate_bb_metadata(PyCodeObject *co, _Py_CODEUNIT *tier2_start, return metadata; } -static int -update_backward_jump_target_bb_ids(PyCodeObject *co, _PyTier2BBMetadata *metadata) -{ - assert(co->_tier2_info != NULL); - -} // Writes BB metadata to code object's tier2info bb_data field. // 0 on success, 1 on error. @@ -1081,7 +1075,8 @@ IS_BACKWARDS_JUMP_TARGET(PyCodeObject *co, _Py_CODEUNIT *curr) // 1 for error, 0 for success. static inline int add_metadata_to_jump_2d_array(_PyTier2Info *t2_info, _PyTier2BBMetadata *meta, - int backwards_jump_target) + int backwards_jump_target, _PyTier2TypeContext *starting_context, + _Py_CODEUNIT *tier1_start) { // Locate where to insert the BB ID int backward_jump_offset_index = 0; @@ -1098,8 +1093,12 @@ add_metadata_to_jump_2d_array(_PyTier2Info *t2_info, _PyTier2BBMetadata *meta, int jump_i = 0; found = false; for (; jump_i < MAX_BB_VERSIONS; jump_i++) { - if (t2_info->backward_jump_target_bb_ids[backward_jump_offset_index][jump_i] == -1) { - t2_info->backward_jump_target_bb_ids[backward_jump_offset_index][jump_i] = meta->id; + if (t2_info->backward_jump_target_bb_pairs[backward_jump_offset_index][jump_i].id == + -1) { + t2_info->backward_jump_target_bb_pairs[backward_jump_offset_index][jump_i].id = + meta->id; + t2_info->backward_jump_target_bb_pairs[backward_jump_offset_index][jump_i].start_type_context = starting_context; + t2_info->backward_jump_target_bb_pairs[backward_jump_offset_index][jump_i].tier1_start = tier1_start; found = true; break; } @@ -1148,15 +1147,17 @@ infer_BINARY_OP_ADD( } } // Unknown, time to emit the chain of guards. - write_curr = rebox_stack(write_curr, type_context, 2); - *needs_guard = true; if (prev_type_guard == NULL) { + write_curr = rebox_stack(write_curr, type_context, 2); + *needs_guard = true; return emit_type_guard(write_curr, BINARY_CHECK_INT, bb_id); } else { int next_guard = type_guard_ladder[ type_guard_to_index[prev_type_guard->op.code] + 1]; if (next_guard != -1) { + write_curr = rebox_stack(write_curr, type_context, 2); + *needs_guard = true; return emit_type_guard(write_curr, next_guard, bb_id); } // End of ladder, fall through @@ -1205,6 +1206,13 @@ _PyTier2_Code_DetectAndEmitBB( i += caches; \ type_propagate(opcode, oparg, starting_type_context, consts); \ continue; + +#define DISPATCH_REBOX(x) write_i = rebox_stack(write_i, starting_type_context, x); \ + write_i = emit_i(write_i, specop, oparg); \ + write_i = copy_cache_entries(write_i, curr+1, caches); \ + i += caches; \ + type_propagate(opcode, oparg, starting_type_context, consts); \ + continue; #define DISPATCH_GOTO() goto dispatch_opcode; #define TYPECONST_GET_RAWTYPE(idx) Py_TYPE(PyTuple_GET_ITEM(consts, idx)) @@ -1228,6 +1236,8 @@ _PyTier2_Code_DetectAndEmitBB( bool starts_with_backwards_jump_target = false; int backwards_jump_target_offset = -1; bool virtual_start = false; + _PyTier2TypeContext *start_type_context_copy = NULL; + _Py_CODEUNIT *virtual_tier1_start = NULL; // A meta-interpreter for types. Py_ssize_t i = (tier1_start - _PyCode_CODE(co)); @@ -1354,18 +1364,12 @@ _PyTier2_Code_DetectAndEmitBB( } // Need to handle reboxing at these boundaries. case CALL: - write_i = rebox_stack(write_i, starting_type_context, - oparg + 2); - DISPATCH(); + DISPATCH_REBOX(oparg + 2); case BUILD_MAP: - write_i = rebox_stack(write_i, starting_type_context, - oparg * 2); - DISPATCH(); + DISPATCH_REBOX(oparg * 2); case BUILD_STRING: case BUILD_LIST: - write_i = rebox_stack(write_i, starting_type_context, - oparg); - DISPATCH(); + DISPATCH_REBOX(oparg); case BINARY_OP: if (oparg == NB_ADD) { // Add operation. Need to check if we can infer types. @@ -1375,8 +1379,7 @@ _PyTier2_Code_DetectAndEmitBB( write_i, starting_type_context, co->_tier2_info->bb_data_curr); if (possible_next == NULL) { - write_i = rebox_stack(write_i, starting_type_context, 2); - DISPATCH() + DISPATCH_REBOX(2); } write_i = possible_next; if (needs_guard) { @@ -1389,24 +1392,20 @@ _PyTier2_Code_DetectAndEmitBB( i += caches; continue; } - write_i = rebox_stack(write_i, starting_type_context, 2); - DISPATCH() + DISPATCH_REBOX(2); case LOAD_ATTR: case CALL_INTRINSIC_1: case UNARY_NEGATIVE: case UNARY_NOT: case UNARY_INVERT: case GET_LEN: - write_i = rebox_stack(write_i, starting_type_context, 1); - DISPATCH(); + DISPATCH_REBOX(1); case CALL_INTRINSIC_2: case BINARY_SUBSCR: case BINARY_SLICE: - write_i = rebox_stack(write_i, starting_type_context, 2); - DISPATCH(); + DISPATCH_REBOX(2); case STORE_SLICE: - write_i = rebox_stack(write_i, starting_type_context, 4); - DISPATCH(); + DISPATCH_REBOX(4); default: #if BB_DEBUG && !TYPEPROP_DEBUG fprintf(stderr, "offset: %Id\n", curr - _PyCode_CODE(co)); @@ -1424,6 +1423,12 @@ _PyTier2_Code_DetectAndEmitBB( starts_with_backwards_jump_target = true; backwards_jump_target_offset = (int)(curr - _PyCode_CODE(co)); virtual_start = false; + start_type_context_copy = _PyTier2TypeContext_Copy(starting_type_context); + virtual_tier1_start = _PyCode_CODE(co) + i; + if (start_type_context_copy == NULL) { + _PyTier2TypeContext_Free(starting_type_context); + return NULL; + } goto fall_through; } #if TYPEPROP_DEBUG @@ -1432,12 +1437,11 @@ _PyTier2_Code_DetectAndEmitBB( // Else, create a virtual end to the basic block. // But generate the block after that so it can fall through. i--; - // Make a copy of the type context _PyTier2TypeContext *type_context_copy = _PyTier2TypeContext_Copy(starting_type_context); if (type_context_copy == NULL) { return NULL; } - jump_end_meta = meta = _PyTier2_AllocateBBMetaData(co, + meta = _PyTier2_AllocateBBMetaData(co, t2_start, _PyCode_CODE(co) + i, type_context_copy); if (meta == NULL) { _PyTier2TypeContext_Free(type_context_copy); @@ -1502,9 +1506,11 @@ _PyTier2_Code_DetectAndEmitBB( } if (starts_with_backwards_jump_target) { // Add the basic block to the jump ids - assert(jump_end_meta != NULL); - if (add_metadata_to_jump_2d_array(t2_info, jump_end_meta, - backwards_jump_target_offset) < 0) { + assert(start_type_context_copy != NULL); + assert(virtual_tier1_start != NULL); + if (add_metadata_to_jump_2d_array(t2_info, temp_meta, + backwards_jump_target_offset, start_type_context_copy, + virtual_tier1_start) < 0) { PyMem_Free(meta); if (meta != temp_meta) { PyMem_Free(temp_meta); @@ -1534,24 +1540,26 @@ compare_ints(const void *a, const void *b) } static int -allocate_jump_offset_2d_array(int backwards_jump_count, int **backward_jump_target_bb_ids) +allocate_jump_offset_2d_array(int backwards_jump_count, + _PyTier2BBStartTypeContextTriplet **backward_jump_target_bb_pairs) { int done = 0; for (int i = 0; i < backwards_jump_count; i++) { - int *jump_offsets = PyMem_Malloc(sizeof(int) * MAX_BB_VERSIONS); - if (jump_offsets == NULL) { + _PyTier2BBStartTypeContextTriplet *pair = + PyMem_Malloc(sizeof(_PyTier2BBStartTypeContextTriplet) * MAX_BB_VERSIONS); + if (pair == NULL) { goto error; } for (int i = 0; i < MAX_BB_VERSIONS; i++) { - jump_offsets[i] = -1; + pair[i].id = -1; } done++; - backward_jump_target_bb_ids[i] = jump_offsets; + backward_jump_target_bb_pairs[i] = pair; } return 0; error: for (int i = 0; i < done; i++) { - PyMem_Free(backward_jump_target_bb_ids[i]); + PyMem_Free(backward_jump_target_bb_pairs[i]); } return 1; } @@ -1589,15 +1597,16 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) if (backward_jump_offsets == NULL) { return 1; } - int **backward_jump_target_bb_ids = PyMem_Malloc(backwards_jump_count * sizeof(int *)); - if (backward_jump_target_bb_ids == NULL) { + _PyTier2BBStartTypeContextTriplet **backward_jump_target_bb_pairs = + PyMem_Malloc(backwards_jump_count * sizeof(_PyTier2BBStartTypeContextTriplet *)); + if (backward_jump_target_bb_pairs == NULL) { PyMem_Free(backward_jump_offsets); return 1; } if (allocate_jump_offset_2d_array((int)backwards_jump_count, - backward_jump_target_bb_ids)) { + backward_jump_target_bb_pairs)) { PyMem_Free(backward_jump_offsets); - PyMem_Free(backward_jump_target_bb_ids); + PyMem_Free(backward_jump_target_bb_pairs); return 1; } @@ -1623,6 +1632,18 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) assert(curr_i == backwards_jump_count); qsort(backward_jump_offsets, backwards_jump_count, sizeof(int), compare_ints); + // Deduplicate + int backwards_jump_count_new = backwards_jump_count; + for (int i = 0; i < backwards_jump_count - 1; i++) { + for (int x = i + 1; x < backwards_jump_count; x++) { + if (backward_jump_offsets[i] == backward_jump_offsets[x]) { + backward_jump_offsets[x] = -1; + backwards_jump_count_new--; + } + } + } + qsort(backward_jump_offsets, backwards_jump_count, + sizeof(int), compare_ints); #if BB_DEBUG fprintf(stderr, "BACKWARD JUMP COUNT : %Id\n", backwards_jump_count); fprintf(stderr, "BACKWARD JUMP TARGET OFFSETS (FROM START OF CODE): "); @@ -1633,7 +1654,7 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) #endif co->_tier2_info->backward_jump_count = (int)backwards_jump_count; co->_tier2_info->backward_jump_offsets = backward_jump_offsets; - co->_tier2_info->backward_jump_target_bb_ids = backward_jump_target_bb_ids; + co->_tier2_info->backward_jump_target_bb_pairs = backward_jump_target_bb_pairs; return 0; } @@ -1841,13 +1862,15 @@ _PyTier2_GenerateNextBBMetaWithTypeContext( int jumpby, _Py_CODEUNIT **tier1_fallback, char bb_flag, - _PyTier2TypeContext *type_context_copy) + _PyTier2TypeContext *type_context_copy, + _Py_CODEUNIT *custom_tier1_end) { PyCodeObject *co = frame->f_code; assert(co->_tier2_info != NULL); assert(BB_ID(bb_id_tagged) <= co->_tier2_info->bb_data_curr); _PyTier2BBMetadata *meta = co->_tier2_info->bb_data[BB_ID(bb_id_tagged)]; - _Py_CODEUNIT *tier1_end = meta->tier1_end + jumpby; + _Py_CODEUNIT *tier1_end = custom_tier1_end == NULL + ? meta->tier1_end + jumpby : custom_tier1_end; *tier1_fallback = tier1_end; // Be a pessimist and assume we need to write the entire rest of code into the BB. // The size of the BB generated will definitely be equal to or smaller than this. @@ -1916,7 +1939,8 @@ _PyTier2_GenerateNextBBMeta( jumpby, tier1_fallback, bb_flag, - type_context_copy + type_context_copy, + NULL ); if (next == NULL) { @@ -1954,6 +1978,8 @@ _PyTier2_GenerateNextBB( static int diff_typecontext(_PyTier2TypeContext *ctx1, _PyTier2TypeContext *ctx2) { + assert(ctx1 != NULL); + assert(ctx2 != NULL); #if BB_DEBUG fprintf(stderr, " [*] Diffing type contexts\n"); static void print_typestack(const _PyTier2TypeContext * type_context); @@ -1976,6 +2002,7 @@ diff_typecontext(_PyTier2TypeContext *ctx1, _PyTier2TypeContext *ctx2) // 2. Int -> Unknown/NULL (bueno, diff + 1) // 3. Unknown -> Int (no bueno) // 4. Int -> Float (no bueno) + // 5. Unboxed type -> Unknown/Boxed type (no bueno) // Case 3. Widening operation. if (a == NULL && b != NULL) { @@ -1987,6 +2014,11 @@ diff_typecontext(_PyTier2TypeContext *ctx1, _PyTier2TypeContext *ctx2) return INT_MAX; } + // Case 5. Boxed to unboxed conversion. + if (is_unboxed_type(a) && a != b) { + return INT_MAX; + } + // Case 1 and 2. Diff increases if 2. diff += (a != b); } @@ -1994,8 +2026,8 @@ diff_typecontext(_PyTier2TypeContext *ctx1, _PyTier2TypeContext *ctx2) // Check the difference in the type stack. for (int i = 0; i < stack_elems1; i++) { // Exact same as above. - PyTypeObject *a = typenode_get_type(ctx1->type_locals[i]); - PyTypeObject *b = typenode_get_type(ctx2->type_locals[i]); + PyTypeObject *a = typenode_get_type(ctx1->type_stack[i]); + PyTypeObject *b = typenode_get_type(ctx2->type_stack[i]); if (a == NULL && b != NULL) { return INT_MAX; @@ -2005,6 +2037,11 @@ diff_typecontext(_PyTier2TypeContext *ctx1, _PyTier2TypeContext *ctx2) return INT_MAX; } + // Case 5. Boxed to unboxed conversion. + if (is_unboxed_type(a) && a != b) { + return INT_MAX; + } + diff += (a != b); } return diff; @@ -2041,6 +2078,7 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id_tagged int candidate_bb_id = -1; int min_diff = INT_MAX; int jump_offset_id = -1; + _Py_CODEUNIT *candidate_bb_tier1_start = NULL; #if BB_DEBUG fprintf(stderr, "finding jump target: %d\n", jump_offset); @@ -2052,15 +2090,16 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id_tagged if (t2_info->backward_jump_offsets[i] == jump_offset) { jump_offset_id = i; for (int x = 0; x < MAX_BB_VERSIONS; x++) { - int target_bb_id = t2_info->backward_jump_target_bb_ids[i][x]; + int target_bb_id = t2_info->backward_jump_target_bb_pairs[i][x].id; if (target_bb_id >= 0) { candidate_bb_id = target_bb_id; + candidate_bb_tier1_start = t2_info->backward_jump_target_bb_pairs[i][x].tier1_start; #if BB_DEBUG fprintf(stderr, "candidate jump target BB ID: %d\n", candidate_bb_id); #endif int diff = diff_typecontext(curr_type_context, - co->_tier2_info->bb_data[target_bb_id]->type_context); + t2_info->backward_jump_target_bb_pairs[i][x].start_type_context); if (diff < min_diff) { min_diff = diff; matching_bb_id = target_bb_id; @@ -2072,6 +2111,7 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id_tagged } assert(jump_offset_id >= 0); assert(candidate_bb_id >= 0); + assert(candidate_bb_tier1_start != NULL); // We couldn't find a matching BB to jump to. Time to generate our own. // This also requires rewriting our backwards jump to a forward jump later. if (matching_bb_id == -1) { @@ -2080,25 +2120,33 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id_tagged if (copied == NULL) { return NULL; } + _PyTier2TypeContext *second_copy = _PyTier2TypeContext_Copy(curr_type_context); + if (second_copy == NULL) { + return NULL; + } _PyTier2BBMetadata *meta = _PyTier2_GenerateNextBBMetaWithTypeContext( frame, MAKE_TAGGED_BB_ID(candidate_bb_id, 0), NULL, - 1, + 0, tier1_fallback, 0, - copied); + copied, + candidate_bb_tier1_start); if (meta == NULL) { - PyMem_Free(copied); + _PyTier2TypeContext_Free(copied); + _PyTier2TypeContext_Free(second_copy); return NULL; } // Store the metadata in the jump ids. assert(t2_info->backward_jump_offsets[jump_offset_id] == jump_offset); bool found = false; for (int x = 0; x < MAX_BB_VERSIONS; x++) { - int target_bb_id = t2_info->backward_jump_target_bb_ids[jump_offset_id][x]; + int target_bb_id = t2_info->backward_jump_target_bb_pairs[jump_offset_id][x].id; // Write to an available space if (target_bb_id < 0) { - t2_info->backward_jump_target_bb_ids[jump_offset_id][x] = meta->id; + t2_info->backward_jump_target_bb_pairs[jump_offset_id][x].id = meta->id; + t2_info->backward_jump_target_bb_pairs[jump_offset_id][x].start_type_context = second_copy; + t2_info->backward_jump_target_bb_pairs[jump_offset_id][x].tier1_start = candidate_bb_tier1_start; found = true; break; } From 3c2ac64f1669f53a1efee383b9cdc7631857275a Mon Sep 17 00:00:00 2001 From: Jules <57632293+JuliaPoo@users.noreply.github.com> Date: Thu, 30 Mar 2023 01:06:09 +0800 Subject: [PATCH 242/280] Fix: Buggy type propagation across SWAP (#30) --- Python/tier2.c | 79 ++++++++++++++++++ Python/tier2_typepropagator.c.h | 104 ------------------------ Tools/cases_generator/generate_cases.py | 22 ++--- 3 files changed, 84 insertions(+), 121 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index 58547035d9fea4..07adcdfdca1b12 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -376,6 +376,74 @@ __type_propagate_TYPE_OVERWRITE( } } +// src and dst are assumed to already be within the type context +static void +__type_propagate_TYPE_SWAP( + _PyTier2TypeContext *type_context, + _Py_TYPENODE_t *src, _Py_TYPENODE_t *dst) +{ + // Check if they are the same tree + _Py_TYPENODE_t *srcrootref = src; + _Py_TYPENODE_t *dstrootref = dst; + uintptr_t dsttag = _Py_TYPENODE_GET_TAG(*dst); + uintptr_t srctag = _Py_TYPENODE_GET_TAG(*src); + switch (dsttag) { + case TYPE_REF: dstrootref = __typenode_get_rootptr(*dst); + case TYPE_ROOT: + switch (srctag) { + case TYPE_REF: srcrootref = __typenode_get_rootptr(*src); + case TYPE_ROOT: + if (srcrootref == dstrootref) { + // Same tree, no point swapping + return; + } + break; + default: + Py_UNREACHABLE(); + } + break; + default: + Py_UNREACHABLE(); + } + + // src and dst are different tree, + // Make all children of src be children of dst and vice versa + + _Py_TYPENODE_t src_child_test = _Py_TYPENODE_MAKE_REF( + _Py_TYPENODE_CLEAR_TAG((_Py_TYPENODE_t)src)); + _Py_TYPENODE_t dst_child_test = _Py_TYPENODE_MAKE_REF( + _Py_TYPENODE_CLEAR_TAG((_Py_TYPENODE_t)dst)); + + // Search locals for children + int nlocals = type_context->type_locals_len; + for (int i = 0; i < nlocals; i++) { + _Py_TYPENODE_t *node_ptr = &(type_context->type_locals[i]); + if (*node_ptr == src_child_test) { + *node_ptr = dst_child_test; + } + else if (*node_ptr == dst_child_test) { + *node_ptr = src_child_test; + } + } + + // Search stack for children + int nstack = type_context->type_stack_len; + for (int i = 0; i < nstack; i++) { + _Py_TYPENODE_t *node_ptr = &(type_context->type_stack[i]); + if (*node_ptr == src_child_test) { + *node_ptr = dst_child_test; + } + else if (*node_ptr == dst_child_test) { + *node_ptr = src_child_test; + } + } + + // Finally, actually swap the nodes + *src ^= *dst; + *dst ^= *src; + *src ^= *dst; +} + static void __type_stack_shrink(_Py_TYPENODE_t **type_stackptr, int idx) { @@ -489,6 +557,7 @@ type_propagate( #define TYPE_SET(src, dst, flag) __type_propagate_TYPE_SET((src), (dst), (flag)) #define TYPE_OVERWRITE(src, dst, flag) __type_propagate_TYPE_OVERWRITE(type_context, (src), (dst), (flag)) +#define TYPE_SWAP(src, dst) __type_propagate_TYPE_SWAP(type_context, (src), (dst)) #define STACK_GROW(idx) *type_stackptr += (idx) @@ -504,8 +573,18 @@ type_propagate( switch (opcode) { #include "tier2_typepropagator.c.h" + TARGET(SWAP) { + _Py_TYPENODE_t *top = TYPESTACK_PEEK(1); + _Py_TYPENODE_t * bottom = TYPESTACK_PEEK(2 + (oparg - 2)); + TYPE_SWAP(top, bottom); + break; + } default: +#ifdef Py_DEBUG + fprintf(stderr, "Unsupported opcode in type propagator: %s : %d\n", _PyOpcode_OpName[opcode], oparg); +#else fprintf(stderr, "Unsupported opcode in type propagator: %d\n", opcode); +#endif Py_UNREACHABLE(); } diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index 1f2cfddd0378b2..9c645df9007b0b 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -284,12 +284,6 @@ break; } - TARGET(RAISE_VARARGS) { - fprintf(stderr, "Type propagation across `RAISE_VARARGS` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - TARGET(INTERPRETER_EXIT) { STACK_SHRINK(1); break; @@ -320,36 +314,6 @@ break; } - TARGET(SEND) { - fprintf(stderr, "Type propagation across `SEND` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - - TARGET(SEND_GEN) { - fprintf(stderr, "Type propagation across `SEND_GEN` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - - TARGET(YIELD_VALUE) { - fprintf(stderr, "Type propagation across `YIELD_VALUE` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - - TARGET(POP_EXCEPT) { - fprintf(stderr, "Type propagation across `POP_EXCEPT` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - - TARGET(RERAISE) { - fprintf(stderr, "Type propagation across `RERAISE` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - TARGET(END_ASYNC_FOR) { STACK_SHRINK(2); break; @@ -464,18 +428,6 @@ break; } - TARGET(DELETE_FAST) { - fprintf(stderr, "Type propagation across `DELETE_FAST` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - - TARGET(MAKE_CELL) { - fprintf(stderr, "Type propagation across `MAKE_CELL` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - TARGET(DELETE_DEREF) { break; } @@ -486,12 +438,6 @@ break; } - TARGET(LOAD_DEREF) { - fprintf(stderr, "Type propagation across `LOAD_DEREF` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - TARGET(STORE_DEREF) { STACK_SHRINK(1); break; @@ -766,24 +712,6 @@ break; } - TARGET(MATCH_MAPPING) { - fprintf(stderr, "Type propagation across `MATCH_MAPPING` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - - TARGET(MATCH_SEQUENCE) { - fprintf(stderr, "Type propagation across `MATCH_SEQUENCE` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - - TARGET(MATCH_KEYS) { - fprintf(stderr, "Type propagation across `MATCH_KEYS` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - TARGET(GET_ITER) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; @@ -794,12 +722,6 @@ break; } - TARGET(FOR_ITER) { - fprintf(stderr, "Type propagation across `FOR_ITER` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - TARGET(BB_TEST_ITER) { STACK_GROW(1); TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); @@ -843,18 +765,6 @@ break; } - TARGET(WITH_EXCEPT_START) { - fprintf(stderr, "Type propagation across `WITH_EXCEPT_START` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - - TARGET(PUSH_EXC_INFO) { - fprintf(stderr, "Type propagation across `PUSH_EXC_INFO` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - TARGET(LOAD_ATTR_METHOD_WITH_VALUES) { STACK_GROW(((oparg & 1) ? 1 : 0)); TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); @@ -1045,20 +955,6 @@ break; } - TARGET(SWAP) { - _Py_TYPENODE_t *top = TYPESTACK_PEEK(1); - _Py_TYPENODE_t *bottom = TYPESTACK_PEEK(2 + (oparg-2)); - TYPE_OVERWRITE(bottom, TYPESTACK_PEEK(1), false); - TYPE_OVERWRITE(top, TYPESTACK_PEEK(2 + (oparg-2)), false); - break; - } - - TARGET(EXTENDED_ARG) { - fprintf(stderr, "Type propagation across `EXTENDED_ARG` shouldn't be handled statically!\n"); - Py_UNREACHABLE(); - break; - } - TARGET(CACHE) { break; } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 35207912ab2abb..1255ba463f5a8b 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -53,9 +53,9 @@ TYPE_PROPAGATOR_FORBIDDEN = [ # Type propagator shouldn't see these - "JUMP_IF_FALSE_OR_POP", - "JUMP_IF_TRUE_OR_POP", "FOR_ITER", + "SWAP", + # Not supported "SEND", "SEND_GEN", "YIELD_VALUE", @@ -71,12 +71,6 @@ "MATCH_KEYS", "EXTENDED_ARG", "WITH_EXCEPT_START", - # Type propagation across these instructions are forbidden - # due to conditional effects that can't be determined statically - # The handling of type propagation across these opcodes are handled elsewhere - # within tier2. - "BB_TEST_IF_FALSE_OR_POP", - "BB_TEST_IF_TRUE_OR_POP" # Type propagator handles this in BB_BRANCH ] arg_parser = argparse.ArgumentParser( @@ -344,10 +338,7 @@ def __init__(self, inst: parser.InstDef): def write_typeprop(self, out: Formatter) -> None: """Write one instruction's type propagation rules""" - if self.name in TYPE_PROPAGATOR_FORBIDDEN: - out.emit(f'fprintf(stderr, "Type propagation across `{self.name}` shouldn\'t be handled statically!\\n");') - out.emit("Py_UNREACHABLE();") - return + # TODO: Detect loops like in SWAP need_to_declare = [] # Stack input is used in local effect @@ -644,11 +635,6 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None def write_typeprop(self, out: Formatter) -> None: """Write one instruction's type propagation rules""" - if self.name in TYPE_PROPAGATOR_FORBIDDEN: - out.emit(f'fprintf(stderr, "Type propagation across `{self.name}` shouldn\'t be handled statically!\\n");') - out.emit("Py_UNREACHABLE();") - return - need_to_declare = [] # Stack input is used in local effect if self.local_effects and \ @@ -1328,6 +1314,8 @@ def write_typepropagator(self) -> None: self.out = Formatter(f, 8) for thing in self.everything: + if thing.name in TYPE_PROPAGATOR_FORBIDDEN: + continue match thing: case parser.InstDef(kind=kind, name=name): match kind: From 6bade7bcf3955da069216d5dc801d63be0449284 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu, 30 Mar 2023 01:30:01 +0800 Subject: [PATCH 243/280] More support for EXTENDED_ARGS --- Include/internal/pycore_code.h | 2 +- Lib/dis.py | 12 ++++- Python/bytecodes.c | 2 +- Python/generated_cases.c.h | 2 +- Python/tier2.c | 89 +++++++++++++++++++++------------- 5 files changed, 70 insertions(+), 37 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 55c8bd9cd4227a..0f8d9f7808153f 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -282,7 +282,7 @@ extern _Py_CODEUNIT *_PyTier2_GenerateNextBB( char bb_flag); extern _Py_CODEUNIT *_PyTier2_LocateJumpBackwardsBB( struct _PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, - _Py_CODEUNIT **tier1_fallback); + _Py_CODEUNIT **tier1_fallback, _Py_CODEUNIT *curr); extern void _PyTier2_RewriteForwardJump(_Py_CODEUNIT *bb_branch, _Py_CODEUNIT *target); extern void _PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *target); #ifdef Py_STATS diff --git a/Lib/dis.py b/Lib/dis.py index 5475c404858991..65fd696012718f 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -58,6 +58,7 @@ _empty_slot = [slot for slot, name in enumerate(_all_opname) if name.startswith("<")] for uop_opcode, uop in zip(_empty_slot, _uops): _all_opname[uop_opcode] = uop + _all_opmap[uop] = uop_opcode if uop.startswith('BB_BRANCH') or uop.startswith('BB_JUMP'): if uop.startswith('BB_JUMP'): _bb_jumps.append(uop_opcode) @@ -69,6 +70,15 @@ specialized: base for base, family in _specializations.items() for specialized in family } +_TIER2_STORE_OPS = ( + # 'LOAD_FAST_NO_INCREF', + # 'STORE_FAST_BOXED_UNBOXED', + # 'STORE_FAST_UNBOXED_BOXED', + # 'STORE_FAST_UNBOXED_UNBOXED', +) +for store_op in ([_all_opmap[op] for op in _TIER2_STORE_OPS]): + hasname.append(store_op) + hasarg.append(store_op) def _try_compile(source, name): """Attempts to compile the given source, first as an expression and then as a statement if the first approach fails. @@ -442,7 +452,7 @@ def _parse_exception_table(code): return entries def _is_backward_jump(op): - return 'JUMP_BACKWARD' in opname[op] + return 'JUMP_BACKWARD' in opname[op] or 'JUMP_BACKWARD_QUICK' in opname[op] def _get_instructions_bytes(code, varname_from_oparg=None, names=None, co_consts=None, diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 0aa87a4a93d16a..76bbb5e566567d 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3276,7 +3276,7 @@ dummy_func( _Py_CODEUNIT *tier1_fallback = NULL; t2_nextinstr = _PyTier2_LocateJumpBackwardsBB( - frame, cache->bb_id_tagged, -oparg, &tier1_fallback); + frame, cache->bb_id_tagged, -oparg, &tier1_fallback, curr); if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index c2d46d5e4dcab6..00601c8800259c 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -4153,7 +4153,7 @@ _Py_CODEUNIT *tier1_fallback = NULL; t2_nextinstr = _PyTier2_LocateJumpBackwardsBB( - frame, cache->bb_id_tagged, -oparg, &tier1_fallback); + frame, cache->bb_id_tagged, -oparg, &tier1_fallback, curr); if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; diff --git a/Python/tier2.c b/Python/tier2.c index 07adcdfdca1b12..32c75f8eb65de4 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -12,8 +12,8 @@ #define TYPEPROP_DEBUG 1 // Max typed version basic blocks per basic block #define MAX_BB_VERSIONS 5 -// Number of potential extra instructions at end of a BB, for branch or cleanup purposes. -#define BB_EPILOG 0 + +#define OVERALLOCATE_FACTOR 4 /* Dummy types used by the types propagator */ @@ -1336,14 +1336,6 @@ _PyTier2_Code_DetectAndEmitBB( fprintf(stderr, "offset: %Id\n", curr - _PyCode_CODE(co)); #endif switch (opcode) { - case EXTENDED_ARG: - specop = next_instr->op.code; - opcode = _PyOpcode_Deopt[specop]; - oparg = oparg << 8 | next_instr->op.arg; - curr++; - next_instr++; - i+=2; - DISPATCH_GOTO(); case RESUME: opcode = specop = RESUME_QUICK; DISPATCH(); @@ -1489,27 +1481,26 @@ _PyTier2_Code_DetectAndEmitBB( #if BB_DEBUG && !TYPEPROP_DEBUG fprintf(stderr, "offset: %Id\n", curr - _PyCode_CODE(co)); #endif - if (IS_BACKWARDS_JUMP_TARGET(co, curr)) { + // This should be the end of another basic block, or the start of a new. + // Start of a new basic block, just ignore and continue. + if (virtual_start) { #if BB_DEBUG - fprintf(stderr, "Encountered a backward jump target\n"); + fprintf(stderr, "Emitted virtual start of basic block\n"); #endif - // This should be the end of another basic block, or the start of a new. - // Start of a new basic block, just ignore and continue. - if (virtual_start) { + starts_with_backwards_jump_target = true; + virtual_start = false; + start_type_context_copy = _PyTier2TypeContext_Copy(starting_type_context); + if (start_type_context_copy == NULL) { + _PyTier2TypeContext_Free(starting_type_context); + return NULL; + } + goto fall_through; + } + if (IS_BACKWARDS_JUMP_TARGET(co, curr)) { +backward_jump_target: #if BB_DEBUG - fprintf(stderr, "Emitted virtual start of basic block\n"); + fprintf(stderr, "Encountered a backward jump target\n"); #endif - starts_with_backwards_jump_target = true; - backwards_jump_target_offset = (int)(curr - _PyCode_CODE(co)); - virtual_start = false; - start_type_context_copy = _PyTier2TypeContext_Copy(starting_type_context); - virtual_tier1_start = _PyCode_CODE(co) + i; - if (start_type_context_copy == NULL) { - _PyTier2TypeContext_Free(starting_type_context); - return NULL; - } - goto fall_through; - } #if TYPEPROP_DEBUG print_typestack(starting_type_context); #endif @@ -1530,8 +1521,20 @@ _PyTier2_Code_DetectAndEmitBB( // Reset all our values t2_start = write_i; i++; + virtual_tier1_start = _PyCode_CODE(co) + i; + backwards_jump_target_offset = (int)(curr - _PyCode_CODE(co)); virtual_start = true; + if (opcode == EXTENDED_ARG) { + // Note: EXTENDED_ARG could be a jump target!!!!! + caches = _PyOpcode_Caches[opcode]; + specop = next_instr->op.code; + opcode = _PyOpcode_Deopt[specop]; + oparg = oparg << 8 | next_instr->op.arg; + curr++; + next_instr++; + i += 2; + } // Don't change opcode or oparg, let us handle it again. DISPATCH_GOTO(); } @@ -1558,6 +1561,17 @@ _PyTier2_Code_DetectAndEmitBB( i += caches; END(); } + if (opcode == EXTENDED_ARG) { + // Note: EXTENDED_ARG could be a jump target!!!!! + caches = _PyOpcode_Caches[opcode]; + specop = next_instr->op.code; + opcode = _PyOpcode_Deopt[specop]; + oparg = oparg << 8 | next_instr->op.arg; + curr++; + next_instr++; + i += 2; + DISPATCH_GOTO(); + } DISPATCH(); } @@ -1691,11 +1705,12 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) _Py_CODEUNIT *start = _PyCode_CODE(co); int curr_i = 0; + int oparg = 0; for (Py_ssize_t i = 0; i < Py_SIZE(co); i++) { _Py_CODEUNIT *curr = start + i; - _Py_CODEUNIT instr = *curr; - int opcode = _PyOpcode_Deopt[_Py_OPCODE(instr)]; - int oparg = _Py_OPARG(instr); + int opcode = _PyOpcode_Deopt[curr->op.code]; + oparg = curr->op.arg; + dispatch_same_oparg: if (IS_JUMP_BACKWARDS_OPCODE(opcode)) { // + 1 because it's calculated from nextinstr (see JUMPBY in ceval.c) _Py_CODEUNIT *target = curr + 1 - oparg; @@ -1706,6 +1721,13 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) backward_jump_offsets[curr_i] = (int)(target - start); curr_i++; } + else if (opcode == EXTENDED_ARG) { + oparg = oparg << 8 | (curr+1)->op.arg; + opcode = _PyOpcode_Deopt[(curr+1)->op.code]; + i++; + curr++; + goto dispatch_same_oparg; + } i += _PyOpcode_Caches[opcode]; } assert(curr_i == backwards_jump_count); @@ -1868,7 +1890,7 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) fprintf(stderr, "INITIALIZING\n"); #endif - Py_ssize_t space_to_alloc = (_PyCode_NBYTES(co)) * 3; + Py_ssize_t space_to_alloc = (_PyCode_NBYTES(co)) * OVERALLOCATE_FACTOR; _PyTier2BBSpace *bb_space = _PyTier2_CreateBBSpace(space_to_alloc); if (bb_space == NULL) { @@ -2128,14 +2150,15 @@ diff_typecontext(_PyTier2TypeContext *ctx1, _PyTier2TypeContext *ctx2) _Py_CODEUNIT * _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id_tagged, int jumpby, - _Py_CODEUNIT **tier1_fallback) + _Py_CODEUNIT **tier1_fallback, + _Py_CODEUNIT *curr) { PyCodeObject *co = frame->f_code; assert(co->_tier2_info != NULL); assert(BB_ID(bb_id_tagged) <= co->_tier2_info->bb_data_curr); _PyTier2BBMetadata *meta = co->_tier2_info->bb_data[BB_ID(bb_id_tagged)]; // The jump target - _Py_CODEUNIT *tier1_jump_target = meta->tier1_end + jumpby; + _Py_CODEUNIT *tier1_jump_target = meta->tier1_end + jumpby - ((curr-1)->op.code == EXTENDED_ARG && (curr-1)->op.arg > 0); *tier1_fallback = tier1_jump_target; // Be a pessimist and assume we need to write the entire rest of code into the BB. // The size of the BB generated will definitely be equal to or smaller than this. From 10fd8ecd197382b8ab89b793f918af1803d26c06 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu, 30 Mar 2023 01:42:02 +0800 Subject: [PATCH 244/280] fix a small memory leak --- Python/tier2.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index 32c75f8eb65de4..188af5e6b88998 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -1576,20 +1576,14 @@ _PyTier2_Code_DetectAndEmitBB( } } - _PyTier2TypeContext *type_context_copy = NULL; end: // Create the tier 2 BB - // Make a copy of the type context - type_context_copy = _PyTier2TypeContext_Copy(starting_type_context); - if (type_context_copy == NULL) { - return NULL; - } temp_meta = _PyTier2_AllocateBBMetaData(co, t2_start, // + 1 because we want to start with the NEXT instruction for the scan - _PyCode_CODE(co) + i + 1, type_context_copy); + _PyCode_CODE(co) + i + 1, starting_type_context); if (temp_meta == NULL) { - _PyTier2TypeContext_Free(type_context_copy); + _PyTier2TypeContext_Free(starting_type_context); return NULL; } // We need to return the first block to enter into. If there is already a block generated @@ -1608,7 +1602,7 @@ _PyTier2_Code_DetectAndEmitBB( if (meta != temp_meta) { PyMem_Free(temp_meta); } - _PyTier2TypeContext_Free(type_context_copy); + _PyTier2TypeContext_Free(starting_type_context); return NULL; } } From c9d3b4981f61e28eb145030e8aa986e962e82184 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu, 30 Mar 2023 01:56:51 +0800 Subject: [PATCH 245/280] Add assert for type stacksize --- Include/internal/pycore_code.h | 2 +- Python/bytecodes.c | 3 ++- Python/generated_cases.c.h | 3 ++- Python/tier2.c | 6 ++++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 0f8d9f7808153f..863e6b383a4937 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -282,7 +282,7 @@ extern _Py_CODEUNIT *_PyTier2_GenerateNextBB( char bb_flag); extern _Py_CODEUNIT *_PyTier2_LocateJumpBackwardsBB( struct _PyInterpreterFrame *frame, uint16_t bb_id, int jumpby, - _Py_CODEUNIT **tier1_fallback, _Py_CODEUNIT *curr); + _Py_CODEUNIT **tier1_fallback, _Py_CODEUNIT *curr, int stacksize); extern void _PyTier2_RewriteForwardJump(_Py_CODEUNIT *bb_branch, _Py_CODEUNIT *target); extern void _PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *target); #ifdef Py_STATS diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 76bbb5e566567d..93ab5df1b3f171 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3276,7 +3276,8 @@ dummy_func( _Py_CODEUNIT *tier1_fallback = NULL; t2_nextinstr = _PyTier2_LocateJumpBackwardsBB( - frame, cache->bb_id_tagged, -oparg, &tier1_fallback, curr); + frame, cache->bb_id_tagged, -oparg, &tier1_fallback, curr, + STACK_LEVEL()); if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 00601c8800259c..f3eca0b9832732 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -4153,7 +4153,8 @@ _Py_CODEUNIT *tier1_fallback = NULL; t2_nextinstr = _PyTier2_LocateJumpBackwardsBB( - frame, cache->bb_id_tagged, -oparg, &tier1_fallback, curr); + frame, cache->bb_id_tagged, -oparg, &tier1_fallback, curr, + STACK_LEVEL()); if (t2_nextinstr == NULL) { // Fall back to tier 1. next_instr = tier1_fallback; diff --git a/Python/tier2.c b/Python/tier2.c index 188af5e6b88998..20d40acc1b3d34 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -1497,7 +1497,6 @@ _PyTier2_Code_DetectAndEmitBB( goto fall_through; } if (IS_BACKWARDS_JUMP_TARGET(co, curr)) { -backward_jump_target: #if BB_DEBUG fprintf(stderr, "Encountered a backward jump target\n"); #endif @@ -2145,12 +2144,15 @@ diff_typecontext(_PyTier2TypeContext *ctx1, _PyTier2TypeContext *ctx2) _Py_CODEUNIT * _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id_tagged, int jumpby, _Py_CODEUNIT **tier1_fallback, - _Py_CODEUNIT *curr) + _Py_CODEUNIT *curr, int stacklevel) { PyCodeObject *co = frame->f_code; assert(co->_tier2_info != NULL); assert(BB_ID(bb_id_tagged) <= co->_tier2_info->bb_data_curr); _PyTier2BBMetadata *meta = co->_tier2_info->bb_data[BB_ID(bb_id_tagged)]; + // We assert that there are as many items on the operand stack as there are in the + // saved type stack. + assert((meta->type_context->type_stack_ptr - meta->type_context->type_stack) == stacklevel); // The jump target _Py_CODEUNIT *tier1_jump_target = meta->tier1_end + jumpby - ((curr-1)->op.code == EXTENDED_ARG && (curr-1)->op.arg > 0); *tier1_fallback = tier1_jump_target; From a77cf568e1decd9bfc1222955a49da86e56f5099 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu, 30 Mar 2023 02:15:03 +0800 Subject: [PATCH 246/280] Fix an EXTENDED_ARG bug --- Python/tier2.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index 20d40acc1b3d34..cc4974e047e4e8 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -1525,14 +1525,16 @@ _PyTier2_Code_DetectAndEmitBB( virtual_start = true; if (opcode == EXTENDED_ARG) { + write_i = emit_i(write_i, specop, oparg); // Note: EXTENDED_ARG could be a jump target!!!!! - caches = _PyOpcode_Caches[opcode]; specop = next_instr->op.code; opcode = _PyOpcode_Deopt[specop]; + caches = _PyOpcode_Caches[opcode]; oparg = oparg << 8 | next_instr->op.arg; curr++; next_instr++; - i += 2; + i += 1; + DISPATCH_GOTO(); } // Don't change opcode or oparg, let us handle it again. DISPATCH_GOTO(); @@ -1561,14 +1563,15 @@ _PyTier2_Code_DetectAndEmitBB( END(); } if (opcode == EXTENDED_ARG) { + write_i = emit_i(write_i, specop, oparg); // Note: EXTENDED_ARG could be a jump target!!!!! - caches = _PyOpcode_Caches[opcode]; specop = next_instr->op.code; opcode = _PyOpcode_Deopt[specop]; + caches = _PyOpcode_Caches[opcode]; oparg = oparg << 8 | next_instr->op.arg; curr++; next_instr++; - i += 2; + i += 1; DISPATCH_GOTO(); } DISPATCH(); @@ -2150,9 +2153,12 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id_tagged assert(co->_tier2_info != NULL); assert(BB_ID(bb_id_tagged) <= co->_tier2_info->bb_data_curr); _PyTier2BBMetadata *meta = co->_tier2_info->bb_data[BB_ID(bb_id_tagged)]; - // We assert that there are as many items on the operand stack as there are in the +#ifdef Py_DEBUG + // We assert that there are as many items on the operand stack as there are on the // saved type stack. - assert((meta->type_context->type_stack_ptr - meta->type_context->type_stack) == stacklevel); + int typestack_level = meta->type_context->type_stack_ptr - meta->type_context->type_stack; + assert(typestack_level == stacklevel); +#endif // The jump target _Py_CODEUNIT *tier1_jump_target = meta->tier1_end + jumpby - ((curr-1)->op.code == EXTENDED_ARG && (curr-1)->op.arg > 0); *tier1_fallback = tier1_jump_target; From 66143f9adfaca1a3880d64d391102f46280f2aa3 Mon Sep 17 00:00:00 2001 From: Jules <57632293+JuliaPoo@users.noreply.github.com> Date: Thu, 30 Mar 2023 20:38:19 +0800 Subject: [PATCH 247/280] Fix: BB_TEST_ITER wrong type propagation (#31) --- Include/internal/pycore_code.h | 8 ++++---- Python/bytecodes.c | 2 +- Python/generated_cases.c.h | 2 +- Python/tier2.c | 6 ++++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 863e6b383a4937..3bee8696ed5efb 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -261,15 +261,15 @@ extern int _PyStaticCode_Init(PyCodeObject *co); // gen_bb_is_successor: // true = successor // false = alternate -// gen_bb_requires_pop: +// gen_bb_requires_pop (maximum 7): // For tier2 type propagation, handling of jump instructions with // runtime-dependent stack effect. // This flag is used to determine if the type context of a new bb // requires a stack element to be popped. #define BB_TEST(gen_bb_is_successor, gen_bb_requires_pop) \ - (((gen_bb_is_successor) << 1) | (gen_bb_requires_pop)) -#define BB_TEST_IS_SUCCESSOR(bb_test) ((bb_test) >> 1) -#define BB_TEST_IS_REQUIRES_POP(bb_test) ((bb_test) & 1) + (((gen_bb_is_successor) << 4) | (gen_bb_requires_pop)) +#define BB_TEST_IS_SUCCESSOR(bb_test) ((bb_test) >> 4) +#define BB_TEST_GET_N_REQUIRES_POP(bb_test) ((bb_test) & 0b1111) extern _Py_CODEUNIT *_PyCode_Tier2Warmup(struct _PyInterpreterFrame *, _Py_CODEUNIT *); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 93ab5df1b3f171..34ae3cbddd681c 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2190,7 +2190,7 @@ dummy_func( /* iterator ended normally */ Py_DECREF(iter); STACK_SHRINK(1); - bb_test = BB_TEST(0, 1); + bb_test = BB_TEST(0, 2); JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); DISPATCH(); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index f3eca0b9832732..0ef2014548b926 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2824,7 +2824,7 @@ /* iterator ended normally */ Py_DECREF(iter); STACK_SHRINK(1); - bb_test = BB_TEST(0, 1); + bb_test = BB_TEST(0, 2); JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); DISPATCH(); } diff --git a/Python/tier2.c b/Python/tier2.c index cc4974e047e4e8..2bb36794c131d3 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -1979,8 +1979,10 @@ _PyTier2_GenerateNextBBMetaWithTypeContext( // DEOPTIMIZE TO TIER 1? return NULL; } - if (BB_TEST_IS_REQUIRES_POP(bb_flag)) { - __type_stack_shrink(&(type_context_copy->type_stack_ptr), 1); + + int n_required_pop = BB_TEST_GET_N_REQUIRES_POP(bb_flag); + if (n_required_pop) { + __type_stack_shrink(&(type_context_copy->type_stack_ptr), n_required_pop); } // For type branches, they directly precede the bb branch instruction _Py_CODEUNIT *prev_type_guard = BB_IS_TYPE_BRANCH(bb_id_tagged) From f36e9d7a3711c1e9918e7f3b292cdabdcb051af3 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu, 30 Mar 2023 21:18:54 +0800 Subject: [PATCH 248/280] Fix more EXTENDED_ARG issues --- Python/tier2.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index 2bb36794c131d3..a5aa841bc40f4d 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -658,7 +658,7 @@ _PyTier2_BBSpaceCheckAndReallocIfNeeded(PyCodeObject *co, Py_ssize_t space_reque // Note: overallocate Py_ssize_t new_size = sizeof(_PyTier2BBSpace) + (curr->water_level + space_requested) * 2; #if BB_DEBUG - fprintf(stderr, "Allocating new BB of size %lld\n", (int64_t)new_size); + fprintf(stderr, "Space requested: %lld, Allocating new BB of size %lld\n", (int64_t)space_requested, (int64_t)new_size); #endif // @TODO We can't Realloc, we actually need to do the linked list method. Py_UNREACHABLE(); @@ -1113,8 +1113,13 @@ emit_scope_exit(_Py_CODEUNIT *write_curr, _Py_CODEUNIT exit, static inline _Py_CODEUNIT * emit_i(_Py_CODEUNIT *write_curr, int opcode, int oparg) { + if (oparg > 0xFF) { + _py_set_opcode(write_curr, EXTENDED_ARG); + write_curr->op.arg = (oparg >> 8) & 0xFF; + write_curr++; + } _py_set_opcode(write_curr, opcode); - write_curr->op.arg = oparg; + write_curr->op.arg = oparg & 0xFF; write_curr++; return write_curr; } @@ -1280,14 +1285,14 @@ _PyTier2_Code_DetectAndEmitBB( ); #define END() goto end; #define JUMPBY(x) i += x + 1; -#define DISPATCH() write_i = emit_i(write_i, specop, oparg); \ +#define DISPATCH() write_i = emit_i(write_i, specop, curr->op.arg); \ write_i = copy_cache_entries(write_i, curr+1, caches); \ i += caches; \ type_propagate(opcode, oparg, starting_type_context, consts); \ continue; #define DISPATCH_REBOX(x) write_i = rebox_stack(write_i, starting_type_context, x); \ - write_i = emit_i(write_i, specop, oparg); \ + write_i = emit_i(write_i, specop, curr->op.arg); \ write_i = copy_cache_entries(write_i, curr+1, caches); \ i += caches; \ type_propagate(opcode, oparg, starting_type_context, consts); \ @@ -1525,7 +1530,6 @@ _PyTier2_Code_DetectAndEmitBB( virtual_start = true; if (opcode == EXTENDED_ARG) { - write_i = emit_i(write_i, specop, oparg); // Note: EXTENDED_ARG could be a jump target!!!!! specop = next_instr->op.code; opcode = _PyOpcode_Deopt[specop]; @@ -1563,7 +1567,6 @@ _PyTier2_Code_DetectAndEmitBB( END(); } if (opcode == EXTENDED_ARG) { - write_i = emit_i(write_i, specop, oparg); // Note: EXTENDED_ARG could be a jump target!!!!! specop = next_instr->op.code; opcode = _PyOpcode_Deopt[specop]; @@ -2162,7 +2165,7 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id_tagged assert(typestack_level == stacklevel); #endif // The jump target - _Py_CODEUNIT *tier1_jump_target = meta->tier1_end + jumpby - ((curr-1)->op.code == EXTENDED_ARG && (curr-1)->op.arg > 0); + _Py_CODEUNIT *tier1_jump_target = meta->tier1_end + jumpby; *tier1_fallback = tier1_jump_target; // Be a pessimist and assume we need to write the entire rest of code into the BB. // The size of the BB generated will definitely be equal to or smaller than this. From 941fea048b53a874b7a3caa89a24790b321dabe0 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu, 30 Mar 2023 22:02:25 +0800 Subject: [PATCH 249/280] Add BB_TEST_ITER specialisations --- Include/internal/pycore_code.h | 2 +- Include/internal/pycore_opcode.h | 15 ++--- Include/opcode.h | 111 ++++++------------------------- Lib/opcode.py | 5 ++ Python/bytecodes.c | 83 ++++++++++++++++++++++- Python/generated_cases.c.h | 102 +++++++++++++++++++++++++++- Python/opcode_metadata.h | 17 ++++- Python/specialize.c | 16 ++--- Python/tier2.c | 2 + Python/tier2_typepropagator.c.h | 18 +++++ Tools/build/generate_opcode_h.py | 5 +- 11 files changed, 263 insertions(+), 113 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 3bee8696ed5efb..c62c39a6a080d6 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -248,7 +248,7 @@ extern void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, int oparg); extern void _Py_Specialize_UnpackSequence(PyObject *seq, _Py_CODEUNIT *instr, int oparg); -extern void _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg); +extern void _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg, char is_bb); extern void _Py_Specialize_Send(PyObject *receiver, _Py_CODEUNIT *instr); /* Finalizer function for static codeobjects used in deepfreeze.py */ diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 155f8461021686..0a9dbd1623c4a1 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -412,6 +412,9 @@ static const char *const _PyOpcode_OpName[263] = { [BB_JUMP_IF_FLAG_UNSET] = "BB_JUMP_IF_FLAG_UNSET", [BB_JUMP_IF_FLAG_SET] = "BB_JUMP_IF_FLAG_SET", [BB_TEST_ITER] = "BB_TEST_ITER", + [BB_TEST_ITER_RANGE] = "BB_TEST_ITER_RANGE", + [BB_TEST_ITER_LIST] = "BB_TEST_ITER_LIST", + [BB_TEST_ITER_TUPLE] = "BB_TEST_ITER_TUPLE", [BB_TEST_POP_IF_FALSE] = "BB_TEST_POP_IF_FALSE", [BB_TEST_POP_IF_TRUE] = "BB_TEST_POP_IF_TRUE", [BB_TEST_POP_IF_NOT_NONE] = "BB_TEST_POP_IF_NOT_NONE", @@ -422,6 +425,8 @@ static const char *const _PyOpcode_OpName[263] = { [UNARY_CHECK_FLOAT] = "UNARY_CHECK_FLOAT", [BINARY_OP_ADD_INT_REST] = "BINARY_OP_ADD_INT_REST", [BINARY_OP_ADD_FLOAT_UNBOXED] = "BINARY_OP_ADD_FLOAT_UNBOXED", + [BINARY_OP_SUBTRACT_FLOAT_UNBOXED] = "BINARY_OP_SUBTRACT_FLOAT_UNBOXED", + [BINARY_OP_MULTIPLY_FLOAT_UNBOXED] = "BINARY_OP_MULTIPLY_FLOAT_UNBOXED", [POP_TOP_NO_DECREF] = "POP_TOP_NO_DECREF", [UNBOX_FLOAT] = "UNBOX_FLOAT", [BOX_FLOAT] = "BOX_FLOAT", @@ -429,11 +434,6 @@ static const char *const _PyOpcode_OpName[263] = { [STORE_FAST_BOXED_UNBOXED] = "STORE_FAST_BOXED_UNBOXED", [STORE_FAST_UNBOXED_BOXED] = "STORE_FAST_UNBOXED_BOXED", [STORE_FAST_UNBOXED_UNBOXED] = "STORE_FAST_UNBOXED_UNBOXED", - [196] = "<196>", - [197] = "<197>", - [198] = "<198>", - [199] = "<199>", - [200] = "<200>", [201] = "<201>", [202] = "<202>", [203] = "<203>", @@ -501,11 +501,6 @@ static const char *const _PyOpcode_OpName[263] = { #define EXTRA_CASES \ - case 196: \ - case 197: \ - case 198: \ - case 199: \ - case 200: \ case 201: \ case 202: \ case 203: \ diff --git a/Include/opcode.h b/Include/opcode.h index 6ae5375ed0dadc..eb4cb486cad590 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -161,9 +161,6 @@ extern "C" { #define FOR_ITER_TUPLE 63 #define FOR_ITER_RANGE 64 #define FOR_ITER_GEN 65 -#define BB_TEST_ITER_LIST 66 -#define BB_TEST_ITER_TUPLE 67 -#define BB_TEST_ITER_RANGE 70 #define BB_TEST_ITER_GEN 72 #define LOAD_ATTR_CLASS 73 #define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 76 @@ -193,98 +190,34 @@ extern "C" { #define SEND_GEN 168 #define DO_TRACING 255 // Tier 2 interpreter ops -#define RESUME_QUICK 5 -#define JUMP_BACKWARD_QUICK 6 -#define BINARY_OP_ADD_FLOAT 7 -#define BINARY_OP_ADD_INT 8 -#define BINARY_OP_ADD_UNICODE 10 -#define BINARY_OP_INPLACE_ADD_UNICODE 13 -#define BINARY_OP_MULTIPLY_FLOAT 14 -#define BINARY_OP_MULTIPLY_INT 16 -#define BINARY_OP_SUBTRACT_FLOAT 17 -#define BINARY_OP_SUBTRACT_INT 18 -#define BINARY_SUBSCR_DICT 19 -#define BINARY_SUBSCR_GETITEM 20 -#define BINARY_SUBSCR_LIST_INT 21 -#define BINARY_SUBSCR_TUPLE_INT 22 -#define CALL_PY_EXACT_ARGS 23 -#define CALL_PY_WITH_DEFAULTS 24 -#define CALL_BOUND_METHOD_EXACT_ARGS 28 -#define CALL_BUILTIN_CLASS 29 -#define CALL_BUILTIN_FAST_WITH_KEYWORDS 34 -#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 38 -#define CALL_NO_KW_BUILTIN_FAST 39 -#define CALL_NO_KW_BUILTIN_O 40 -#define CALL_NO_KW_ISINSTANCE 41 -#define CALL_NO_KW_LEN 42 -#define CALL_NO_KW_LIST_APPEND 43 -#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 44 -#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 45 -#define CALL_NO_KW_METHOD_DESCRIPTOR_O 46 -#define CALL_NO_KW_STR_1 47 -#define CALL_NO_KW_TUPLE_1 48 -#define CALL_NO_KW_TYPE_1 56 -#define COMPARE_OP_FLOAT 57 -#define COMPARE_OP_INT 58 -#define COMPARE_OP_STR 59 -#define FOR_ITER_LIST 62 -#define FOR_ITER_TUPLE 63 -#define FOR_ITER_RANGE 64 -#define FOR_ITER_GEN 65 -#define BB_TEST_ITER_LIST 66 -#define BB_TEST_ITER_TUPLE 67 -#define BB_TEST_ITER_RANGE 70 -#define BB_TEST_ITER_GEN 72 -#define LOAD_ATTR_CLASS 73 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 76 -#define LOAD_ATTR_INSTANCE_VALUE 77 -#define LOAD_ATTR_MODULE 78 -#define LOAD_ATTR_PROPERTY 79 -#define LOAD_ATTR_SLOT 80 -#define LOAD_ATTR_WITH_HINT 81 -#define LOAD_ATTR_METHOD_LAZY_DICT 82 -#define LOAD_ATTR_METHOD_NO_DICT 84 -#define LOAD_ATTR_METHOD_WITH_VALUES 86 -#define LOAD_CONST__LOAD_FAST 87 -#define LOAD_FAST__LOAD_CONST 88 -#define LOAD_FAST__LOAD_FAST 111 -#define LOAD_GLOBAL_BUILTIN 112 -#define LOAD_GLOBAL_MODULE 113 -#define STORE_ATTR_INSTANCE_VALUE 141 -#define STORE_ATTR_SLOT 143 -#define STORE_ATTR_WITH_HINT 153 -#define STORE_FAST__LOAD_FAST 154 -#define STORE_FAST__STORE_FAST 158 -#define STORE_SUBSCR_DICT 159 -#define STORE_SUBSCR_LIST_INT 160 -#define UNPACK_SEQUENCE_LIST 161 -#define UNPACK_SEQUENCE_TUPLE 166 -#define UNPACK_SEQUENCE_TWO_TUPLE 167 -#define SEND_GEN 168 -#define DO_TRACING 255 #define BB_BRANCH 169 #define BB_BRANCH_IF_FLAG_UNSET 170 #define BB_BRANCH_IF_FLAG_SET 175 #define BB_JUMP_IF_FLAG_UNSET 176 #define BB_JUMP_IF_FLAG_SET 177 #define BB_TEST_ITER 178 -#define BB_TEST_POP_IF_FALSE 179 -#define BB_TEST_POP_IF_TRUE 180 -#define BB_TEST_POP_IF_NOT_NONE 181 -#define BB_TEST_POP_IF_NONE 182 -#define BB_JUMP_BACKWARD_LAZY 183 -#define BINARY_CHECK_INT 184 -#define BINARY_CHECK_FLOAT 185 -#define UNARY_CHECK_FLOAT 186 -#define BINARY_OP_ADD_INT_REST 187 -#define BINARY_OP_ADD_FLOAT_UNBOXED 188 -#define POP_TOP_NO_DECREF 189 -#define UNBOX_FLOAT 190 -#define BOX_FLOAT 191 -#define LOAD_FAST_NO_INCREF 192 -#define STORE_FAST_BOXED_UNBOXED 193 -#define STORE_FAST_UNBOXED_BOXED 194 -#define STORE_FAST_UNBOXED_UNBOXED 195 +#define BB_TEST_ITER_RANGE 179 +#define BB_TEST_ITER_LIST 180 +#define BB_TEST_ITER_TUPLE 181 +#define BB_TEST_POP_IF_FALSE 182 +#define BB_TEST_POP_IF_TRUE 183 +#define BB_TEST_POP_IF_NOT_NONE 184 +#define BB_TEST_POP_IF_NONE 185 +#define BB_JUMP_BACKWARD_LAZY 186 +#define BINARY_CHECK_INT 187 +#define BINARY_CHECK_FLOAT 188 +#define UNARY_CHECK_FLOAT 189 +#define BINARY_OP_ADD_INT_REST 190 +#define BINARY_OP_ADD_FLOAT_UNBOXED 191 +#define BINARY_OP_SUBTRACT_FLOAT_UNBOXED 192 +#define BINARY_OP_MULTIPLY_FLOAT_UNBOXED 193 +#define POP_TOP_NO_DECREF 194 +#define UNBOX_FLOAT 195 +#define BOX_FLOAT 196 +#define LOAD_FAST_NO_INCREF 197 +#define STORE_FAST_BOXED_UNBOXED 198 +#define STORE_FAST_UNBOXED_BOXED 199 +#define STORE_FAST_UNBOXED_UNBOXED 200 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/opcode.py b/Lib/opcode.py index 5277f47b457262..54751c07d0145e 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -465,6 +465,9 @@ def pseudo_op(name, op, real_ops): # These tests correspond to the jump instructions # FOR_ITER's null (iterator) check 'BB_TEST_ITER', + 'BB_TEST_ITER_RANGE', + 'BB_TEST_ITER_LIST', + 'BB_TEST_ITER_TUPLE', # POP_JUMP_IF_FALSE, POP_JUMP_IF_TRUE 'BB_TEST_POP_IF_FALSE', 'BB_TEST_POP_IF_TRUE', @@ -490,6 +493,8 @@ def pseudo_op(name, op, real_ops): # 'BINARY_CHECK_STR', 'BINARY_OP_ADD_INT_REST', 'BINARY_OP_ADD_FLOAT_UNBOXED', + 'BINARY_OP_SUBTRACT_FLOAT_UNBOXED', + 'BINARY_OP_MULTIPLY_FLOAT_UNBOXED', # Boxing / unboxing ops 'POP_TOP_NO_DECREF', diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 34ae3cbddd681c..3c6901db7e10a6 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2145,7 +2145,7 @@ dummy_func( if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); next_instr--; - _Py_Specialize_ForIter(iter, next_instr, oparg); + _Py_Specialize_ForIter(iter, next_instr, oparg, 0); DISPATCH_SAME_OPARG(); } STAT_INC(FOR_ITER, deferred); @@ -2176,6 +2176,17 @@ dummy_func( // FOR_ITER inst(BB_TEST_ITER, (unused/1, iter -- iter, next)) { + #if ENABLE_SPECIALIZATION + _PyForIterCache *cache = (_PyForIterCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + assert(cframe.use_tracing == 0); + next_instr--; + _Py_Specialize_ForIter(iter, next_instr, oparg, 1); + DISPATCH_SAME_OPARG(); + } + STAT_INC(BB_TEST_ITER, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ next = (*Py_TYPE(iter)->tp_iternext)(iter); if (next == NULL) { if (_PyErr_Occurred(tstate)) { @@ -2220,6 +2231,30 @@ dummy_func( // Common case: no jump, leave it to the code generator } + inst(BB_TEST_ITER_LIST, (unused/1, iter -- iter, next)) { + assert(cframe.use_tracing == 0); + DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, BB_TEST_ITER); + _PyListIterObject *it = (_PyListIterObject *)iter; + STAT_INC(FOR_ITER, hit); + PyListObject *seq = it->it_seq; + if (seq) { + if (it->it_index < PyList_GET_SIZE(seq)) { + next = Py_NewRef(PyList_GET_ITEM(seq, it->it_index++)); + goto end_bb_iter_list; // End of this instruction + } + it->it_seq = NULL; + Py_DECREF(seq); + } + Py_DECREF(iter); + STACK_SHRINK(1); + bb_test = BB_TEST(0, 2); + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + DISPATCH(); + end_bb_iter_list: + // Common case: no jump, leave it to the code generator + bb_test = BB_TEST(1, 0); + } + inst(FOR_ITER_TUPLE, (unused/1, iter -- iter, next)) { assert(cframe.use_tracing == 0); _PyTupleIterObject *it = (_PyTupleIterObject *)iter; @@ -2243,6 +2278,30 @@ dummy_func( // Common case: no jump, leave it to the code generator } + inst(BB_TEST_ITER_TUPLE, (unused/1, iter -- iter, next)) { + assert(cframe.use_tracing == 0); + _PyTupleIterObject *it = (_PyTupleIterObject *)iter; + DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, BB_TEST_ITER); + STAT_INC(FOR_ITER, hit); + PyTupleObject *seq = it->it_seq; + if (seq) { + if (it->it_index < PyTuple_GET_SIZE(seq)) { + next = Py_NewRef(PyTuple_GET_ITEM(seq, it->it_index++)); + goto end_test_iter_tuple; // End of this instruction + } + it->it_seq = NULL; + Py_DECREF(seq); + } + Py_DECREF(iter); + STACK_SHRINK(1); + bb_test = BB_TEST(0, 2); + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + DISPATCH(); + end_test_iter_tuple: + // Common case: no jump, leave it to the code generator + bb_test = BB_TEST(1, 0); + } + inst(FOR_ITER_RANGE, (unused/1, iter -- iter, next)) { assert(cframe.use_tracing == 0); _PyRangeIterObject *r = (_PyRangeIterObject *)iter; @@ -2264,6 +2323,28 @@ dummy_func( } } + inst(BB_TEST_ITER_RANGE, (unused / 1, iter -- iter, next)) { + assert(cframe.use_tracing == 0); + _PyRangeIterObject *r = (_PyRangeIterObject *)iter; + DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, BB_TEST_ITER); + STAT_INC(FOR_ITER, hit); + if (r->len <= 0) { + STACK_SHRINK(1); + Py_DECREF(r); + bb_test = BB_TEST(0, 2); + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + DISPATCH(); + } + long value = r->start; + r->start = value + r->step; + r->len--; + next = PyLong_FromLong(value); + if (next == NULL) { + goto error; + } + bb_test = BB_TEST(1, 0); + } + inst(FOR_ITER_GEN, (unused/1, iter -- iter, unused)) { assert(cframe.use_tracing == 0); PyGenObject *gen = (PyGenObject *)iter; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 0ef2014548b926..8190fe7a4a5403 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2774,7 +2774,7 @@ if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); next_instr--; - _Py_Specialize_ForIter(iter, next_instr, oparg); + _Py_Specialize_ForIter(iter, next_instr, oparg, 0); DISPATCH_SAME_OPARG(); } STAT_INC(FOR_ITER, deferred); @@ -2808,8 +2808,20 @@ } TARGET(BB_TEST_ITER) { + PREDICTED(BB_TEST_ITER); PyObject *iter = stack_pointer[-1]; PyObject *next; + #if ENABLE_SPECIALIZATION + _PyForIterCache *cache = (_PyForIterCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + assert(cframe.use_tracing == 0); + next_instr--; + _Py_Specialize_ForIter(iter, next_instr, oparg, 1); + DISPATCH_SAME_OPARG(); + } + STAT_INC(BB_TEST_ITER, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ next = (*Py_TYPE(iter)->tp_iternext)(iter); if (next == NULL) { if (_PyErr_Occurred(tstate)) { @@ -2864,6 +2876,36 @@ DISPATCH(); } + TARGET(BB_TEST_ITER_LIST) { + PyObject *iter = stack_pointer[-1]; + PyObject *next; + assert(cframe.use_tracing == 0); + DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, BB_TEST_ITER); + _PyListIterObject *it = (_PyListIterObject *)iter; + STAT_INC(FOR_ITER, hit); + PyListObject *seq = it->it_seq; + if (seq) { + if (it->it_index < PyList_GET_SIZE(seq)) { + next = Py_NewRef(PyList_GET_ITEM(seq, it->it_index++)); + goto end_bb_iter_list; // End of this instruction + } + it->it_seq = NULL; + Py_DECREF(seq); + } + Py_DECREF(iter); + STACK_SHRINK(1); + bb_test = BB_TEST(0, 2); + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + DISPATCH(); + end_bb_iter_list: + // Common case: no jump, leave it to the code generator + bb_test = BB_TEST(1, 0); + STACK_GROW(1); + stack_pointer[-1] = next; + next_instr += 1; + DISPATCH(); + } + TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; @@ -2893,6 +2935,36 @@ DISPATCH(); } + TARGET(BB_TEST_ITER_TUPLE) { + PyObject *iter = stack_pointer[-1]; + PyObject *next; + assert(cframe.use_tracing == 0); + _PyTupleIterObject *it = (_PyTupleIterObject *)iter; + DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, BB_TEST_ITER); + STAT_INC(FOR_ITER, hit); + PyTupleObject *seq = it->it_seq; + if (seq) { + if (it->it_index < PyTuple_GET_SIZE(seq)) { + next = Py_NewRef(PyTuple_GET_ITEM(seq, it->it_index++)); + goto end_test_iter_tuple; // End of this instruction + } + it->it_seq = NULL; + Py_DECREF(seq); + } + Py_DECREF(iter); + STACK_SHRINK(1); + bb_test = BB_TEST(0, 2); + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + DISPATCH(); + end_test_iter_tuple: + // Common case: no jump, leave it to the code generator + bb_test = BB_TEST(1, 0); + STACK_GROW(1); + stack_pointer[-1] = next; + next_instr += 1; + DISPATCH(); + } + TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; @@ -2920,6 +2992,34 @@ DISPATCH(); } + TARGET(BB_TEST_ITER_RANGE) { + PyObject *iter = stack_pointer[-1]; + PyObject *next; + assert(cframe.use_tracing == 0); + _PyRangeIterObject *r = (_PyRangeIterObject *)iter; + DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, BB_TEST_ITER); + STAT_INC(FOR_ITER, hit); + if (r->len <= 0) { + STACK_SHRINK(1); + Py_DECREF(r); + bb_test = BB_TEST(0, 2); + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + DISPATCH(); + } + long value = r->start; + r->start = value + r->step; + r->len--; + next = PyLong_FromLong(value); + if (next == NULL) { + goto error; + } + bb_test = BB_TEST(1, 0); + STACK_GROW(1); + stack_pointer[-1] = next; + next_instr += 1; + DISPATCH(); + } + TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; assert(cframe.use_tracing == 0); diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 6f77f7c5d4e67c..1bb9f7b2926a4b 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -303,10 +303,16 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 1; case FOR_ITER_LIST: return 1; + case BB_TEST_ITER_LIST: + return 1; case FOR_ITER_TUPLE: return 1; + case BB_TEST_ITER_TUPLE: + return 1; case FOR_ITER_RANGE: return 1; + case BB_TEST_ITER_RANGE: + return 1; case FOR_ITER_GEN: return 1; case BEFORE_ASYNC_WITH: @@ -699,10 +705,16 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 2; case FOR_ITER_LIST: return 2; + case BB_TEST_ITER_LIST: + return 2; case FOR_ITER_TUPLE: return 2; + case BB_TEST_ITER_TUPLE: + return 2; case FOR_ITER_RANGE: return 2; + case BB_TEST_ITER_RANGE: + return 2; case FOR_ITER_GEN: return 2; case BEFORE_ASYNC_WITH: @@ -950,10 +962,13 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [GET_ITER] = { true, INSTR_FMT_IX }, [GET_YIELD_FROM_ITER] = { true, INSTR_FMT_IX }, [FOR_ITER] = { true, INSTR_FMT_IBC }, - [BB_TEST_ITER] = { true, INSTR_FMT_IXC }, + [BB_TEST_ITER] = { true, INSTR_FMT_IBC }, [FOR_ITER_LIST] = { true, INSTR_FMT_IBC }, + [BB_TEST_ITER_LIST] = { true, INSTR_FMT_IXC }, [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC }, + [BB_TEST_ITER_TUPLE] = { true, INSTR_FMT_IXC }, [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC }, + [BB_TEST_ITER_RANGE] = { true, INSTR_FMT_IXC }, [FOR_ITER_GEN] = { true, INSTR_FMT_IBC }, [BEFORE_ASYNC_WITH] = { true, INSTR_FMT_IX }, [BEFORE_WITH] = { true, INSTR_FMT_IX }, diff --git a/Python/specialize.c b/Python/specialize.c index f27951613bfc7a..b9e450c74efffd 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -2135,22 +2135,22 @@ int #endif void -_Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg) +_Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg, char is_bb) { assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[FOR_ITER] == INLINE_CACHE_ENTRIES_FOR_ITER); _PyForIterCache *cache = (_PyForIterCache *)(instr + 1); PyTypeObject *tp = Py_TYPE(iter); if (tp == &PyListIter_Type) { - instr->op.code = FOR_ITER_LIST; + instr->op.code = is_bb ? BB_TEST_ITER_LIST : FOR_ITER_LIST; goto success; } else if (tp == &PyTupleIter_Type) { - instr->op.code = FOR_ITER_TUPLE; + instr->op.code = is_bb ? BB_TEST_ITER_TUPLE : FOR_ITER_TUPLE; goto success; } else if (tp == &PyRangeIter_Type) { - instr->op.code = FOR_ITER_RANGE; + instr->op.code = is_bb ? BB_TEST_ITER_RANGE : FOR_ITER_RANGE; goto success; } //else if (tp == &PyGen_Type && oparg <= SHRT_MAX) { @@ -2158,14 +2158,14 @@ _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg) // instr->op.code = FOR_ITER_GEN; // goto success; //} - SPECIALIZATION_FAIL(FOR_ITER, + SPECIALIZATION_FAIL(is_bb ? BB_TEST_ITER : FOR_ITER, _PySpecialization_ClassifyIterator(iter)); - STAT_INC(FOR_ITER, failure); - instr->op.code = FOR_ITER; + STAT_INC(is_bb ? BB_TEST_ITER : FOR_ITER, failure); + instr->op.code = is_bb ? BB_TEST_ITER : FOR_ITER; cache->counter = adaptive_counter_backoff(cache->counter); return; success: - STAT_INC(FOR_ITER, success); + STAT_INC(is_bb ? BB_TEST_ITER : FOR_ITER, success); cache->counter = adaptive_counter_cooldown(); } diff --git a/Python/tier2.c b/Python/tier2.c index a5aa841bc40f4d..7a1e11a241398a 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -1043,6 +1043,8 @@ emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, _py_set_opcode(write_curr, BB_TEST_ITER); write_curr->op.arg = oparg & 0xFF; write_curr++; + // Initialize adaptive interpreter counter + write_curr->cache = adaptive_counter_warmup(); write_curr = emit_cache_entries(write_curr, INLINE_CACHE_ENTRIES_FOR_ITER); type_propagate(BB_TEST_ITER, oparg, type_context, NULL); _py_set_opcode(write_curr, requires_extended_arg ? EXTENDED_ARG : NOP); diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index 9c645df9007b0b..13093092ba8a70 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -734,18 +734,36 @@ break; } + TARGET(BB_TEST_ITER_LIST) { + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + TARGET(FOR_ITER_TUPLE) { STACK_GROW(1); TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } + TARGET(BB_TEST_ITER_TUPLE) { + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + TARGET(FOR_ITER_RANGE) { STACK_GROW(1); TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); break; } + TARGET(BB_TEST_ITER_RANGE) { + STACK_GROW(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + TARGET(FOR_ITER_GEN) { STACK_GROW(1); break; diff --git a/Tools/build/generate_opcode_h.py b/Tools/build/generate_opcode_h.py index d3889f5b67fd7f..a8f3d5460f11f7 100644 --- a/Tools/build/generate_opcode_h.py +++ b/Tools/build/generate_opcode_h.py @@ -112,7 +112,7 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna # The Tier 2 ops next_op = 1 - uop_opmap = specialized_opmap.copy() + uop_opmap = {} # Add microops for name in opcode['_uops']: while used[next_op]: @@ -141,7 +141,8 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna fobj.write(DEFINE.format("MAX_PSEUDO_OPCODE", MAX_PSEUDO_OPCODE)) for name, op in specialized_opmap.items(): - fobj.write(DEFINE.format(name, op)) + if name not in uop_opmap: + fobj.write(DEFINE.format(name, op)) # Tier 2 opcodes fobj.write("// Tier 2 interpreter ops\n") From 3608d6b7e00394247500665d7d93083183863121 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 31 Mar 2023 00:27:31 +0800 Subject: [PATCH 250/280] Add unboxed float ops for multiply and subtract --- Include/internal/pycore_opcode.h | 9 +-- Include/opcode.h | 21 +++--- Lib/opcode.py | 5 ++ Python/bytecodes.c | 33 ++++++++- Python/generated_cases.c.h | 80 ++++++++++++++++++++- Python/opcode_metadata.h | 25 +++++++ Python/tier2.c | 117 ++++++++++++++++++++++++++----- Python/tier2_typepropagator.c.h | 34 ++++++++- 8 files changed, 285 insertions(+), 39 deletions(-) diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 0a9dbd1623c4a1..71491b83e71a56 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -425,18 +425,18 @@ static const char *const _PyOpcode_OpName[263] = { [UNARY_CHECK_FLOAT] = "UNARY_CHECK_FLOAT", [BINARY_OP_ADD_INT_REST] = "BINARY_OP_ADD_INT_REST", [BINARY_OP_ADD_FLOAT_UNBOXED] = "BINARY_OP_ADD_FLOAT_UNBOXED", + [BINARY_OP_SUBTRACT_INT_REST] = "BINARY_OP_SUBTRACT_INT_REST", [BINARY_OP_SUBTRACT_FLOAT_UNBOXED] = "BINARY_OP_SUBTRACT_FLOAT_UNBOXED", + [BINARY_OP_MULTIPLY_INT_REST] = "BINARY_OP_MULTIPLY_INT_REST", [BINARY_OP_MULTIPLY_FLOAT_UNBOXED] = "BINARY_OP_MULTIPLY_FLOAT_UNBOXED", [POP_TOP_NO_DECREF] = "POP_TOP_NO_DECREF", [UNBOX_FLOAT] = "UNBOX_FLOAT", [BOX_FLOAT] = "BOX_FLOAT", + [COPY_NO_INCREF] = "COPY_NO_INCREF", [LOAD_FAST_NO_INCREF] = "LOAD_FAST_NO_INCREF", [STORE_FAST_BOXED_UNBOXED] = "STORE_FAST_BOXED_UNBOXED", [STORE_FAST_UNBOXED_BOXED] = "STORE_FAST_UNBOXED_BOXED", [STORE_FAST_UNBOXED_UNBOXED] = "STORE_FAST_UNBOXED_UNBOXED", - [201] = "<201>", - [202] = "<202>", - [203] = "<203>", [204] = "<204>", [205] = "<205>", [206] = "<206>", @@ -501,9 +501,6 @@ static const char *const _PyOpcode_OpName[263] = { #define EXTRA_CASES \ - case 201: \ - case 202: \ - case 203: \ case 204: \ case 205: \ case 206: \ diff --git a/Include/opcode.h b/Include/opcode.h index eb4cb486cad590..c0c5a79fd9da38 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -209,15 +209,18 @@ extern "C" { #define UNARY_CHECK_FLOAT 189 #define BINARY_OP_ADD_INT_REST 190 #define BINARY_OP_ADD_FLOAT_UNBOXED 191 -#define BINARY_OP_SUBTRACT_FLOAT_UNBOXED 192 -#define BINARY_OP_MULTIPLY_FLOAT_UNBOXED 193 -#define POP_TOP_NO_DECREF 194 -#define UNBOX_FLOAT 195 -#define BOX_FLOAT 196 -#define LOAD_FAST_NO_INCREF 197 -#define STORE_FAST_BOXED_UNBOXED 198 -#define STORE_FAST_UNBOXED_BOXED 199 -#define STORE_FAST_UNBOXED_UNBOXED 200 +#define BINARY_OP_SUBTRACT_INT_REST 192 +#define BINARY_OP_SUBTRACT_FLOAT_UNBOXED 193 +#define BINARY_OP_MULTIPLY_INT_REST 194 +#define BINARY_OP_MULTIPLY_FLOAT_UNBOXED 195 +#define POP_TOP_NO_DECREF 196 +#define UNBOX_FLOAT 197 +#define BOX_FLOAT 198 +#define COPY_NO_INCREF 199 +#define LOAD_FAST_NO_INCREF 200 +#define STORE_FAST_BOXED_UNBOXED 201 +#define STORE_FAST_UNBOXED_BOXED 202 +#define STORE_FAST_UNBOXED_UNBOXED 203 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/opcode.py b/Lib/opcode.py index 54751c07d0145e..a3d60584a877d8 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -443,6 +443,8 @@ def pseudo_op(name, op, real_ops): _macro_ops = [ 'BINARY_OP_ADD_INT', + 'BINARY_OP_SUBTRACT_INT', + 'BINARY_OP_MULTIPLY_INT', 'BINARY_OP_ADD_FLOAT', ] _uops = [ @@ -493,13 +495,16 @@ def pseudo_op(name, op, real_ops): # 'BINARY_CHECK_STR', 'BINARY_OP_ADD_INT_REST', 'BINARY_OP_ADD_FLOAT_UNBOXED', + 'BINARY_OP_SUBTRACT_INT_REST', 'BINARY_OP_SUBTRACT_FLOAT_UNBOXED', + 'BINARY_OP_MULTIPLY_INT_REST', 'BINARY_OP_MULTIPLY_FLOAT_UNBOXED', # Boxing / unboxing ops 'POP_TOP_NO_DECREF', 'UNBOX_FLOAT', 'BOX_FLOAT', + 'COPY_NO_INCREF', 'LOAD_FAST_NO_INCREF', # Storing a boxed value, overwriting an unboxed local. 'STORE_FAST_BOXED_UNBOXED', diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 3c6901db7e10a6..7b3e11a7799373 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -203,10 +203,14 @@ dummy_func( }; - inst(BINARY_OP_MULTIPLY_INT, (unused/1, left, right -- prod)) { + macro_inst(BINARY_OP_MULTIPLY_INT, (unused/1, left, right -- prod)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); + U_INST(BINARY_OP_MULTIPLY_INT_REST); + } + + u_inst(BINARY_OP_MULTIPLY_INT_REST, (left, right -- prod : PyLong_Type)) { STAT_INC(BINARY_OP, hit); prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -224,10 +228,14 @@ dummy_func( DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dprod, prod); } - inst(BINARY_OP_SUBTRACT_INT, (unused/1, left, right -- sub)) { + macro_inst(BINARY_OP_SUBTRACT_INT, (unused/1, left, right -- sub)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); + U_INST(BINARY_OP_SUBTRACT_INT_REST); + } + + u_inst(BINARY_OP_SUBTRACT_INT_REST, (left, right -- sub : PyLong_Type)) { STAT_INC(BINARY_OP, hit); sub = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -318,10 +326,13 @@ dummy_func( : right); } - inst(UNARY_CHECK_FLOAT, (arg, unused[oparg] -- arg : PyFloat_Type, unused[oparg])) { + inst(UNARY_CHECK_FLOAT, (arg, unused[oparg] -- arg_unboxed : { <<= PyFloat_Type, PyRawFloat_Type}, unused[oparg])) { assert(cframe.use_tracing == 0); char is_successor = PyFloat_CheckExact(arg); bb_test = BB_TEST(is_successor, 0); + arg_unboxed = (is_successor + ? *((PyObject **)(&(((PyFloatObject *)arg)->ob_fval))) + : arg); } inst(BINARY_OP_ADD_FLOAT_UNBOXED, (left, right -- sum : PyRawFloat_Type)) { @@ -330,6 +341,18 @@ dummy_func( sum = *(PyObject **)(&temp); } + inst(BINARY_OP_SUBTRACT_FLOAT_UNBOXED, (left, right -- sum : PyRawFloat_Type)) { + STAT_INC(BINARY_OP, hit); + double temp = *(double *)(&(left)) - *(double *)(&(right)); + sum = *(PyObject **)(&temp); + } + + inst(BINARY_OP_MULTIPLY_FLOAT_UNBOXED, (left, right -- prod : PyRawFloat_Type)) { + STAT_INC(BINARY_OP, hit); + double temp = *(double *)(&(left)) * *(double *)(&(right)); + prod = *(PyObject **)(&temp); + } + inst(UNBOX_FLOAT, (boxed_float, unused[oparg] -- unboxed_float : PyRawFloat_Type, unused[oparg])) { double temp = ((PyFloatObject *)boxed_float)->ob_fval; Py_DECREF(boxed_float); @@ -3212,6 +3235,10 @@ dummy_func( top = Py_NewRef(bottom); } + inst(COPY_NO_INCREF, (bottom, unused[oparg - 1] -- bottom, unused[oparg - 1], top: *bottom)) { + assert(oparg > 0); + } + inst(BINARY_OP, (unused/1, lhs, rhs -- res)) { #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 8190fe7a4a5403..455fb6ee3a2520 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3,6 +3,24 @@ // Python/bytecodes.c // Do not edit! + #define UOP_BINARY_OP_MULTIPLY_INT_REST() \ + do { \ + STAT_INC(BINARY_OP, hit);\ + prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right);\ + _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);\ + _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);\ + if (prod == NULL) goto pop_2_error;\ + } while (0) + + #define UOP_BINARY_OP_SUBTRACT_INT_REST() \ + do { \ + STAT_INC(BINARY_OP, hit);\ + sub = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right);\ + _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);\ + _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);\ + if (sub == NULL) goto pop_2_error;\ + } while (0) + #define UOP_BINARY_OP_ADD_INT_REST() \ do { \ STAT_INC(BINARY_OP, hit);\ @@ -296,6 +314,17 @@ assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); + UOP_BINARY_OP_MULTIPLY_INT_REST(); + STACK_SHRINK(1); + stack_pointer[-1] = prod; + next_instr += 1; + DISPATCH(); + } + + TARGET(BINARY_OP_MULTIPLY_INT_REST) { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *prod; STAT_INC(BINARY_OP, hit); prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -303,7 +332,6 @@ if (prod == NULL) goto pop_2_error; STACK_SHRINK(1); stack_pointer[-1] = prod; - next_instr += 1; DISPATCH(); } @@ -331,6 +359,17 @@ assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); + UOP_BINARY_OP_SUBTRACT_INT_REST(); + STACK_SHRINK(1); + stack_pointer[-1] = sub; + next_instr += 1; + DISPATCH(); + } + + TARGET(BINARY_OP_SUBTRACT_INT_REST) { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *sub; STAT_INC(BINARY_OP, hit); sub = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); @@ -338,7 +377,6 @@ if (sub == NULL) goto pop_2_error; STACK_SHRINK(1); stack_pointer[-1] = sub; - next_instr += 1; DISPATCH(); } @@ -449,9 +487,14 @@ TARGET(UNARY_CHECK_FLOAT) { PyObject *arg = stack_pointer[-(1 + oparg)]; + PyObject *arg_unboxed; assert(cframe.use_tracing == 0); char is_successor = PyFloat_CheckExact(arg); bb_test = BB_TEST(is_successor, 0); + arg_unboxed = (is_successor + ? *((PyObject **)(&(((PyFloatObject *)arg)->ob_fval))) + : arg); + stack_pointer[-(1 + oparg)] = arg_unboxed; DISPATCH(); } @@ -467,6 +510,30 @@ DISPATCH(); } + TARGET(BINARY_OP_SUBTRACT_FLOAT_UNBOXED) { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *sum; + STAT_INC(BINARY_OP, hit); + double temp = *(double *)(&(left)) - *(double *)(&(right)); + sum = *(PyObject **)(&temp); + STACK_SHRINK(1); + stack_pointer[-1] = sum; + DISPATCH(); + } + + TARGET(BINARY_OP_MULTIPLY_FLOAT_UNBOXED) { + PyObject *right = stack_pointer[-1]; + PyObject *left = stack_pointer[-2]; + PyObject *prod; + STAT_INC(BINARY_OP, hit); + double temp = *(double *)(&(left)) * *(double *)(&(right)); + prod = *(PyObject **)(&temp); + STACK_SHRINK(1); + stack_pointer[-1] = prod; + DISPATCH(); + } + TARGET(UNBOX_FLOAT) { PyObject *boxed_float = stack_pointer[-(1 + oparg)]; PyObject *unboxed_float; @@ -4089,6 +4156,15 @@ DISPATCH(); } + TARGET(COPY_NO_INCREF) { + PyObject *bottom = stack_pointer[-(1 + (oparg - 1))]; + PyObject *top; + assert(oparg > 0); + STACK_GROW(1); + stack_pointer[-1] = top; + DISPATCH(); + } + TARGET(BINARY_OP) { PREDICTED(BINARY_OP); static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 1bb9f7b2926a4b..7f7200503960f6 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -59,10 +59,14 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 1; case BINARY_OP_MULTIPLY_INT: return 2; + case BINARY_OP_MULTIPLY_INT_REST: + return 2; case BINARY_OP_MULTIPLY_FLOAT: return 2; case BINARY_OP_SUBTRACT_INT: return 2; + case BINARY_OP_SUBTRACT_INT_REST: + return 2; case BINARY_OP_SUBTRACT_FLOAT: return 2; case BINARY_OP_ADD_UNICODE: @@ -77,6 +81,10 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return oparg + 1; case BINARY_OP_ADD_FLOAT_UNBOXED: return 2; + case BINARY_OP_SUBTRACT_FLOAT_UNBOXED: + return 2; + case BINARY_OP_MULTIPLY_FLOAT_UNBOXED: + return 2; case UNBOX_FLOAT: return oparg + 1; case BOX_FLOAT: @@ -379,6 +387,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0) + 1; case COPY: return (oparg-1) + 1; + case COPY_NO_INCREF: + return (oparg - 1) + 1; case BINARY_OP: return 2; case SWAP: @@ -461,10 +471,14 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 1; case BINARY_OP_MULTIPLY_INT: return 1; + case BINARY_OP_MULTIPLY_INT_REST: + return 1; case BINARY_OP_MULTIPLY_FLOAT: return 1; case BINARY_OP_SUBTRACT_INT: return 1; + case BINARY_OP_SUBTRACT_INT_REST: + return 1; case BINARY_OP_SUBTRACT_FLOAT: return 1; case BINARY_OP_ADD_UNICODE: @@ -479,6 +493,10 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return oparg + 1; case BINARY_OP_ADD_FLOAT_UNBOXED: return 1; + case BINARY_OP_SUBTRACT_FLOAT_UNBOXED: + return 1; + case BINARY_OP_MULTIPLY_FLOAT_UNBOXED: + return 1; case UNBOX_FLOAT: return oparg + 1; case BOX_FLOAT: @@ -781,6 +799,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 1; case COPY: return (oparg-1) + 2; + case COPY_NO_INCREF: + return (oparg - 1) + 2; case BINARY_OP: return 1; case SWAP: @@ -842,8 +862,10 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [UNARY_NOT] = { true, INSTR_FMT_IX }, [UNARY_INVERT] = { true, INSTR_FMT_IX }, [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC }, + [BINARY_OP_MULTIPLY_INT_REST] = { true, INSTR_FMT_IX }, [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC }, [BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IXC }, + [BINARY_OP_SUBTRACT_INT_REST] = { true, INSTR_FMT_IX }, [BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IXC }, [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC }, [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IX }, @@ -851,6 +873,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [BINARY_CHECK_FLOAT] = { true, INSTR_FMT_IX }, [UNARY_CHECK_FLOAT] = { true, INSTR_FMT_IB }, [BINARY_OP_ADD_FLOAT_UNBOXED] = { true, INSTR_FMT_IX }, + [BINARY_OP_SUBTRACT_FLOAT_UNBOXED] = { true, INSTR_FMT_IX }, + [BINARY_OP_MULTIPLY_FLOAT_UNBOXED] = { true, INSTR_FMT_IX }, [UNBOX_FLOAT] = { true, INSTR_FMT_IB }, [BOX_FLOAT] = { true, INSTR_FMT_IB }, [BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC }, @@ -1002,6 +1026,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [BUILD_SLICE] = { true, INSTR_FMT_IB }, [FORMAT_VALUE] = { true, INSTR_FMT_IB }, [COPY] = { true, INSTR_FMT_IB }, + [COPY_NO_INCREF] = { true, INSTR_FMT_IB }, [BINARY_OP] = { true, INSTR_FMT_IBC }, [SWAP] = { true, INSTR_FMT_IB }, [EXTENDED_ARG] = { true, INSTR_FMT_IB }, diff --git a/Python/tier2.c b/Python/tier2.c index 7a1e11a241398a..41d3521a606e3b 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -11,9 +11,9 @@ #define BB_DEBUG 1 #define TYPEPROP_DEBUG 1 // Max typed version basic blocks per basic block -#define MAX_BB_VERSIONS 5 +#define MAX_BB_VERSIONS 10 -#define OVERALLOCATE_FACTOR 4 +#define OVERALLOCATE_FACTOR 6 /* Dummy types used by the types propagator */ @@ -917,16 +917,19 @@ write_bb_id(_PyBBBranchCache *cache, int bb_id, bool is_type_guard) { // NEED TO ADD TO THIS EVERY TIME WE ADD A NEW ONE. static int type_guard_ladder[256] = { -1, - BINARY_CHECK_INT, BINARY_CHECK_FLOAT, + BINARY_CHECK_INT, + -1, + UNARY_CHECK_FLOAT, -1, }; // Type guard to index in the ladder. // KEEP IN SYNC WITH INDEX IN type_guard_ladder static int type_guard_to_index[256] = { - [BINARY_CHECK_INT] = 1, - [BINARY_CHECK_FLOAT] = 2, + [BINARY_CHECK_FLOAT] = 1, + [BINARY_CHECK_INT] = 2, + [UNARY_CHECK_FLOAT] = 4, }; @@ -1205,7 +1208,8 @@ add_metadata_to_jump_2d_array(_PyTier2Info *t2_info, _PyTier2BBMetadata *meta, // CACHE (bb_id of the current BB << 1 | is_type_branch) // // The BINARY_ADD then goes to the next BB static inline _Py_CODEUNIT * -infer_BINARY_OP_ADD( +infer_BINARY_OP( + int oparg, bool *needs_guard, _Py_CODEUNIT *prev_type_guard, _Py_CODEUNIT raw_op, @@ -1213,30 +1217,57 @@ infer_BINARY_OP_ADD( _PyTier2TypeContext *type_context, int bb_id) { + assert(oparg == NB_ADD || oparg == NB_SUBTRACT || oparg == NB_MULTIPLY); *needs_guard = false; PyTypeObject *right = typenode_get_type(type_context->type_stack_ptr[-1]); PyTypeObject *left = typenode_get_type(type_context->type_stack_ptr[-2]); if (left == &PyLong_Type) { if (right == &PyLong_Type) { - write_curr->op.code = BINARY_OP_ADD_INT_REST; + int opcode = oparg == NB_ADD + ? BINARY_OP_ADD_INT_REST + : oparg == NB_SUBTRACT + ? BINARY_OP_SUBTRACT_INT_REST + : oparg == NB_MULTIPLY + ? BINARY_OP_MULTIPLY_INT_REST + : (Py_UNREACHABLE(), 1); + write_curr->op.code = opcode; write_curr++; - type_propagate(BINARY_OP_ADD_INT_REST, 0, type_context, NULL); + type_propagate(opcode, 0, type_context, NULL); return write_curr; } } - if (left == &PyRawFloat_Type) { - if (right == &PyRawFloat_Type) { - write_curr->op.code = BINARY_OP_ADD_FLOAT_UNBOXED; + if ((left == &PyRawFloat_Type || left == &PyFloat_Type) && + (right == &PyRawFloat_Type || right == &PyFloat_Type)) { + int opcode = oparg == NB_ADD + ? BINARY_OP_ADD_FLOAT_UNBOXED + : oparg == NB_SUBTRACT + ? BINARY_OP_SUBTRACT_FLOAT_UNBOXED + : oparg == NB_MULTIPLY + ? BINARY_OP_MULTIPLY_FLOAT_UNBOXED + : (Py_UNREACHABLE(), 1); + if (right == &PyFloat_Type) { + write_curr->op.code = UNBOX_FLOAT; + write_curr->op.arg = 0; write_curr++; - type_propagate(BINARY_OP_ADD_FLOAT_UNBOXED, 0, type_context, NULL); - return write_curr; + type_propagate(UNBOX_FLOAT, 0, type_context, NULL); } + if (left == &PyFloat_Type) { + write_curr->op.code = UNBOX_FLOAT; + write_curr->op.arg = 1; + write_curr++; + type_propagate(UNBOX_FLOAT, 1, type_context, NULL); + } + write_curr->op.code = opcode; + write_curr++; + type_propagate(opcode, 0, type_context, NULL); + return write_curr; } + // Both side unknown // Unknown, time to emit the chain of guards. if (prev_type_guard == NULL) { write_curr = rebox_stack(write_curr, type_context, 2); *needs_guard = true; - return emit_type_guard(write_curr, BINARY_CHECK_INT, bb_id); + return emit_type_guard(write_curr, BINARY_CHECK_FLOAT, bb_id); } else { int next_guard = type_guard_ladder[ @@ -1248,8 +1279,6 @@ infer_BINARY_OP_ADD( } // End of ladder, fall through } - // Unknown, just emit the same opcode, don't bother emitting guard. - // Fall through and let the code generator handle. return NULL; } @@ -1364,6 +1393,17 @@ _PyTier2_Code_DetectAndEmitBB( } DISPATCH(); } + case COPY: { + // Read-only, only for us to inspect the types. DO NOT MODIFY HERE. + // ONLY THE TYPES PROPAGATOR SHOULD MODIFY THEIR INTERNAL VALUES. + _Py_TYPENODE_t **type_stackptr = &starting_type_context->type_stack_ptr; + PyTypeObject *pop = typenode_get_type(*TYPESTACK_PEEK(1 + (oparg - 1))); + // Writing unboxed val to a boxed val. + if (is_unboxed_type(pop)) { + opcode = specop = COPY_NO_INCREF; + } + DISPATCH(); + } case LOAD_CONST: { if (TYPECONST_GET_RAWTYPE(oparg) == &PyFloat_Type) { write_i->op.code = LOAD_CONST; @@ -1414,6 +1454,42 @@ _PyTier2_Code_DetectAndEmitBB( } DISPATCH(); } + case LOAD_FAST_CHECK: { + // Read-only, only for us to inspect the types. DO NOT MODIFY HERE. + // ONLY THE TYPES PROPAGATOR SHOULD MODIFY THEIR INTERNAL VALUES. + _Py_TYPENODE_t *type_locals = starting_type_context->type_locals; + // Writing unboxed val to a boxed val. + PyTypeObject *local = typenode_get_type(*TYPELOCALS_GET(oparg)); + if (is_unboxed_type(local)) { + opcode = specop = LOAD_FAST_NO_INCREF; + } + else { + if (local == &PyFloat_Type) { + write_i->op.code = LOAD_FAST; + write_i->op.arg = oparg; + write_i++; + type_propagate(LOAD_FAST, + oparg, starting_type_context, consts); + write_i->op.code = UNBOX_FLOAT; + write_i->op.arg = 0; + write_i++; + type_propagate(UNBOX_FLOAT, 0, starting_type_context, consts); + write_i->op.code = STORE_FAST_UNBOXED_BOXED; + write_i->op.arg = oparg; + write_i++; + type_propagate(STORE_FAST_UNBOXED_BOXED, + oparg, starting_type_context, consts); + write_i->op.code = LOAD_FAST_NO_INCREF; + write_i->op.arg = oparg; + write_i++; + type_propagate(LOAD_FAST_NO_INCREF, + oparg, starting_type_context, consts); + continue; + } + opcode = specop = LOAD_FAST_CHECK; + } + DISPATCH(); + } case STORE_FAST: { // Read-only, only for us to inspect the types. DO NOT MODIFY HERE. // ONLY THE TYPES PROPAGATOR SHOULD MODIFY THEIR INTERNAL VALUES. @@ -1449,9 +1525,9 @@ _PyTier2_Code_DetectAndEmitBB( case BUILD_LIST: DISPATCH_REBOX(oparg); case BINARY_OP: - if (oparg == NB_ADD) { + if (oparg == NB_ADD || oparg == NB_SUBTRACT || oparg == NB_MULTIPLY) { // Add operation. Need to check if we can infer types. - _Py_CODEUNIT *possible_next = infer_BINARY_OP_ADD(&needs_guard, + _Py_CODEUNIT *possible_next = infer_BINARY_OP(oparg, &needs_guard, prev_type_guard, *curr, write_i, starting_type_context, @@ -1477,11 +1553,14 @@ _PyTier2_Code_DetectAndEmitBB( case UNARY_NOT: case UNARY_INVERT: case GET_LEN: + case UNPACK_SEQUENCE: DISPATCH_REBOX(1); case CALL_INTRINSIC_2: case BINARY_SUBSCR: case BINARY_SLICE: DISPATCH_REBOX(2); + case STORE_SUBSCR: + DISPATCH_REBOX(4); case STORE_SLICE: DISPATCH_REBOX(4); default: @@ -1807,6 +1886,8 @@ IS_OPTIMIZABLE_OPCODE(int opcode, int oparg) switch (_PyOpcode_Deopt[opcode]) { case BINARY_OP: switch (oparg) { + case NB_SUBTRACT: + case NB_MULTIPLY: case NB_ADD: // We want a specialised form, not the generic BINARY_OP. return opcode != _PyOpcode_Deopt[opcode]; diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index 13093092ba8a70..9cdc9b062095c8 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -120,6 +120,12 @@ break; } + TARGET(BINARY_OP_MULTIPLY_INT_REST) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyLong_Type), TYPESTACK_PEEK(1), true); + break; + } + TARGET(BINARY_OP_MULTIPLY_FLOAT) { STACK_SHRINK(1); TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); @@ -132,6 +138,12 @@ break; } + TARGET(BINARY_OP_SUBTRACT_INT_REST) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyLong_Type), TYPESTACK_PEEK(1), true); + break; + } + TARGET(BINARY_OP_SUBTRACT_FLOAT) { STACK_SHRINK(1); TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); @@ -164,7 +176,8 @@ } TARGET(UNARY_CHECK_FLOAT) { - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(1 + oparg), true); + TYPE_SET((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(1 + oparg), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyRawFloat_Type), TYPESTACK_PEEK(1 + oparg), true); break; } @@ -174,6 +187,18 @@ break; } + TARGET(BINARY_OP_SUBTRACT_FLOAT_UNBOXED) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyRawFloat_Type), TYPESTACK_PEEK(1), true); + break; + } + + TARGET(BINARY_OP_MULTIPLY_FLOAT_UNBOXED) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyRawFloat_Type), TYPESTACK_PEEK(1), true); + break; + } + TARGET(UNBOX_FLOAT) { TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyRawFloat_Type), TYPESTACK_PEEK(1 + oparg), true); break; @@ -967,6 +992,13 @@ break; } + TARGET(COPY_NO_INCREF) { + _Py_TYPENODE_t *bottom = TYPESTACK_PEEK(1 + (oparg - 1)); + STACK_GROW(1); + TYPE_OVERWRITE(bottom, TYPESTACK_PEEK(1), false); + break; + } + TARGET(BINARY_OP) { STACK_SHRINK(1); TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); From cfe1e1a75e551806a875386390338bbb813974ae Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 31 Mar 2023 05:52:36 +0800 Subject: [PATCH 251/280] fix up type check ladder generation --- Python/ceval.c | 3 ++- Python/tier2.c | 12 +++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index e09966d449f23e..ad458ea6194063 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1010,7 +1010,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int PyObject **stackbase = _PyFrame_Stackbase(frame); while (stack_pointer > stackbase) { PyObject *o = POP(); - Py_XDECREF(o); + // @TODO UNDO ME ONCE FINISHING DEBUGGING + // Py_XDECREF(o); } assert(STACK_LEVEL() == 0); _PyFrame_SetStackPointer(frame, stack_pointer); diff --git a/Python/tier2.c b/Python/tier2.c index 41d3521a606e3b..dc66c756918de7 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -1209,6 +1209,7 @@ add_metadata_to_jump_2d_array(_PyTier2Info *t2_info, _PyTier2BBMetadata *meta, // // The BINARY_ADD then goes to the next BB static inline _Py_CODEUNIT * infer_BINARY_OP( + _Py_CODEUNIT *t2_start, int oparg, bool *needs_guard, _Py_CODEUNIT *prev_type_guard, @@ -1218,6 +1219,7 @@ infer_BINARY_OP( int bb_id) { assert(oparg == NB_ADD || oparg == NB_SUBTRACT || oparg == NB_MULTIPLY); + bool is_first_instr = (write_curr == t2_start); *needs_guard = false; PyTypeObject *right = typenode_get_type(type_context->type_stack_ptr[-1]); PyTypeObject *left = typenode_get_type(type_context->type_stack_ptr[-2]); @@ -1262,9 +1264,12 @@ infer_BINARY_OP( type_propagate(opcode, 0, type_context, NULL); return write_curr; } - // Both side unknown // Unknown, time to emit the chain of guards. - if (prev_type_guard == NULL) { + // No type guard before this, or it's not the first in the new BB. + // First in new BB usually indicates it's already part of a pre-existing ladder. + if (prev_type_guard == NULL || + (!is_first_instr && prev_type_guard != NULL && + type_guard_ladder[type_guard_to_index[prev_type_guard->op.code] + 1] != -1)) { write_curr = rebox_stack(write_curr, type_context, 2); *needs_guard = true; return emit_type_guard(write_curr, BINARY_CHECK_FLOAT, bb_id); @@ -1527,7 +1532,8 @@ _PyTier2_Code_DetectAndEmitBB( case BINARY_OP: if (oparg == NB_ADD || oparg == NB_SUBTRACT || oparg == NB_MULTIPLY) { // Add operation. Need to check if we can infer types. - _Py_CODEUNIT *possible_next = infer_BINARY_OP(oparg, &needs_guard, + _Py_CODEUNIT *possible_next = infer_BINARY_OP(t2_start, + oparg, &needs_guard, prev_type_guard, *curr, write_i, starting_type_context, From 15aa9c10db4c5e382930757981c83d94f2071335 Mon Sep 17 00:00:00 2001 From: Jules <57632293+JuliaPoo@users.noreply.github.com> Date: Fri, 31 Mar 2023 16:08:24 +0800 Subject: [PATCH 252/280] Fix: Bug in typeprop handling UNPACK_*, and bug in COPY_NO_INCREF (#32) --- Python/bytecodes.c | 5 +- Python/generated_cases.c.h | 5 +- Python/opcode_metadata.h | 2 +- Python/tier2.c | 4 +- Python/tier2_typepropagator.c.h | 10 +- Tools/cases_generator/generate_cases.py | 156 +++--------------------- Tools/cases_generator/parser.py | 1 + 7 files changed, 33 insertions(+), 150 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 7b3e11a7799373..993fb1523ceb42 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -978,7 +978,7 @@ dummy_func( UNPACK_SEQUENCE_LIST, }; - inst(UNPACK_SEQUENCE, (unused/1, seq -- unused[oparg])) { + inst(UNPACK_SEQUENCE, (unused/1, seq -- values[oparg])) { #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1028,7 +1028,7 @@ dummy_func( DECREF_INPUTS(); } - inst(UNPACK_EX, (seq -- unused[oparg & 0xFF], unused, unused[oparg >> 8])) { + inst(UNPACK_EX, (seq -- unused[oparg >> 8], unused, values[oparg & 0xFF])) { int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); @@ -3237,6 +3237,7 @@ dummy_func( inst(COPY_NO_INCREF, (bottom, unused[oparg - 1] -- bottom, unused[oparg - 1], top: *bottom)) { assert(oparg > 0); + top = bottom; } inst(BINARY_OP, (unused/1, lhs, rhs -- res)) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 455fb6ee3a2520..8ac8cfcf530627 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1318,6 +1318,7 @@ PREDICTED(UNPACK_SEQUENCE); static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); PyObject *seq = stack_pointer[-1]; + PyObject **values = stack_pointer - (1); #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -1391,12 +1392,13 @@ TARGET(UNPACK_EX) { PyObject *seq = stack_pointer[-1]; + PyObject **values = stack_pointer - (1) + 1 + (oparg >> 8); int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); Py_DECREF(seq); if (res == 0) goto pop_1_error; - STACK_GROW((oparg & 0xFF) + (oparg >> 8)); + STACK_GROW((oparg >> 8) + (oparg & 0xFF)); DISPATCH(); } @@ -4160,6 +4162,7 @@ PyObject *bottom = stack_pointer[-(1 + (oparg - 1))]; PyObject *top; assert(oparg > 0); + top = bottom; STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 7f7200503960f6..be21be496104fb 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -582,7 +582,7 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { case UNPACK_SEQUENCE_LIST: return oparg; case UNPACK_EX: - return (oparg & 0xFF) + (oparg >> 8) + 1; + return (oparg >> 8) + (oparg & 0xFF) + 1; case STORE_ATTR: return 0; case DELETE_ATTR: diff --git a/Python/tier2.c b/Python/tier2.c index dc66c756918de7..0e869925135523 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -121,8 +121,8 @@ _PyTier2TypeContext_Copy(const _PyTier2TypeContext *type_context) } // Is part of stack else { -#if TYPEPROP_DEBUG int offset_stack = (int)(parent - type_context->type_stack); +#if TYPEPROP_DEBUG assert(0 <= offset_stack && offset_stack < nstack); #endif type_locals[i] = _Py_TYPENODE_MAKE_REF((_Py_TYPENODE_t)(&type_stack[offset_stack])); @@ -152,8 +152,8 @@ _PyTier2TypeContext_Copy(const _PyTier2TypeContext *type_context) } // Is part of stack else { -#if TYPEPROP_DEBUG int offset_stack = (int)(parent - type_context->type_stack); +#if TYPEPROP_DEBUG assert(0 <= offset_stack && offset_stack < nstack); #endif type_stack[i] = _Py_TYPENODE_MAKE_REF((_Py_TYPENODE_t)(&type_stack[offset_stack])); diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index 9cdc9b062095c8..df008d7028e8ed 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -375,32 +375,34 @@ TARGET(UNPACK_SEQUENCE) { STACK_SHRINK(1); STACK_GROW(oparg); + for (int i = 0; i < (oparg); i++) {TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(oparg - i), true);} break; } TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { STACK_SHRINK(1); STACK_GROW(oparg); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(oparg), true); + for (int i = 0; i < (oparg); i++) {TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(oparg - i), true);} break; } TARGET(UNPACK_SEQUENCE_TUPLE) { STACK_SHRINK(1); STACK_GROW(oparg); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(oparg), true); + for (int i = 0; i < (oparg); i++) {TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(oparg - i), true);} break; } TARGET(UNPACK_SEQUENCE_LIST) { STACK_SHRINK(1); STACK_GROW(oparg); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(oparg), true); + for (int i = 0; i < (oparg); i++) {TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(oparg - i), true);} break; } TARGET(UNPACK_EX) { - STACK_GROW((oparg & 0xFF) + (oparg >> 8)); + STACK_GROW((oparg >> 8) + (oparg & 0xFF)); + for (int i = 0; i < (oparg & 0xFF); i++) {TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK((oparg & 0xFF) - i), true);} break; } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index 1255ba463f5a8b..caa224493ae5d9 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -335,146 +335,6 @@ def __init__(self, inst: parser.InstDef): cache = "0" self.instr_fmt = fmt - def write_typeprop(self, out: Formatter) -> None: - """Write one instruction's type propagation rules""" - - # TODO: Detect loops like in SWAP - - need_to_declare = [] - # Stack input is used in local effect - if self.local_effects and \ - isinstance(val := self.local_effects.value, TypeSrcStackInput): - need_to_declare.append(val.name) - # Stack input is used in output effect - for oeffect in self.output_effects: - if not (typ := oeffect.type_annotation): continue - ops = typ.ops - for op in ops: - if not isinstance(src := op.src, TypeSrcStackInput): continue - if oeffect.name in self.unmoved_names and oeffect.name == src.name: - print( - f"Warn: {self.name} type annotation for {oeffect.name} will be ignored " - "as it is unmoved") - continue - need_to_declare.append(src.name) - - # Write input stack effect variable declarations and initializations - ieffects = list(reversed(self.input_effects)) - usable_for_local_effect = {} - all_input_effect_names = {} - for i, ieffect in enumerate(ieffects): - - if ieffect.name not in need_to_declare: continue - - isize = string_effect_size( - list_effect_size([ieff for ieff in ieffects[: i + 1]]) - ) - all_input_effect_names[ieffect.name] = (ieffect, i) - dst = StackEffect(ieffect.name, "_Py_TYPENODE_t *") - if ieffect.size: - # TODO: Support more cases as needed - raise Exception("Type propagation across sized input effect not implemented") - elif ieffect.cond: - src = StackEffect(f"({ieffect.cond}) ? TYPESTACK_PEEK({isize}) : NULL", "_Py_TYPENODE_t *") - else: - usable_for_local_effect[ieffect.name] = ieffect - src = StackEffect(f"TYPESTACK_PEEK({isize})", "_Py_TYPENODE_t *") - out.declare(dst, src) - - # Write localarr effect - if self.local_effects: - - idx = self.local_effects.index - val = self.local_effects.value - - typ_op = "TYPE_OVERWRITE" - dst = f"TYPELOCALS_GET({idx})" - match val: - case TypeSrcLiteral(name=valstr): - if valstr == "NULL": - src = "(_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT" - flag = "true" - else: - src = f"(_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&{valstr})" - flag = "true" - case TypeSrcStackInput(name=valstr): - assert valstr in usable_for_local_effect, \ - "`cond` and `size` stackvar not supported for localeffect" - src = valstr - flag = "false" - # TODO: Support more cases as needed - case TypeSrcConst(): - raise Exception("Not implemented") - case TypeSrcLocals(): - raise Exception("Not implemented") - case _: - typing.assert_never(val) - out.emit(f"{typ_op}({src}, {dst}, {flag});") - - # Update stack size - out.stack_adjust( - 0, - [ieff for ieff in self.input_effects], - [oeff for oeff in self.output_effects], - ) - - # Stack effect - oeffects = list(reversed(self.output_effects)) - for i, oeffect in enumerate(oeffects): - osize = string_effect_size( - list_effect_size([oeff for oeff in oeffects[: i + 1]]) - ) - dst = f"TYPESTACK_PEEK({osize})" - - # Check if it's even used - if oeffect.name == UNUSED: continue - - # Check if there's type info - if typ := oeffect.type_annotation: - for op in typ.ops: - match op.src: - case TypeSrcLiteral(literal=valstr): - if valstr == "NULL": - src = "(_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT" - flag = "true" - else: - src = f"(_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&{valstr})" - flag = "true" - case TypeSrcStackInput(name=valstr): - assert valstr in need_to_declare - assert oeffect.name not in self.unmoved_names - src = valstr - flag = "false" - case TypeSrcConst(index=idx): - src = f"(_Py_TYPENODE_t *)TYPECONST_GET({idx})" - flag = "true" - case TypeSrcLocals(index=idx): - src = f"TYPELOCALS_GET({idx})" - flag = "false" - case _: - typing.assert_never(op.src) - - opstr = f"{op.op}({src}, {dst}, {flag})" - if oeffect.cond: - out.emit(f"if ({oeffect.cond}) {{ {opstr}; }}") - else: - out.emit(f"{opstr};") - continue - - # Don't touch unmoved stack vars - if oeffect.name in self.unmoved_names: - continue - - # Just output null - typ_op = "TYPE_OVERWRITE" - src = "(_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT" - flag = "true" - opstr = f"{typ_op}({src}, {dst}, {flag})" - if oeffect.cond: - out.emit(f"if ({oeffect.cond}) {{ {opstr}; }}") - else: - out.emit(f"{opstr};") - def write(self, out: Formatter) -> None: """Write one instruction, sans prologue and epilogue.""" # Write a static assertion that a family's cache size is correct @@ -635,6 +495,8 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None def write_typeprop(self, out: Formatter) -> None: """Write one instruction's type propagation rules""" + # TODO: Add SWAP to DSL + need_to_declare = [] # Stack input is used in local effect if self.local_effects and \ @@ -724,6 +586,20 @@ def write_typeprop(self, out: Formatter) -> None: # Check if it's even used if oeffect.name == UNUSED: continue + # For now assume OVERWRITE with NULL + if oeffect.size: + op = "TYPE_OVERWRITE" + src = "(_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT" + flag = "true" + dst = f"TYPESTACK_PEEK({osize} - i)" + opstr = "".join([ + f"for (int i = 0; i < ({oeffect.size}); i++) {{" + f"{op}({src}, {dst}, {flag});" + f"}}" + ]) + out.emit(opstr) + continue + # Check if there's type info if typ := oeffect.type_annotation: for op in typ.ops: diff --git a/Tools/cases_generator/parser.py b/Tools/cases_generator/parser.py index 658b1b0d46c513..5c87a2b85a2dd6 100644 --- a/Tools/cases_generator/parser.py +++ b/Tools/cases_generator/parser.py @@ -343,6 +343,7 @@ def stack_effect(self) -> StackEffect | None: cond_text = cond.text.strip() size_text = "" if self.expect(lx.LBRACKET): + # TODO: Support type annotation for size output if has_type_annotation or cond_text: raise self.make_syntax_error("Unexpected [") if not (size := self.expression()): From 48212848926a16666cc099a1de46216d59ed0380 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 31 Mar 2023 21:44:46 +0800 Subject: [PATCH 253/280] Add guardless container ops --- Include/internal/pycore_code.h | 1 + Include/internal/pycore_opcode.h | 8 +- Include/opcode.h | 20 ++-- Lib/opcode.py | 11 ++- Objects/codeobject.c | 22 +++-- Python/bytecodes.c | 31 ++++--- Python/ceval.c | 3 +- Python/generated_cases.c.h | 75 +++++++++++---- Python/opcode_metadata.h | 20 +++- Python/tier2.c | 152 ++++++++++++++++++++++++++----- Python/tier2_typepropagator.c.h | 23 +++-- 11 files changed, 280 insertions(+), 86 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index c62c39a6a080d6..add3dfc28a436c 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -285,6 +285,7 @@ extern _Py_CODEUNIT *_PyTier2_LocateJumpBackwardsBB( _Py_CODEUNIT **tier1_fallback, _Py_CODEUNIT *curr, int stacksize); extern void _PyTier2_RewriteForwardJump(_Py_CODEUNIT *bb_branch, _Py_CODEUNIT *target); extern void _PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *target); +void _PyTier2TypeContext_Free(_PyTier2TypeContext *type_context); #ifdef Py_STATS diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index 71491b83e71a56..ce1195d45819ea 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -422,13 +422,15 @@ static const char *const _PyOpcode_OpName[263] = { [BB_JUMP_BACKWARD_LAZY] = "BB_JUMP_BACKWARD_LAZY", [BINARY_CHECK_INT] = "BINARY_CHECK_INT", [BINARY_CHECK_FLOAT] = "BINARY_CHECK_FLOAT", - [UNARY_CHECK_FLOAT] = "UNARY_CHECK_FLOAT", + [CHECK_LIST] = "CHECK_LIST", [BINARY_OP_ADD_INT_REST] = "BINARY_OP_ADD_INT_REST", [BINARY_OP_ADD_FLOAT_UNBOXED] = "BINARY_OP_ADD_FLOAT_UNBOXED", [BINARY_OP_SUBTRACT_INT_REST] = "BINARY_OP_SUBTRACT_INT_REST", [BINARY_OP_SUBTRACT_FLOAT_UNBOXED] = "BINARY_OP_SUBTRACT_FLOAT_UNBOXED", [BINARY_OP_MULTIPLY_INT_REST] = "BINARY_OP_MULTIPLY_INT_REST", [BINARY_OP_MULTIPLY_FLOAT_UNBOXED] = "BINARY_OP_MULTIPLY_FLOAT_UNBOXED", + [BINARY_SUBSCR_LIST_INT_REST] = "BINARY_SUBSCR_LIST_INT_REST", + [STORE_SUBSCR_LIST_INT_REST] = "STORE_SUBSCR_LIST_INT_REST", [POP_TOP_NO_DECREF] = "POP_TOP_NO_DECREF", [UNBOX_FLOAT] = "UNBOX_FLOAT", [BOX_FLOAT] = "BOX_FLOAT", @@ -437,8 +439,6 @@ static const char *const _PyOpcode_OpName[263] = { [STORE_FAST_BOXED_UNBOXED] = "STORE_FAST_BOXED_UNBOXED", [STORE_FAST_UNBOXED_BOXED] = "STORE_FAST_UNBOXED_BOXED", [STORE_FAST_UNBOXED_UNBOXED] = "STORE_FAST_UNBOXED_UNBOXED", - [204] = "<204>", - [205] = "<205>", [206] = "<206>", [207] = "<207>", [208] = "<208>", @@ -501,8 +501,6 @@ static const char *const _PyOpcode_OpName[263] = { #define EXTRA_CASES \ - case 204: \ - case 205: \ case 206: \ case 207: \ case 208: \ diff --git a/Include/opcode.h b/Include/opcode.h index c0c5a79fd9da38..3d99716fec63e6 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -206,21 +206,23 @@ extern "C" { #define BB_JUMP_BACKWARD_LAZY 186 #define BINARY_CHECK_INT 187 #define BINARY_CHECK_FLOAT 188 -#define UNARY_CHECK_FLOAT 189 +#define CHECK_LIST 189 #define BINARY_OP_ADD_INT_REST 190 #define BINARY_OP_ADD_FLOAT_UNBOXED 191 #define BINARY_OP_SUBTRACT_INT_REST 192 #define BINARY_OP_SUBTRACT_FLOAT_UNBOXED 193 #define BINARY_OP_MULTIPLY_INT_REST 194 #define BINARY_OP_MULTIPLY_FLOAT_UNBOXED 195 -#define POP_TOP_NO_DECREF 196 -#define UNBOX_FLOAT 197 -#define BOX_FLOAT 198 -#define COPY_NO_INCREF 199 -#define LOAD_FAST_NO_INCREF 200 -#define STORE_FAST_BOXED_UNBOXED 201 -#define STORE_FAST_UNBOXED_BOXED 202 -#define STORE_FAST_UNBOXED_UNBOXED 203 +#define BINARY_SUBSCR_LIST_INT_REST 196 +#define STORE_SUBSCR_LIST_INT_REST 197 +#define POP_TOP_NO_DECREF 198 +#define UNBOX_FLOAT 199 +#define BOX_FLOAT 200 +#define COPY_NO_INCREF 201 +#define LOAD_FAST_NO_INCREF 202 +#define STORE_FAST_BOXED_UNBOXED 203 +#define STORE_FAST_UNBOXED_BOXED 204 +#define STORE_FAST_UNBOXED_UNBOXED 205 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/opcode.py b/Lib/opcode.py index a3d60584a877d8..1e26407a16ab06 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -446,6 +446,7 @@ def pseudo_op(name, op, real_ops): 'BINARY_OP_SUBTRACT_INT', 'BINARY_OP_MULTIPLY_INT', 'BINARY_OP_ADD_FLOAT', + 'BINARY_SUBSCR_LIST_INT', ] _uops = [ # Tier 2 BB opcodes @@ -491,8 +492,10 @@ def pseudo_op(name, op, real_ops): # single operand forms. 'BINARY_CHECK_INT', 'BINARY_CHECK_FLOAT', - 'UNARY_CHECK_FLOAT', - # 'BINARY_CHECK_STR', + 'CHECK_LIST', + + # These are guardless instructions + ## Arithmetic 'BINARY_OP_ADD_INT_REST', 'BINARY_OP_ADD_FLOAT_UNBOXED', 'BINARY_OP_SUBTRACT_INT_REST', @@ -500,6 +503,10 @@ def pseudo_op(name, op, real_ops): 'BINARY_OP_MULTIPLY_INT_REST', 'BINARY_OP_MULTIPLY_FLOAT_UNBOXED', + # Containers + 'BINARY_SUBSCR_LIST_INT_REST', + 'STORE_SUBSCR_LIST_INT_REST', + # Boxing / unboxing ops 'POP_TOP_NO_DECREF', 'UNBOX_FLOAT', diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 3b1edc08f54786..f60aea5e4d46a5 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1713,12 +1713,6 @@ code_tier2_fini(PyCodeObject *co) _PyTier2Info *t2_info = co->_tier2_info; t2_info->_entry_bb = NULL; if (t2_info->_bb_space != NULL) { - // Traverse the linked list - //for (_PyTier2BBSpace *curr = t2_info->_bb_space; curr != NULL;) { - // _PyTier2BBSpace *prev = curr; - // curr = curr->next; - // PyMem_Free(prev); - //} PyMem_Free(t2_info->_bb_space); t2_info->_bb_space = NULL; } @@ -1727,12 +1721,28 @@ code_tier2_fini(PyCodeObject *co) t2_info->backward_jump_offsets != NULL) { PyMem_Free(t2_info->backward_jump_offsets); t2_info->backward_jump_offsets = NULL; + _PyTier2BBStartTypeContextTriplet **backward_jump_target_bb_pairs = t2_info->backward_jump_target_bb_pairs; + //int backwards_jump_count = t2_info->backward_jump_count; + //for (int i = 0; i < backwards_jump_count; i++) { + // PyMem_Free(backward_jump_target_bb_pairs[i]); + //} + PyMem_Free(backward_jump_target_bb_pairs); } t2_info->backward_jump_count = 0; if (t2_info->bb_data != NULL && t2_info->bb_data_len > 0) { PyMem_Free(t2_info->bb_data); } + //if (t2_info->bb_data != NULL) { + // for (int i = 0; i < t2_info->bb_data_curr; i++) { + // if (t2_info->bb_data[i] != NULL) { + // _PyTier2BBMetadata *meta = t2_info->bb_data[i]; + // //_PyTier2TypeContext_Free(meta->type_context); + // //PyMem_Free(meta); + // } + // } + // PyMem_Free(t2_info->bb_data); + //} t2_info->bb_data_len = 0; PyMem_Free(t2_info); } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 993fb1523ceb42..d0f2d04dfead0f 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -326,15 +326,6 @@ dummy_func( : right); } - inst(UNARY_CHECK_FLOAT, (arg, unused[oparg] -- arg_unboxed : { <<= PyFloat_Type, PyRawFloat_Type}, unused[oparg])) { - assert(cframe.use_tracing == 0); - char is_successor = PyFloat_CheckExact(arg); - bb_test = BB_TEST(is_successor, 0); - arg_unboxed = (is_successor - ? *((PyObject **)(&(((PyFloatObject *)arg)->ob_fval))) - : arg); - } - inst(BINARY_OP_ADD_FLOAT_UNBOXED, (left, right -- sum : PyRawFloat_Type)) { STAT_INC(BINARY_OP, hit); double temp = *(double *)(&(left)) + *(double *)(&(right)); @@ -439,14 +430,18 @@ dummy_func( ERROR_IF(err, error); } - inst(BINARY_SUBSCR_LIST_INT, (unused/4, list, sub -- res)) { + macro_inst(BINARY_SUBSCR_LIST_INT, (unused/4, list, sub -- res)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR); // Deopt unless 0 <= sub < PyList_Size(list) DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); - Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; + U_INST(BINARY_SUBSCR_LIST_INT_REST); + } + + u_inst(BINARY_SUBSCR_LIST_INT_REST, (list, sub -- res)) { + Py_ssize_t index = ((PyLongObject *)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyList_GET_ITEM(list, index); @@ -456,6 +451,11 @@ dummy_func( Py_DECREF(list); } + inst(CHECK_LIST, (container, unused[oparg] -- container : { <<= PyList_Type, PyList_Type}, unused[oparg])) { + char is_successor = PyList_CheckExact(container); + bb_test = BB_TEST(is_successor, 0); + } + inst(BINARY_SUBSCR_TUPLE_INT, (unused/4, tuple, sub -- res)) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR); @@ -548,7 +548,7 @@ dummy_func( ERROR_IF(err, error); } - inst(STORE_SUBSCR_LIST_INT, (unused/1, value, list, sub -- )) { + macro_inst(STORE_SUBSCR_LIST_INT, (unused/1, value, list, sub -- )) { assert(cframe.use_tracing == 0); DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR); DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR); @@ -556,7 +556,12 @@ dummy_func( // Ensure nonnegative, zero-or-one-digit ints. DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), STORE_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; - // Ensure index < len(list) + U_INST(STORE_SUBSCR_LIST_INT_REST); + } + + u_inst(STORE_SUBSCR_LIST_INT_REST, (value, list, sub -- )) { + Py_ssize_t index = ((PyLongObject *)sub)->long_value.ob_digit[0]; + /* Ensure index < len(list) */ DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); diff --git a/Python/ceval.c b/Python/ceval.c index ad458ea6194063..6cf504a91e0c35 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1010,8 +1010,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int PyObject **stackbase = _PyFrame_Stackbase(frame); while (stack_pointer > stackbase) { PyObject *o = POP(); - // @TODO UNDO ME ONCE FINISHING DEBUGGING - // Py_XDECREF(o); + Py_XDECREF(o); } assert(STACK_LEVEL() == 0); _PyFrame_SetStackPointer(frame, stack_pointer); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 8ac8cfcf530627..d0dde435a97081 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -30,6 +30,33 @@ if (sum == NULL) goto pop_2_error;\ } while (0) + #define UOP_BINARY_SUBSCR_LIST_INT_REST() \ + do { \ + Py_ssize_t index = ((PyLongObject *)sub)->long_value.ob_digit[0];\ + DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR);\ + STAT_INC(BINARY_SUBSCR, hit);\ + res = PyList_GET_ITEM(list, index);\ + assert(res != NULL);\ + Py_INCREF(res);\ + _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free);\ + Py_DECREF(list);\ + } while (0) + + #define UOP_STORE_SUBSCR_LIST_INT_REST() \ + do { \ + Py_ssize_t index = ((PyLongObject *)sub)->long_value.ob_digit[0];\ + /* Ensure index < len(list) */\ + DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR);\ + STAT_INC(STORE_SUBSCR, hit);\ +\ + PyObject *old_value = PyList_GET_ITEM(list, index);\ + PyList_SET_ITEM(list, index, value);\ + assert(old_value != NULL);\ + Py_DECREF(old_value);\ + _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free);\ + Py_DECREF(list);\ + } while (0) + TARGET(NOP) { DISPATCH(); } @@ -485,19 +512,6 @@ DISPATCH(); } - TARGET(UNARY_CHECK_FLOAT) { - PyObject *arg = stack_pointer[-(1 + oparg)]; - PyObject *arg_unboxed; - assert(cframe.use_tracing == 0); - char is_successor = PyFloat_CheckExact(arg); - bb_test = BB_TEST(is_successor, 0); - arg_unboxed = (is_successor - ? *((PyObject **)(&(((PyFloatObject *)arg)->ob_fval))) - : arg); - stack_pointer[-(1 + oparg)] = arg_unboxed; - DISPATCH(); - } - TARGET(BINARY_OP_ADD_FLOAT_UNBOXED) { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; @@ -669,7 +683,18 @@ // Deopt unless 0 <= sub < PyList_Size(list) DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), BINARY_SUBSCR); - Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; + UOP_BINARY_SUBSCR_LIST_INT_REST(); + STACK_SHRINK(1); + stack_pointer[-1] = res; + next_instr += 4; + DISPATCH(); + } + + TARGET(BINARY_SUBSCR_LIST_INT_REST) { + PyObject *sub = stack_pointer[-1]; + PyObject *list = stack_pointer[-2]; + PyObject *res; + Py_ssize_t index = ((PyLongObject *)sub)->long_value.ob_digit[0]; DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR); STAT_INC(BINARY_SUBSCR, hit); res = PyList_GET_ITEM(list, index); @@ -679,7 +704,13 @@ Py_DECREF(list); STACK_SHRINK(1); stack_pointer[-1] = res; - next_instr += 4; + DISPATCH(); + } + + TARGET(CHECK_LIST) { + PyObject *container = stack_pointer[-(1 + oparg)]; + char is_successor = PyList_CheckExact(container); + bb_test = BB_TEST(is_successor, 0); DISPATCH(); } @@ -819,7 +850,18 @@ // Ensure nonnegative, zero-or-one-digit ints. DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub), STORE_SUBSCR); Py_ssize_t index = ((PyLongObject*)sub)->long_value.ob_digit[0]; - // Ensure index < len(list) + UOP_STORE_SUBSCR_LIST_INT_REST(); + STACK_SHRINK(3); + next_instr += 1; + DISPATCH(); + } + + TARGET(STORE_SUBSCR_LIST_INT_REST) { + PyObject *sub = stack_pointer[-1]; + PyObject *list = stack_pointer[-2]; + PyObject *value = stack_pointer[-3]; + Py_ssize_t index = ((PyLongObject *)sub)->long_value.ob_digit[0]; + /* Ensure index < len(list) */ DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR); STAT_INC(STORE_SUBSCR, hit); @@ -830,7 +872,6 @@ _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); STACK_SHRINK(3); - next_instr += 1; DISPATCH(); } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index be21be496104fb..c62dd4c48b7c03 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -77,8 +77,6 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 2; case BINARY_CHECK_FLOAT: return 2; - case UNARY_CHECK_FLOAT: - return oparg + 1; case BINARY_OP_ADD_FLOAT_UNBOXED: return 2; case BINARY_OP_SUBTRACT_FLOAT_UNBOXED: @@ -103,6 +101,10 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 4; case BINARY_SUBSCR_LIST_INT: return 2; + case BINARY_SUBSCR_LIST_INT_REST: + return 2; + case CHECK_LIST: + return oparg + 1; case BINARY_SUBSCR_TUPLE_INT: return 2; case BINARY_SUBSCR_DICT: @@ -117,6 +119,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { return 3; case STORE_SUBSCR_LIST_INT: return 3; + case STORE_SUBSCR_LIST_INT_REST: + return 3; case STORE_SUBSCR_DICT: return 3; case DELETE_SUBSCR: @@ -489,8 +493,6 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 1; case BINARY_CHECK_FLOAT: return 2; - case UNARY_CHECK_FLOAT: - return oparg + 1; case BINARY_OP_ADD_FLOAT_UNBOXED: return 1; case BINARY_OP_SUBTRACT_FLOAT_UNBOXED: @@ -515,6 +517,10 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case BINARY_SUBSCR_LIST_INT: return 1; + case BINARY_SUBSCR_LIST_INT_REST: + return 1; + case CHECK_LIST: + return oparg + 1; case BINARY_SUBSCR_TUPLE_INT: return 1; case BINARY_SUBSCR_DICT: @@ -529,6 +535,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { return 0; case STORE_SUBSCR_LIST_INT: return 0; + case STORE_SUBSCR_LIST_INT_REST: + return 0; case STORE_SUBSCR_DICT: return 0; case DELETE_SUBSCR: @@ -871,7 +879,6 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IX }, [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC }, [BINARY_CHECK_FLOAT] = { true, INSTR_FMT_IX }, - [UNARY_CHECK_FLOAT] = { true, INSTR_FMT_IB }, [BINARY_OP_ADD_FLOAT_UNBOXED] = { true, INSTR_FMT_IX }, [BINARY_OP_SUBTRACT_FLOAT_UNBOXED] = { true, INSTR_FMT_IX }, [BINARY_OP_MULTIPLY_FLOAT_UNBOXED] = { true, INSTR_FMT_IX }, @@ -884,6 +891,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [BINARY_SLICE] = { true, INSTR_FMT_IX }, [STORE_SLICE] = { true, INSTR_FMT_IX }, [BINARY_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC000 }, + [BINARY_SUBSCR_LIST_INT_REST] = { true, INSTR_FMT_IX }, + [CHECK_LIST] = { true, INSTR_FMT_IB }, [BINARY_SUBSCR_TUPLE_INT] = { true, INSTR_FMT_IXC000 }, [BINARY_SUBSCR_DICT] = { true, INSTR_FMT_IXC000 }, [BINARY_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC000 }, @@ -891,6 +900,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = { [SET_ADD] = { true, INSTR_FMT_IB }, [STORE_SUBSCR] = { true, INSTR_FMT_IXC }, [STORE_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC }, + [STORE_SUBSCR_LIST_INT_REST] = { true, INSTR_FMT_IX }, [STORE_SUBSCR_DICT] = { true, INSTR_FMT_IXC }, [DELETE_SUBSCR] = { true, INSTR_FMT_IX }, [CALL_INTRINSIC_1] = { true, INSTR_FMT_IB }, diff --git a/Python/tier2.c b/Python/tier2.c index 0e869925135523..98071e272e76f3 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -4,6 +4,7 @@ #include "pycore_frame.h" #include "pycore_opcode.h" #include "pycore_pystate.h" +#include "pycore_long.h" #include "stdbool.h" #include "opcode.h" @@ -17,12 +18,22 @@ /* Dummy types used by the types propagator */ + +// Represents a 64-bit unboxed double PyTypeObject PyRawFloat_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "rawfloat", sizeof(PyFloatObject), }; +// Represents a PyLong that fits in a 64-bit long. +PyTypeObject PySmallInt_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "smallint", + sizeof(PyFloatObject), +}; + + static inline int IS_SCOPE_EXIT_OPCODE(int opcode); @@ -173,7 +184,7 @@ _PyTier2TypeContext_Copy(const _PyTier2TypeContext *type_context) return new_type_context; } -static void +void _PyTier2TypeContext_Free(_PyTier2TypeContext *type_context) { @@ -920,7 +931,7 @@ static int type_guard_ladder[256] = { BINARY_CHECK_FLOAT, BINARY_CHECK_INT, -1, - UNARY_CHECK_FLOAT, + CHECK_LIST, -1, }; @@ -929,19 +940,19 @@ static int type_guard_ladder[256] = { static int type_guard_to_index[256] = { [BINARY_CHECK_FLOAT] = 1, [BINARY_CHECK_INT] = 2, - [UNARY_CHECK_FLOAT] = 4, + [CHECK_LIST] = 4, }; static inline _Py_CODEUNIT * -emit_type_guard(_Py_CODEUNIT *write_curr, int guard_opcode, int bb_id) +emit_type_guard(_Py_CODEUNIT *write_curr, int guard_opcode, int guard_oparg, int bb_id) { #if BB_DEBUG && defined(Py_DEBUG) fprintf(stderr, "emitted type guard %p %s\n", write_curr, _PyOpcode_OpName[guard_opcode]); #endif write_curr->op.code = guard_opcode; - write_curr->op.arg = type_guard_to_index[guard_opcode]; + write_curr->op.arg = guard_oparg; write_curr++; _py_set_opcode(write_curr, BB_BRANCH); write_curr->op.arg = 0; @@ -1267,12 +1278,10 @@ infer_BINARY_OP( // Unknown, time to emit the chain of guards. // No type guard before this, or it's not the first in the new BB. // First in new BB usually indicates it's already part of a pre-existing ladder. - if (prev_type_guard == NULL || - (!is_first_instr && prev_type_guard != NULL && - type_guard_ladder[type_guard_to_index[prev_type_guard->op.code] + 1] != -1)) { + if (prev_type_guard == NULL || !is_first_instr) { write_curr = rebox_stack(write_curr, type_context, 2); *needs_guard = true; - return emit_type_guard(write_curr, BINARY_CHECK_FLOAT, bb_id); + return emit_type_guard(write_curr, BINARY_CHECK_FLOAT, 0, bb_id); } else { int next_guard = type_guard_ladder[ @@ -1280,7 +1289,55 @@ infer_BINARY_OP( if (next_guard != -1) { write_curr = rebox_stack(write_curr, type_context, 2); *needs_guard = true; - return emit_type_guard(write_curr, next_guard, bb_id); + return emit_type_guard(write_curr, next_guard, 0, bb_id); + } + // End of ladder, fall through + } + return NULL; +} + +static inline _Py_CODEUNIT * +infer_BINARY_SUBSCR( + _Py_CODEUNIT *t2_start, + int oparg, + bool *needs_guard, + _Py_CODEUNIT *prev_type_guard, + _Py_CODEUNIT raw_op, + _Py_CODEUNIT *write_curr, + _PyTier2TypeContext *type_context, + int bb_id, + bool store) +{ + assert(oparg == NB_ADD || oparg == NB_SUBTRACT || oparg == NB_MULTIPLY); + bool is_first_instr = (write_curr == t2_start); + *needs_guard = false; + PyTypeObject *sub = typenode_get_type(type_context->type_stack_ptr[-1]); + PyTypeObject *container = typenode_get_type(type_context->type_stack_ptr[-2]); + if (container == &PyList_Type) { + if (sub == &PySmallInt_Type) { + int opcode = store + ? STORE_SUBSCR_LIST_INT_REST : BINARY_SUBSCR_LIST_INT_REST; + write_curr->op.code = opcode; + write_curr++; + type_propagate(opcode, 0, type_context, NULL); + return write_curr; + } + } + // Unknown, time to emit the chain of guards. + // No type guard before this, or it's not the first in the new BB. + // First in new BB usually indicates it's already part of a pre-existing ladder. + if (prev_type_guard == NULL || !is_first_instr) { + write_curr = rebox_stack(write_curr, type_context, 2); + *needs_guard = true; + return emit_type_guard(write_curr, CHECK_LIST, 1, bb_id); + } + else { + int next_guard = type_guard_ladder[ + type_guard_to_index[prev_type_guard->op.code] + 1]; + if (next_guard != -1) { + write_curr = rebox_stack(write_curr, type_context, store ? 3 : 2); + *needs_guard = true; + return emit_type_guard(write_curr, next_guard, 1, bb_id); } // End of ladder, fall through } @@ -1317,7 +1374,8 @@ _PyTier2_Code_DetectAndEmitBB( assert( prev_type_guard == NULL || prev_type_guard->op.code == BINARY_CHECK_INT || - prev_type_guard->op.code == BINARY_CHECK_FLOAT + prev_type_guard->op.code == BINARY_CHECK_FLOAT || + prev_type_guard->op.code == CHECK_LIST ); #define END() goto end; #define JUMPBY(x) i += x + 1; @@ -1335,6 +1393,7 @@ _PyTier2_Code_DetectAndEmitBB( continue; #define DISPATCH_GOTO() goto dispatch_opcode; #define TYPECONST_GET_RAWTYPE(idx) Py_TYPE(PyTuple_GET_ITEM(consts, idx)) +#define GET_CONST(idx) PyTuple_GET_ITEM(consts, idx) assert(co->_tier2_info != NULL); // There are only two cases that a BB ends. @@ -1410,10 +1469,9 @@ _PyTier2_Code_DetectAndEmitBB( DISPATCH(); } case LOAD_CONST: { - if (TYPECONST_GET_RAWTYPE(oparg) == &PyFloat_Type) { - write_i->op.code = LOAD_CONST; - write_i->op.arg = oparg; - write_i++; + PyTypeObject *typ = TYPECONST_GET_RAWTYPE(oparg); + if (typ == &PyFloat_Type) { + write_i = emit_i(write_i, LOAD_CONST, curr->op.arg); type_propagate(LOAD_CONST, oparg, starting_type_context, consts); write_i->op.code = UNBOX_FLOAT; write_i->op.arg = 0; @@ -1421,6 +1479,20 @@ _PyTier2_Code_DetectAndEmitBB( type_propagate(UNBOX_FLOAT, 0, starting_type_context, consts); continue; } + else if (typ == &PyLong_Type) { + // We break our own rules for more efficient code here. + // NOTE: THIS MODIFIES THE TYPE CONTEXT. + if (_PyLong_IsNonNegativeCompact((PyLongObject *)GET_CONST(oparg))) { + write_i = emit_i(write_i, LOAD_CONST, curr->op.arg); + + // Type propagate + _PyTier2TypeContext *type_context = starting_type_context; + _Py_TYPENODE_t **type_stackptr = &type_context->type_stack_ptr; + *type_stackptr += 1; + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PySmallInt_Type), TYPESTACK_PEEK(1), true); + continue; + } + } DISPATCH(); } case LOAD_FAST: { @@ -1553,6 +1625,48 @@ _PyTier2_Code_DetectAndEmitBB( continue; } DISPATCH_REBOX(2); + case BINARY_SUBSCR: { + _Py_CODEUNIT *possible_next = infer_BINARY_SUBSCR( + t2_start, oparg, &needs_guard, + prev_type_guard, + *curr, + write_i, starting_type_context, + co->_tier2_info->bb_data_curr, false); + if (possible_next == NULL) { + DISPATCH_REBOX(2); + } + write_i = possible_next; + if (needs_guard) { + // Point to the same instruction, because in this BB we emit + // the guard. + // The next BB emits the instruction. + i--; + END(); + } + i += caches; + continue; + } + case STORE_SUBSCR: { + _Py_CODEUNIT *possible_next = infer_BINARY_SUBSCR( + t2_start, oparg, &needs_guard, + prev_type_guard, + *curr, + write_i, starting_type_context, + co->_tier2_info->bb_data_curr, true); + if (possible_next == NULL) { + DISPATCH_REBOX(3); + } + write_i = possible_next; + if (needs_guard) { + // Point to the same instruction, because in this BB we emit + // the guard. + // The next BB emits the instruction. + i--; + END(); + } + i += caches; + continue; + } case LOAD_ATTR: case CALL_INTRINSIC_1: case UNARY_NEGATIVE: @@ -1562,11 +1676,8 @@ _PyTier2_Code_DetectAndEmitBB( case UNPACK_SEQUENCE: DISPATCH_REBOX(1); case CALL_INTRINSIC_2: - case BINARY_SUBSCR: case BINARY_SLICE: DISPATCH_REBOX(2); - case STORE_SUBSCR: - DISPATCH_REBOX(4); case STORE_SLICE: DISPATCH_REBOX(4); default: @@ -1820,12 +1931,10 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) qsort(backward_jump_offsets, backwards_jump_count, sizeof(int), compare_ints); // Deduplicate - int backwards_jump_count_new = backwards_jump_count; for (int i = 0; i < backwards_jump_count - 1; i++) { for (int x = i + 1; x < backwards_jump_count; x++) { if (backward_jump_offsets[i] == backward_jump_offsets[x]) { backward_jump_offsets[x] = -1; - backwards_jump_count_new--; } } } @@ -2250,7 +2359,7 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id_tagged #ifdef Py_DEBUG // We assert that there are as many items on the operand stack as there are on the // saved type stack. - int typestack_level = meta->type_context->type_stack_ptr - meta->type_context->type_stack; + Py_ssize_t typestack_level = meta->type_context->type_stack_ptr - meta->type_context->type_stack; assert(typestack_level == stacklevel); #endif // The jump target @@ -2466,3 +2575,4 @@ _PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *tar #undef TYPELOCALS_GET #undef TYPE_SET #undef TYPE_OVERWRITE +#undef GET_CONST diff --git a/Python/tier2_typepropagator.c.h b/Python/tier2_typepropagator.c.h index df008d7028e8ed..cdab65faf0c314 100644 --- a/Python/tier2_typepropagator.c.h +++ b/Python/tier2_typepropagator.c.h @@ -175,12 +175,6 @@ break; } - TARGET(UNARY_CHECK_FLOAT) { - TYPE_SET((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyFloat_Type), TYPESTACK_PEEK(1 + oparg), true); - TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyRawFloat_Type), TYPESTACK_PEEK(1 + oparg), true); - break; - } - TARGET(BINARY_OP_ADD_FLOAT_UNBOXED) { STACK_SHRINK(1); TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyRawFloat_Type), TYPESTACK_PEEK(1), true); @@ -250,6 +244,18 @@ break; } + TARGET(BINARY_SUBSCR_LIST_INT_REST) { + STACK_SHRINK(1); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); + break; + } + + TARGET(CHECK_LIST) { + TYPE_SET((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyList_Type), TYPESTACK_PEEK(1 + oparg), true); + TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_MAKE_ROOT((_Py_TYPENODE_t)&PyList_Type), TYPESTACK_PEEK(1 + oparg), true); + break; + } + TARGET(BINARY_SUBSCR_TUPLE_INT) { STACK_SHRINK(1); TYPE_OVERWRITE((_Py_TYPENODE_t *)_Py_TYPENODE_NULLROOT, TYPESTACK_PEEK(1), true); @@ -288,6 +294,11 @@ break; } + TARGET(STORE_SUBSCR_LIST_INT_REST) { + STACK_SHRINK(3); + break; + } + TARGET(STORE_SUBSCR_DICT) { STACK_SHRINK(3); break; From 7ec2dc0aed6540c33ae148f0c60a98e53a3e14d1 Mon Sep 17 00:00:00 2001 From: Jules <57632293+JuliaPoo@users.noreply.github.com> Date: Fri, 31 Mar 2023 21:47:02 +0800 Subject: [PATCH 254/280] Fix: Ref leak in unboxing checks (#33) * Added EXTENDED_ARG to type prop * Revert "Added EXTENDED_ARG to type prop" This reverts commit 7249cb7e968b186857029213490e077d155e7c8a. * Fix: Buggy type propagation across SWP * Fix: Forgot to tag pointers in TYPE_SET * Fix: BB_TEST_ITER wrong type propagation * Fix: Bug in typeprop handling UNPACK_*, and bug in COPY_NO_INCREF * Fix: Misc macro fix * Fix: Ref leak in unboxing checks --------- Co-authored-by: Ken Jin --- Python/bytecodes.c | 14 ++++++++------ Python/generated_cases.c.h | 15 +++++++++------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index d0f2d04dfead0f..2bb42c2ad449e9 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -318,12 +318,14 @@ dummy_func( char is_successor = PyFloat_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); bb_test = BB_TEST(is_successor, 0); - left_unboxed = (is_successor - ? *((PyObject **)(&(((PyFloatObject *)left)->ob_fval))) - : left); - right_unboxed = (is_successor - ? *((PyObject **)(&(((PyFloatObject *)right)->ob_fval))) - : right); + if (is_successor) { + left_unboxed = *((PyObject **)(&(((PyFloatObject *)left)->ob_fval))); + right_unboxed = *((PyObject **)(&(((PyFloatObject *)right)->ob_fval))); + DECREF_INPUTS(); + } else { + left_unboxed = left; + right_unboxed = right; + } } inst(BINARY_OP_ADD_FLOAT_UNBOXED, (left, right -- sum : PyRawFloat_Type)) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index d0dde435a97081..9ae72b8d258798 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -501,12 +501,15 @@ char is_successor = PyFloat_CheckExact(left) && (Py_TYPE(left) == Py_TYPE(right)); bb_test = BB_TEST(is_successor, 0); - left_unboxed = (is_successor - ? *((PyObject **)(&(((PyFloatObject *)left)->ob_fval))) - : left); - right_unboxed = (is_successor - ? *((PyObject **)(&(((PyFloatObject *)right)->ob_fval))) - : right); + if (is_successor) { + left_unboxed = *((PyObject **)(&(((PyFloatObject *)left)->ob_fval))); + right_unboxed = *((PyObject **)(&(((PyFloatObject *)right)->ob_fval))); + Py_DECREF(left); + Py_DECREF(right); + } else { + left_unboxed = left; + right_unboxed = right; + } stack_pointer[-1] = right_unboxed; stack_pointer[-2] = left_unboxed; DISPATCH(); From 0a14be32e83a6b79ae0bc98b0df705467529707d Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 31 Mar 2023 22:32:12 +0800 Subject: [PATCH 255/280] Add our own nbody benchmark --- bm_nbody.py | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 bm_nbody.py diff --git a/bm_nbody.py b/bm_nbody.py new file mode 100644 index 00000000000000..1b8aed05910c89 --- /dev/null +++ b/bm_nbody.py @@ -0,0 +1,149 @@ +""" +N-body benchmark from the Computer Language Benchmarks Game. + +This is intended to support Unladen Swallow's pyperf.py. Accordingly, it has been +modified from the Shootout version: +- Accept standard Unladen Swallow benchmark options. +- Run report_energy()/advance() in a loop. +- Reimplement itertools.combinations() to work with older Python versions. + +Pulled from: +http://benchmarksgame.alioth.debian.org/u64q/program.php?test=nbody&lang=python3&id=1 + +Contributed by Kevin Carson. +Modified by Tupteq, Fredrik Johansson, and Daniel Nanz. +""" + +import time + +__contact__ = "collinwinter@google.com (Collin Winter)" +DEFAULT_ITERATIONS = 100 +DEFAULT_REFERENCE = 'sun' + + +def combinations(l): + """Pure-Python implementation of itertools.combinations(l, 2).""" + result = [] + for x in range(len(l) - 1): + ls = l[x + 1:] + for y in ls: + result.append((l[x], y)) + return result + + +PI = 3.14159265358979323 +SOLAR_MASS = 4 * PI * PI +DAYS_PER_YEAR = 365.24 + +BODIES = { + 'sun': ([0.0, 0.0, 0.0], [0.0, 0.0, 0.0], SOLAR_MASS), + + 'jupiter': ([4.84143144246472090e+00, + -1.16032004402742839e+00, + -1.03622044471123109e-01], + [1.66007664274403694e-03 * DAYS_PER_YEAR, + 7.69901118419740425e-03 * DAYS_PER_YEAR, + -6.90460016972063023e-05 * DAYS_PER_YEAR], + 9.54791938424326609e-04 * SOLAR_MASS), + + 'saturn': ([8.34336671824457987e+00, + 4.12479856412430479e+00, + -4.03523417114321381e-01], + [-2.76742510726862411e-03 * DAYS_PER_YEAR, + 4.99852801234917238e-03 * DAYS_PER_YEAR, + 2.30417297573763929e-05 * DAYS_PER_YEAR], + 2.85885980666130812e-04 * SOLAR_MASS), + + 'uranus': ([1.28943695621391310e+01, + -1.51111514016986312e+01, + -2.23307578892655734e-01], + [2.96460137564761618e-03 * DAYS_PER_YEAR, + 2.37847173959480950e-03 * DAYS_PER_YEAR, + -2.96589568540237556e-05 * DAYS_PER_YEAR], + 4.36624404335156298e-05 * SOLAR_MASS), + + 'neptune': ([1.53796971148509165e+01, + -2.59193146099879641e+01, + 1.79258772950371181e-01], + [2.68067772490389322e-03 * DAYS_PER_YEAR, + 1.62824170038242295e-03 * DAYS_PER_YEAR, + -9.51592254519715870e-05 * DAYS_PER_YEAR], + 5.15138902046611451e-05 * SOLAR_MASS)} + + +SYSTEM = list(BODIES.values()) +PAIRS = combinations(SYSTEM) + + +def advance(dt, n, bodies=SYSTEM, pairs=PAIRS): + for i in range(n): + for (([x1, y1, z1], v1, m1), + ([x2, y2, z2], v2, m2)) in pairs: + dx = x1 - x2 + dy = y1 - y2 + dz = z1 - z2 + mag = dt * ((dx * dx + dy * dy + dz * dz) ** (-1.5)) + b1m = m1 * mag + b2m = m2 * mag + v1[0] -= dx * b2m + v1[1] -= dy * b2m + v1[2] -= dz * b2m + v2[0] += dx * b1m + v2[1] += dy * b1m + v2[2] += dz * b1m + for (r, [vx, vy, vz], m) in bodies: + r[0] += dt * vx + r[1] += dt * vy + r[2] += dt * vz + + +def report_energy(bodies=SYSTEM, pairs=PAIRS, e=0.0): + for (((x1, y1, z1), v1, m1), + ((x2, y2, z2), v2, m2)) in pairs: + dx = x1 - x2 + dy = y1 - y2 + dz = z1 - z2 + e -= (m1 * m2) / ((dx * dx + dy * dy + dz * dz) ** 0.5) + for (r, [vx, vy, vz], m) in bodies: + e += m * (vx * vx + vy * vy + vz * vz) / 2. + return e + + +def offset_momentum(ref, bodies=SYSTEM, px=0.0, py=0.0, pz=0.0): + for (r, [vx, vy, vz], m) in bodies: + px -= vx * m + py -= vy * m + pz -= vz * m + (r, v, m) = ref + v[0] = px / m + v[1] = py / m + v[2] = pz / m + + +def bench_nbody(loops, reference, iterations): + # Set up global state + offset_momentum(BODIES[reference]) + + range_it = range(loops) + t0 = time.perf_counter() + + for _ in range_it: + report_energy() + advance(0.01, iterations) + report_energy() + + return time.perf_counter() - t0 + + +def add_cmdline_args(cmd, args): + cmd.extend(("--iterations", str(args.iterations))) + + +if __name__ == '__main__': + # Warmup + bench_nbody(128, DEFAULT_REFERENCE, 128) + # Showtime + print("It's showtime") + taken = bench_nbody(DEFAULT_ITERATIONS, DEFAULT_REFERENCE, 10_000) + print("Time taken is", taken, "s") + \ No newline at end of file From be8fbf9d78dc53064e1f85c9f85dc785897b3bb8 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 31 Mar 2023 22:36:22 +0800 Subject: [PATCH 256/280] change iterations --- bm_nbody.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bm_nbody.py b/bm_nbody.py index 1b8aed05910c89..721bb3f3f76a1e 100644 --- a/bm_nbody.py +++ b/bm_nbody.py @@ -144,6 +144,6 @@ def add_cmdline_args(cmd, args): bench_nbody(128, DEFAULT_REFERENCE, 128) # Showtime print("It's showtime") - taken = bench_nbody(DEFAULT_ITERATIONS, DEFAULT_REFERENCE, 10_000) + taken = bench_nbody(DEFAULT_ITERATIONS, DEFAULT_REFERENCE, 50_000) print("Time taken is", taken, "s") \ No newline at end of file From 2f12aadad6457f4a79146ac29c239b62b6ba6eb7 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 31 Mar 2023 23:44:33 +0800 Subject: [PATCH 257/280] Remove BB_TEST_ITER_GEN --- Include/internal/pycore_opcode.h | 24 +++---- Include/opcode.h | 119 +++++++++++++++---------------- Lib/opcode.py | 1 - Python/opcode_targets.h | 20 +++--- 4 files changed, 81 insertions(+), 83 deletions(-) diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index ce1195d45819ea..bef8db3d0ebbb1 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -55,7 +55,6 @@ const uint8_t _PyOpcode_Caches[256] = { }; const uint8_t _PyOpcode_Deopt[256] = { - [BB_TEST_ITER_GEN] = BB_TEST_ITER, [BB_TEST_ITER_LIST] = BB_TEST_ITER, [BB_TEST_ITER_RANGE] = BB_TEST_ITER, [BB_TEST_ITER_TUPLE] = BB_TEST_ITER, @@ -305,23 +304,23 @@ static const char *const _PyOpcode_OpName[263] = { [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", [BB_TEST_ITER_RANGE] = "BB_TEST_ITER_RANGE", [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", - [BB_TEST_ITER_GEN] = "BB_TEST_ITER_GEN", [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", + [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", [RETURN_GENERATOR] = "RETURN_GENERATOR", - [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN", [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", - [RETURN_VALUE] = "RETURN_VALUE", [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", - [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", + [RETURN_VALUE] = "RETURN_VALUE", [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", + [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", + [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", [POP_EXCEPT] = "POP_EXCEPT", [STORE_NAME] = "STORE_NAME", [DELETE_NAME] = "DELETE_NAME", @@ -344,9 +343,9 @@ static const char *const _PyOpcode_OpName[263] = { [IMPORT_NAME] = "IMPORT_NAME", [IMPORT_FROM] = "IMPORT_FROM", [JUMP_FORWARD] = "JUMP_FORWARD", - [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", + [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", [POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE", [POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -374,9 +373,9 @@ static const char *const _PyOpcode_OpName[263] = { [STORE_DEREF] = "STORE_DEREF", [DELETE_DEREF] = "DELETE_DEREF", [JUMP_BACKWARD] = "JUMP_BACKWARD", - [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", - [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", + [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", + [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -386,29 +385,28 @@ static const char *const _PyOpcode_OpName[263] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", - [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", + [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", - [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", + [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", - [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", [SEND_GEN] = "SEND_GEN", [BB_BRANCH] = "BB_BRANCH", [BB_BRANCH_IF_FLAG_UNSET] = "BB_BRANCH_IF_FLAG_UNSET", + [BB_BRANCH_IF_FLAG_SET] = "BB_BRANCH_IF_FLAG_SET", [CALL] = "CALL", [KW_NAMES] = "KW_NAMES", [CALL_INTRINSIC_1] = "CALL_INTRINSIC_1", [CALL_INTRINSIC_2] = "CALL_INTRINSIC_2", - [BB_BRANCH_IF_FLAG_SET] = "BB_BRANCH_IF_FLAG_SET", [BB_JUMP_IF_FLAG_UNSET] = "BB_JUMP_IF_FLAG_UNSET", [BB_JUMP_IF_FLAG_SET] = "BB_JUMP_IF_FLAG_SET", [BB_TEST_ITER] = "BB_TEST_ITER", @@ -439,6 +437,7 @@ static const char *const _PyOpcode_OpName[263] = { [STORE_FAST_BOXED_UNBOXED] = "STORE_FAST_BOXED_UNBOXED", [STORE_FAST_UNBOXED_BOXED] = "STORE_FAST_UNBOXED_BOXED", [STORE_FAST_UNBOXED_UNBOXED] = "STORE_FAST_UNBOXED_UNBOXED", + [205] = "<205>", [206] = "<206>", [207] = "<207>", [208] = "<208>", @@ -501,6 +500,7 @@ static const char *const _PyOpcode_OpName[263] = { #define EXTRA_CASES \ + case 205: \ case 206: \ case 207: \ case 208: \ diff --git a/Include/opcode.h b/Include/opcode.h index 3d99716fec63e6..749e50e727fe37 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -161,68 +161,67 @@ extern "C" { #define FOR_ITER_TUPLE 63 #define FOR_ITER_RANGE 64 #define FOR_ITER_GEN 65 -#define BB_TEST_ITER_GEN 72 -#define LOAD_ATTR_CLASS 73 -#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 76 -#define LOAD_ATTR_INSTANCE_VALUE 77 -#define LOAD_ATTR_MODULE 78 -#define LOAD_ATTR_PROPERTY 79 -#define LOAD_ATTR_SLOT 80 -#define LOAD_ATTR_WITH_HINT 81 -#define LOAD_ATTR_METHOD_LAZY_DICT 82 -#define LOAD_ATTR_METHOD_NO_DICT 84 -#define LOAD_ATTR_METHOD_WITH_VALUES 86 -#define LOAD_CONST__LOAD_FAST 87 -#define LOAD_FAST__LOAD_CONST 88 -#define LOAD_FAST__LOAD_FAST 111 -#define LOAD_GLOBAL_BUILTIN 112 -#define LOAD_GLOBAL_MODULE 113 -#define STORE_ATTR_INSTANCE_VALUE 141 -#define STORE_ATTR_SLOT 143 -#define STORE_ATTR_WITH_HINT 153 -#define STORE_FAST__LOAD_FAST 154 -#define STORE_FAST__STORE_FAST 158 -#define STORE_SUBSCR_DICT 159 -#define STORE_SUBSCR_LIST_INT 160 -#define UNPACK_SEQUENCE_LIST 161 -#define UNPACK_SEQUENCE_TUPLE 166 -#define UNPACK_SEQUENCE_TWO_TUPLE 167 -#define SEND_GEN 168 +#define LOAD_ATTR_CLASS 72 +#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 73 +#define LOAD_ATTR_INSTANCE_VALUE 76 +#define LOAD_ATTR_MODULE 77 +#define LOAD_ATTR_PROPERTY 78 +#define LOAD_ATTR_SLOT 79 +#define LOAD_ATTR_WITH_HINT 80 +#define LOAD_ATTR_METHOD_LAZY_DICT 81 +#define LOAD_ATTR_METHOD_NO_DICT 82 +#define LOAD_ATTR_METHOD_WITH_VALUES 84 +#define LOAD_CONST__LOAD_FAST 86 +#define LOAD_FAST__LOAD_CONST 87 +#define LOAD_FAST__LOAD_FAST 88 +#define LOAD_GLOBAL_BUILTIN 111 +#define LOAD_GLOBAL_MODULE 112 +#define STORE_ATTR_INSTANCE_VALUE 113 +#define STORE_ATTR_SLOT 141 +#define STORE_ATTR_WITH_HINT 143 +#define STORE_FAST__LOAD_FAST 153 +#define STORE_FAST__STORE_FAST 154 +#define STORE_SUBSCR_DICT 158 +#define STORE_SUBSCR_LIST_INT 159 +#define UNPACK_SEQUENCE_LIST 160 +#define UNPACK_SEQUENCE_TUPLE 161 +#define UNPACK_SEQUENCE_TWO_TUPLE 166 +#define SEND_GEN 167 #define DO_TRACING 255 // Tier 2 interpreter ops -#define BB_BRANCH 169 -#define BB_BRANCH_IF_FLAG_UNSET 170 -#define BB_BRANCH_IF_FLAG_SET 175 -#define BB_JUMP_IF_FLAG_UNSET 176 -#define BB_JUMP_IF_FLAG_SET 177 -#define BB_TEST_ITER 178 -#define BB_TEST_ITER_RANGE 179 -#define BB_TEST_ITER_LIST 180 -#define BB_TEST_ITER_TUPLE 181 -#define BB_TEST_POP_IF_FALSE 182 -#define BB_TEST_POP_IF_TRUE 183 -#define BB_TEST_POP_IF_NOT_NONE 184 -#define BB_TEST_POP_IF_NONE 185 -#define BB_JUMP_BACKWARD_LAZY 186 -#define BINARY_CHECK_INT 187 -#define BINARY_CHECK_FLOAT 188 -#define CHECK_LIST 189 -#define BINARY_OP_ADD_INT_REST 190 -#define BINARY_OP_ADD_FLOAT_UNBOXED 191 -#define BINARY_OP_SUBTRACT_INT_REST 192 -#define BINARY_OP_SUBTRACT_FLOAT_UNBOXED 193 -#define BINARY_OP_MULTIPLY_INT_REST 194 -#define BINARY_OP_MULTIPLY_FLOAT_UNBOXED 195 -#define BINARY_SUBSCR_LIST_INT_REST 196 -#define STORE_SUBSCR_LIST_INT_REST 197 -#define POP_TOP_NO_DECREF 198 -#define UNBOX_FLOAT 199 -#define BOX_FLOAT 200 -#define COPY_NO_INCREF 201 -#define LOAD_FAST_NO_INCREF 202 -#define STORE_FAST_BOXED_UNBOXED 203 -#define STORE_FAST_UNBOXED_BOXED 204 -#define STORE_FAST_UNBOXED_UNBOXED 205 +#define BB_BRANCH 168 +#define BB_BRANCH_IF_FLAG_UNSET 169 +#define BB_BRANCH_IF_FLAG_SET 170 +#define BB_JUMP_IF_FLAG_UNSET 175 +#define BB_JUMP_IF_FLAG_SET 176 +#define BB_TEST_ITER 177 +#define BB_TEST_ITER_RANGE 178 +#define BB_TEST_ITER_LIST 179 +#define BB_TEST_ITER_TUPLE 180 +#define BB_TEST_POP_IF_FALSE 181 +#define BB_TEST_POP_IF_TRUE 182 +#define BB_TEST_POP_IF_NOT_NONE 183 +#define BB_TEST_POP_IF_NONE 184 +#define BB_JUMP_BACKWARD_LAZY 185 +#define BINARY_CHECK_INT 186 +#define BINARY_CHECK_FLOAT 187 +#define CHECK_LIST 188 +#define BINARY_OP_ADD_INT_REST 189 +#define BINARY_OP_ADD_FLOAT_UNBOXED 190 +#define BINARY_OP_SUBTRACT_INT_REST 191 +#define BINARY_OP_SUBTRACT_FLOAT_UNBOXED 192 +#define BINARY_OP_MULTIPLY_INT_REST 193 +#define BINARY_OP_MULTIPLY_FLOAT_UNBOXED 194 +#define BINARY_SUBSCR_LIST_INT_REST 195 +#define STORE_SUBSCR_LIST_INT_REST 196 +#define POP_TOP_NO_DECREF 197 +#define UNBOX_FLOAT 198 +#define BOX_FLOAT 199 +#define COPY_NO_INCREF 200 +#define LOAD_FAST_NO_INCREF 201 +#define STORE_FAST_BOXED_UNBOXED 202 +#define STORE_FAST_UNBOXED_BOXED 203 +#define STORE_FAST_UNBOXED_UNBOXED 204 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\ || ((op) == JUMP) \ diff --git a/Lib/opcode.py b/Lib/opcode.py index 1e26407a16ab06..297d0001793abf 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -333,7 +333,6 @@ def pseudo_op(name, op, real_ops): "BB_TEST_ITER_LIST", "BB_TEST_ITER_TUPLE", "BB_TEST_ITER_RANGE", - "BB_TEST_ITER_GEN", ], "LOAD_ATTR": [ # These potentially push [NULL, bound method] onto the stack. diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 48c858e0cd2d00..bd0902f1a9f59d 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -71,23 +71,23 @@ static void *opcode_targets[256] = { &&TARGET_GET_YIELD_FROM_ITER, &&TARGET_BB_TEST_ITER_RANGE, &&TARGET_LOAD_BUILD_CLASS, - &&TARGET_BB_TEST_ITER_GEN, &&TARGET_LOAD_ATTR_CLASS, + &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, &&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_RETURN_GENERATOR, - &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_ATTR_MODULE, &&TARGET_LOAD_ATTR_PROPERTY, &&TARGET_LOAD_ATTR_SLOT, &&TARGET_LOAD_ATTR_WITH_HINT, &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, - &&TARGET_RETURN_VALUE, &&TARGET_LOAD_ATTR_METHOD_NO_DICT, - &&TARGET_SETUP_ANNOTATIONS, + &&TARGET_RETURN_VALUE, &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, + &&TARGET_SETUP_ANNOTATIONS, &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_LOAD_FAST__LOAD_CONST, + &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_POP_EXCEPT, &&TARGET_STORE_NAME, &&TARGET_DELETE_NAME, @@ -110,9 +110,9 @@ static void *opcode_targets[256] = { &&TARGET_IMPORT_NAME, &&TARGET_IMPORT_FROM, &&TARGET_JUMP_FORWARD, - &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_LOAD_GLOBAL_BUILTIN, &&TARGET_LOAD_GLOBAL_MODULE, + &&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_POP_JUMP_IF_FALSE, &&TARGET_POP_JUMP_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -140,9 +140,9 @@ static void *opcode_targets[256] = { &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, &&TARGET_JUMP_BACKWARD, - &&TARGET_STORE_ATTR_INSTANCE_VALUE, - &&TARGET_CALL_FUNCTION_EX, &&TARGET_STORE_ATTR_SLOT, + &&TARGET_CALL_FUNCTION_EX, + &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,24 +152,24 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, - &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_STORE_FAST__LOAD_FAST, + &&TARGET_STORE_FAST__STORE_FAST, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, - &&TARGET_STORE_FAST__STORE_FAST, &&TARGET_STORE_SUBSCR_DICT, &&TARGET_STORE_SUBSCR_LIST_INT, &&TARGET_UNPACK_SEQUENCE_LIST, + &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, - &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&TARGET_SEND_GEN, &&_unknown_opcode, &&_unknown_opcode, + &&_unknown_opcode, &&TARGET_CALL, &&TARGET_KW_NAMES, &&TARGET_CALL_INTRINSIC_1, From 74b20cbe479bbf1f99499442a9c11d415eeaa7ce Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Fri, 31 Mar 2023 23:57:09 +0800 Subject: [PATCH 258/280] make work on gcc --- Makefile.pre.in | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.pre.in b/Makefile.pre.in index 74e4171b010d0f..1a6b1cfa1d074b 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -411,6 +411,7 @@ PYTHON_OBJS= \ Python/pytime.o \ Python/bootstrap_hash.o \ Python/specialize.o \ + Python/tier2.o \ Python/structmember.o \ Python/symtable.o \ Python/sysmodule.o \ From 309715c006720275d315a76f352d22944993a0e3 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 1 Apr 2023 00:03:58 +0800 Subject: [PATCH 259/280] regen opcode targets --- Python/makeopcodetargets.py | 4 +++ Python/opcode_targets.h | 66 ++++++++++++++++++------------------- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/Python/makeopcodetargets.py b/Python/makeopcodetargets.py index 33a4b4a76a1253..c5043542fb592d 100755 --- a/Python/makeopcodetargets.py +++ b/Python/makeopcodetargets.py @@ -41,6 +41,10 @@ def write_contents(f): while targets[next_op] != '_unknown_opcode': next_op += 1 targets[next_op] = "TARGET_%s" % opname + for opname in opcode._uops: + while targets[next_op] != '_unknown_opcode': + next_op += 1 + targets[next_op] = "TARGET_%s" % opname f.write("static void *opcode_targets[256] = {\n") f.write(",\n".join([" &&%s" % s for s in targets])) f.write("\n};\n") diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index bd0902f1a9f59d..55e0cd2a690948 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -167,43 +167,43 @@ static void *opcode_targets[256] = { &&TARGET_DICT_UPDATE, &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&TARGET_SEND_GEN, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, + &&TARGET_BB_BRANCH, + &&TARGET_BB_BRANCH_IF_FLAG_UNSET, + &&TARGET_BB_BRANCH_IF_FLAG_SET, &&TARGET_CALL, &&TARGET_KW_NAMES, &&TARGET_CALL_INTRINSIC_1, &&TARGET_CALL_INTRINSIC_2, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, + &&TARGET_BB_JUMP_IF_FLAG_UNSET, + &&TARGET_BB_JUMP_IF_FLAG_SET, + &&TARGET_BB_TEST_ITER, + &&TARGET_BB_TEST_ITER_RANGE, + &&TARGET_BB_TEST_ITER_LIST, + &&TARGET_BB_TEST_ITER_TUPLE, + &&TARGET_BB_TEST_POP_IF_FALSE, + &&TARGET_BB_TEST_POP_IF_TRUE, + &&TARGET_BB_TEST_POP_IF_NOT_NONE, + &&TARGET_BB_TEST_POP_IF_NONE, + &&TARGET_BB_JUMP_BACKWARD_LAZY, + &&TARGET_BINARY_CHECK_INT, + &&TARGET_BINARY_CHECK_FLOAT, + &&TARGET_CHECK_LIST, + &&TARGET_BINARY_OP_ADD_INT_REST, + &&TARGET_BINARY_OP_ADD_FLOAT_UNBOXED, + &&TARGET_BINARY_OP_SUBTRACT_INT_REST, + &&TARGET_BINARY_OP_SUBTRACT_FLOAT_UNBOXED, + &&TARGET_BINARY_OP_MULTIPLY_INT_REST, + &&TARGET_BINARY_OP_MULTIPLY_FLOAT_UNBOXED, + &&TARGET_BINARY_SUBSCR_LIST_INT_REST, + &&TARGET_STORE_SUBSCR_LIST_INT_REST, + &&TARGET_POP_TOP_NO_DECREF, + &&TARGET_UNBOX_FLOAT, + &&TARGET_BOX_FLOAT, + &&TARGET_COPY_NO_INCREF, + &&TARGET_LOAD_FAST_NO_INCREF, + &&TARGET_STORE_FAST_BOXED_UNBOXED, + &&TARGET_STORE_FAST_UNBOXED_BOXED, + &&TARGET_STORE_FAST_UNBOXED_UNBOXED, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, From 1ed4c15b17624025c6d843779815690fccb5748c Mon Sep 17 00:00:00 2001 From: kenjin-work Date: Sat, 1 Apr 2023 00:54:22 +0800 Subject: [PATCH 260/280] fix for makefile --- Makefile.pre.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.pre.in b/Makefile.pre.in index 1a6b1cfa1d074b..1818cf1362e24b 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1198,7 +1198,7 @@ DEEPFREEZE_DEPS=$(srcdir)/Tools/build/deepfreeze.py $(FREEZE_MODULE_DEPS) $(FROZ # BEGIN: deepfreeze modules Python/deepfreeze/deepfreeze.c: $(DEEPFREEZE_DEPS) - $(PYTHON_FOR_FREEZE) $(srcdir)/Tools/build/deepfreeze.py \ + python3 $(srcdir)/Tools/build/deepfreeze.py \ Python/frozen_modules/importlib._bootstrap.h:importlib._bootstrap \ Python/frozen_modules/importlib._bootstrap_external.h:importlib._bootstrap_external \ Python/frozen_modules/zipimport.h:zipimport \ From 552949599863d4b8dbb48f1e43b50643bbc9d5a9 Mon Sep 17 00:00:00 2001 From: kenjin-work Date: Sat, 1 Apr 2023 00:58:29 +0800 Subject: [PATCH 261/280] Update bm_nbody.py --- bm_nbody.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bm_nbody.py b/bm_nbody.py index 721bb3f3f76a1e..51c2d383a47c4c 100644 --- a/bm_nbody.py +++ b/bm_nbody.py @@ -128,9 +128,9 @@ def bench_nbody(loops, reference, iterations): t0 = time.perf_counter() for _ in range_it: - report_energy() + # report_energy() advance(0.01, iterations) - report_energy() + # report_energy() return time.perf_counter() - t0 From b758a31d2a8fbfb93818b91fa002c792f1bf0168 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 8 Apr 2023 02:23:14 +0800 Subject: [PATCH 262/280] Add documentation --- Python/tier2.c | 595 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 456 insertions(+), 139 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index 98071e272e76f3..4dc65af081e0b2 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -39,6 +39,11 @@ static inline int IS_SCOPE_EXIT_OPCODE(int opcode); ////////// TYPE CONTEXT FUNCTIONS +/** + * @brief Allocates and initializes the type context for a code object. + * @param co The code object the type context belongs to. + * @return The newly-created type context. +*/ static _PyTier2TypeContext * initialize_type_context(const PyCodeObject *co) { @@ -82,6 +87,11 @@ initialize_type_context(const PyCodeObject *co) return type_context; } +/** + * @brief Does a deepcopy of a type context and all its nodes. + * @param type_context The type context to copy. + * @return Newly copied type context. +*/ static _PyTier2TypeContext * _PyTier2TypeContext_Copy(const _PyTier2TypeContext *type_context) { @@ -184,6 +194,10 @@ _PyTier2TypeContext_Copy(const _PyTier2TypeContext *type_context) return new_type_context; } +/** + * @brief Destructor for a type context. + * @param type_context The type context to destroy/free. +*/ void _PyTier2TypeContext_Free(_PyTier2TypeContext *type_context) { @@ -210,6 +224,11 @@ __typenode_get_rootptr(_Py_TYPENODE_t ref) return ref_ptr; } +/** + * @brief Gets the actual PyTypeObject* that a type node points to. + * @param node The type propagator node to look up. + * @return The referenced PyTypeObject*. +*/ static PyTypeObject* typenode_get_type(_Py_TYPENODE_t node) { @@ -229,6 +248,13 @@ typenode_get_type(_Py_TYPENODE_t node) } } +// @TODO @JULES +/** + * @brief + * @param src + * @param dst + * @param src_is_new +*/ static void __type_propagate_TYPE_SET( _Py_TYPENODE_t *src, _Py_TYPENODE_t *dst, bool src_is_new) @@ -272,6 +298,14 @@ __type_propagate_TYPE_SET( } } +// @TODO @JULES +/** + * @brief + * @param type_context + * @param src + * @param dst + * @param src_is_new +*/ static void __type_propagate_TYPE_OVERWRITE( _PyTier2TypeContext *type_context, @@ -387,7 +421,16 @@ __type_propagate_TYPE_OVERWRITE( } } -// src and dst are assumed to already be within the type context + +// @TODO @JULES +/** + * @brief + * @param type_context + * @param src + * @param dst + * + * src and dst are assumed to already be within the type context +*/ static void __type_propagate_TYPE_SWAP( _PyTier2TypeContext *type_context, @@ -455,6 +498,11 @@ __type_propagate_TYPE_SWAP( *src ^= *dst; } +/** + * @brief Shrink a type stack by `idx` entries. + * @param type_stackptr The pointer to one after the top of type stack. + * @param idx The number of entries to shrink the stack by. +*/ static void __type_stack_shrink(_Py_TYPENODE_t **type_stackptr, int idx) { @@ -476,6 +524,10 @@ __type_stack_shrink(_Py_TYPENODE_t **type_stackptr, int idx) #if TYPEPROP_DEBUG +/** + * @brief Print the entries in a type context (along with locals). + * @param type_context The type context to display. +*/ static void print_typestack(const _PyTier2TypeContext *type_context) { @@ -546,7 +598,14 @@ print_typestack(const _PyTier2TypeContext *type_context) } #endif -// Type propagates across a single function. + +/** + * @brief Type propagate across a single instruction + * @param opcode The instruction opcode. + * @param oparg The instruction oparg. + * @param type_context The current type context in the basic block. + * @param consts The co_consts array of the code object that holds the constants. +*/ static void type_propagate( int opcode, int oparg, @@ -611,38 +670,14 @@ type_propagate( #undef TYPECONST_GET } -////////// Utility functions - -// Gets end of the bytecode for a code object. -_Py_CODEUNIT * -_PyCode_GetEnd(PyCodeObject *co) -{ - _Py_CODEUNIT *end = (_Py_CODEUNIT *)(co->co_code_adaptive + _PyCode_NBYTES(co)); - return end; -} - -// Gets end of actual bytecode executed. _PyCode_GetEnd might return a CACHE instruction. -_Py_CODEUNIT * -_PyCode_GetLogicalEnd(PyCodeObject *co) -{ - _Py_CODEUNIT *end = _PyCode_GetEnd(co); - while (_Py_OPCODE(*end) == CACHE) { - end--; - } -#if BB_DEBUG - if (!IS_SCOPE_EXIT_OPCODE(_Py_OPCODE(*end))) { - fprintf(stderr, "WRONG EXIT OPCODE: %d\n", _Py_OPCODE(*end)); - assert(0); - } -#endif - assert(IS_SCOPE_EXIT_OPCODE(_Py_OPCODE(*end))); - return end; -} - ////////// BB SPACE FUNCTIONS -// Creates the overallocated array for the BBs. +/** + * @brief Creates the overallocated array for the BBs. + * @param space_to_alloc How much space to allocate. + * @return A new space that we can write basic block instructions to. +*/ static _PyTier2BBSpace * _PyTier2_CreateBBSpace(Py_ssize_t space_to_alloc) { @@ -655,9 +690,12 @@ _PyTier2_CreateBBSpace(Py_ssize_t space_to_alloc) return bb_space; } -// Checks if there's enough space in the BBSpace for space_requested. -// Reallocates if neccessary. -// DOES NOT ADJUST THE WATER LEVEL AS THIS IS JUST A CHECK. ONLY ADJUSTS THE MAX SPACE. +/** + * @brief Checks if there's enough space in the basic block space for space_requested. + * @param co The code object's tier2 basic block space to check + * @param space_requested The amount of extra space you need. + * @return The space of the code object after checks. +*/ static _PyTier2BBSpace * _PyTier2_BBSpaceCheckAndReallocIfNeeded(PyCodeObject *co, Py_ssize_t space_requested) { @@ -673,20 +711,24 @@ _PyTier2_BBSpaceCheckAndReallocIfNeeded(PyCodeObject *co, Py_ssize_t space_reque #endif // @TODO We can't Realloc, we actually need to do the linked list method. Py_UNREACHABLE(); - //_PyTier2BBSpace *new_space = PyMem_Realloc(curr, new_size); - //if (new_space == NULL) { - // return NULL; - //} - //co->_tier2_info->_bb_space = new_space; - //new_space->max_capacity = new_size; - //return new_space; } // We have enouogh space. Don't do anything, j return curr; } -// BB METADATA FUNCTIONS - +//// BB METADATA FUNCTIONS + +/** + * @brief Allocate the metadata associate with a basic block. + * The metadata contains things like the type context at the end of the basic block.* + * + * @param co The code object this basic block belongs to. + * @param tier2_start The start of the tier 2 code (start of the basic block). + * @param tier1_end The end of the tie 1 code this basic block points to. + * @param type_context The type context associated with this basic block. + * @return Newly allocated metadata for this basic block. + * +*/ static _PyTier2BBMetadata * allocate_bb_metadata(PyCodeObject *co, _Py_CODEUNIT *tier2_start, _Py_CODEUNIT *tier1_end, @@ -705,8 +747,12 @@ allocate_bb_metadata(PyCodeObject *co, _Py_CODEUNIT *tier2_start, } -// Writes BB metadata to code object's tier2info bb_data field. -// 0 on success, 1 on error. +/** + * @brief Writes BB metadata to code object's tier2info bb_data field. + * @param co The code object whose metadata we should write to. + * @param metadata The metadata to write. + * @return 0 on success, 1 on error. +*/ static int write_bb_metadata(PyCodeObject *co, _PyTier2BBMetadata *metadata) { @@ -737,6 +783,17 @@ write_bb_metadata(PyCodeObject *co, _PyTier2BBMetadata *metadata) return 0; } +/** + * @brief Allocate BB metadata, then write it. + * Consume this instead of `allocate_bb_metadata`. + * + * @param co The code object the metadat belongs to. + * @param tier2_start The start of the tier 2 code (start of the basic block). + * @param tier1_end The end of the tie 1 code this basic block points to. + * @param type_context The type context associated with this basic block. + * @return Newly allocated metadata for this basic block. + * +*/ static _PyTier2BBMetadata * _PyTier2_AllocateBBMetaData(PyCodeObject *co, _Py_CODEUNIT *tier2_start, _Py_CODEUNIT *tier1_end, @@ -758,14 +815,22 @@ _PyTier2_AllocateBBMetaData(PyCodeObject *co, _Py_CODEUNIT *tier2_start, /* Opcode detection functions. Keep in sync with compile.c and dis! */ -// dis.hasjabs +/** + * @brief C equivalent of dis.hasjabs + * @param opcode Opcode of the instruction. + * @return Whether this is an absolute jump. +*/ static inline int IS_JABS_OPCODE(int opcode) { return 0; } -// dis.hasjrel +/** + * @brief C equivalent of dis.hasjrel + * @param opcode Opcode of the instruction. + * @return Whether this is a relative jump. +*/ static inline int IS_JREL_OPCODE(int opcode) { @@ -788,6 +853,11 @@ IS_JREL_OPCODE(int opcode) } } +/** + * @brief Checks if this is a backwards jump instruction. + * @param opcode Opcode of the instruction. + * @return Whether this is a backwards jump. +*/ static inline int IS_JUMP_BACKWARDS_OPCODE(int opcode) { @@ -797,20 +867,23 @@ IS_JUMP_BACKWARDS_OPCODE(int opcode) } -// dis.hasjrel || dis.hasjabs +/** + * @brief C equivalent of dis.hasjrel || dis.hasjabs + * @param opcode Opcode of the instruction. + * @return Whether this is a jump instruction. +*/ static inline int IS_JUMP_OPCODE(int opcode) { return IS_JREL_OPCODE(opcode) || IS_JABS_OPCODE(opcode); } -// dis.hascompare -static inline int -IS_COMPARE_OPCODE(int opcode) -{ - return opcode == COMPARE_OP; -} +/** + * @brief Checks whether the opcode is a scope exit. + * @param opcode Opcode of the instruction. + * @return Whether this is a scope exit. +*/ static inline int IS_SCOPE_EXIT_OPCODE(int opcode) { @@ -827,14 +900,23 @@ IS_SCOPE_EXIT_OPCODE(int opcode) } // KEEP IN SYNC WITH COMPILE.c!!!! +/** + * @brief Checks whether the opcode terminates a basic block. + * @param opcode Opcode of the instruction. + * @return Whether this is the end of a basic block. +*/ static int IS_TERMINATOR_OPCODE(int opcode) { return IS_JUMP_OPCODE(opcode) || IS_SCOPE_EXIT_OPCODE(opcode); } -// Opcodes that we can't handle at the moment. If we see them, -// ditch tier 2 attempts. +/** + * @brief Opcodes that we can't handle at the moment. If we see them, ditch tier 2 attempts. + * @param opcode Opcode of the instruction. + * @param nextop The opcode of the following instruction. + * @return Whether this opcode is forbidden. +*/ static inline int IS_FORBIDDEN_OPCODE(int opcode, int nextop) { @@ -884,8 +966,17 @@ IS_FORBIDDEN_OPCODE(int opcode, int nextop) } } -// Decides what values we need to rebox. -// num_elements is how many stack entries and thus how far from the TOS we want to rebox. +/** + * @brief Decides what values we need to rebox. + * + * This function automatically emits rebox instructions if needed. + * + * @param write_curr Instruction write buffer. + * @param type_context The type context to base our decisions on. + * @param num_elements How many stack entries and thus how far from the TOS we want to rebox. + * @return Pointer to new instruction write buffer end. + * +*/ static inline _Py_CODEUNIT * rebox_stack(_Py_CODEUNIT *write_curr, _PyTier2TypeContext *type_context, int num_elements) @@ -902,6 +993,16 @@ rebox_stack(_Py_CODEUNIT *write_curr, return write_curr; } +/** + * @brief Emit CACHE entries for an instruction. + * NOTE: THIS DOES NOT PRESERVE PREVIOUS CACHE INFORMATION. + * THUS THIS INITIALIZES A CLEAN SLATE. + * + * @param write_curr Tier 2 instruction write buffer. + * @param cache_entries Number of cache entries to emit. + * @return Pointer to end of tier 2 instruction write buffer. + * +*/ static inline _Py_CODEUNIT * emit_cache_entries(_Py_CODEUNIT *write_curr, int cache_entries) { @@ -916,6 +1017,13 @@ emit_cache_entries(_Py_CODEUNIT *write_curr, int cache_entries) #define BB_IS_TYPE_BRANCH(bb_id_raw) (bb_id_raw & 1) #define MAKE_TAGGED_BB_ID(bb_id, type_branch) (bb_id << 1 | type_branch) +/** + * @brief Write a BB's ID to a CACHE entry. + * @param cache The CACHE entry to write to. + * @param bb_id The BB's ID. + * @param is_type_guard Whether the BB ends with a type guard. + * +*/ static inline void write_bb_id(_PyBBBranchCache *cache, int bb_id, bool is_type_guard) { assert((uint16_t)(bb_id) == bb_id); @@ -924,8 +1032,11 @@ write_bb_id(_PyBBBranchCache *cache, int bb_id, bool is_type_guard) { cache->bb_id_tagged = MAKE_TAGGED_BB_ID((uint16_t)bb_id, is_type_guard); } -// The order/hierarchy to emit type guards -// NEED TO ADD TO THIS EVERY TIME WE ADD A NEW ONE. +/** + * @brief The order/hierarchy to emit type guards. + * + * NEED TO ADD TO THIS EVERY TIME WE ADD A NEW ONE. +*/ static int type_guard_ladder[256] = { -1, BINARY_CHECK_FLOAT, @@ -935,8 +1046,11 @@ static int type_guard_ladder[256] = { -1, }; -// Type guard to index in the ladder. -// KEEP IN SYNC WITH INDEX IN type_guard_ladder +/** + * @brief Type guard to index in the ladder. + * + * KEEP IN SYNC WITH INDEX IN type_guard_ladder +*/ static int type_guard_to_index[256] = { [BINARY_CHECK_FLOAT] = 1, [BINARY_CHECK_INT] = 2, @@ -944,6 +1058,14 @@ static int type_guard_to_index[256] = { }; +/** + * @brief Emit a type guard. + * @param write_curr The tier 2 instruction write buffer. + * @param guard_opcode The opcode of the type guard. + * @param guard_oparg The oparg of the type guard. + * @param bb_id The BB ID of the current BB we're writing to. + * @return Pointer to new end of the tier 2 instruction write buffer. +*/ static inline _Py_CODEUNIT * emit_type_guard(_Py_CODEUNIT *write_curr, int guard_opcode, int guard_oparg, int bb_id) { @@ -963,13 +1085,24 @@ emit_type_guard(_Py_CODEUNIT *write_curr, int guard_opcode, int guard_oparg, int return write_curr; } -// Converts the tier 1 branch bytecode to tier 2 branch bytecode. -// This converts sequence of instructions like -// POP_JUMP_IF_FALSE -// to -// BB_TEST_POP_IF_FALSE -// BB_BRANCH -// CACHE (bb_id of the current BB << 1 | is_type_branch) +/** + * @brief Converts the tier 1 branch bytecode to tier 2 branch bytecode. + * + * This converts sequence of instructions like + * POP_JUMP_IF_FALSE + * to + * BB_TEST_POP_IF_FALSE + * BB_BRANCH + * CACHE (bb_id of the current BB << 1 | is_type_branch)* + * + * @param type_context The type_context of the current BB. + * @param write_curr The tier 2 instruction write buffer. + * @param branch The tier 1 branch instruction to convert. + * @param bb_id The BB_ID of the current BB. + * @param oparg Oparg of the branch instruction (respects EXTENDED_ARGS). + * @return The updated tier 2 instruction write buffer end. + * +*/ static inline _Py_CODEUNIT * emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, _Py_CODEUNIT branch, int bb_id, int oparg) @@ -1096,6 +1229,13 @@ emit_logical_branch(_PyTier2TypeContext *type_context, _Py_CODEUNIT *write_curr, } } +/** + * @brief Emits the exit of a scope. + * @param write_curr The tier 2 instruction write buffer. + * @param exit The tier 1 exit instruction. + * @param type_context The BB's type context. + * @return The updated tier 2 instruction write buffer end. +*/ static inline _Py_CODEUNIT * emit_scope_exit(_Py_CODEUNIT *write_curr, _Py_CODEUNIT exit, _PyTier2TypeContext *type_context) @@ -1126,6 +1266,13 @@ emit_scope_exit(_Py_CODEUNIT *write_curr, _Py_CODEUNIT exit, } } +/** + * @brief Emit a single instruction. (Respects EXTENDED_ARG). + * @param write_curr The tier 2 instruction write buffer. + * @param opcode The instruction's opcode. + * @param oparg The instruction's oparg. + * @return The updated tier 2 instruction write buffer end. +*/ static inline _Py_CODEUNIT * emit_i(_Py_CODEUNIT *write_curr, int opcode, int oparg) { @@ -1140,9 +1287,18 @@ emit_i(_Py_CODEUNIT *write_curr, int opcode, int oparg) return write_curr; } -// Note: we're copying over the actual caches to preserve information! -// This way instructions that we can't type propagate over still stay -// optimized. + +/** + * @brief Copy over cache entries, preserving their information. + * Note: we're copying over the actual caches to preserve information! + * This way instructions that we can't type propagate over still stay + * optimized. + * + * @param write_curr The tier 2 instruction write buffer + * @param cache The tier 1 CACHE to copy. + * @param n_entries How many CACHE entries to copy. + * @return The updated tier 2 instruction write buffer end. +*/ static inline _Py_CODEUNIT * copy_cache_entries(_Py_CODEUNIT *write_curr, _Py_CODEUNIT *cache, int n_entries) { @@ -1155,7 +1311,12 @@ copy_cache_entries(_Py_CODEUNIT *write_curr, _Py_CODEUNIT *cache, int n_entries) } - +/** + * @brief Checks if the current instruction is a backwards jump target. + * @param co The code object the instruction belongs to. + * @param curr The current instruction to check. + * @return Yes/No. +*/ static int IS_BACKWARDS_JUMP_TARGET(PyCodeObject *co, _Py_CODEUNIT *curr) { @@ -1172,7 +1333,19 @@ IS_BACKWARDS_JUMP_TARGET(PyCodeObject *co, _Py_CODEUNIT *curr) return 0; } -// 1 for error, 0 for success. +/** + * @brief Adds BB metadata to the jump 2D array that a tier 2 code object contains. + * This happens when a BB is a backwards jump target. + * + * @param t2_info Tier 2 info of that code object. + * @param meta The BB metadata to add. + * @param backwards_jump_target Offset (in number of codeunits) from start of code object where + * the backwards jump target is located. + * + * @param starting_context The type context at the start of the jump target BB. + * @param tier1_start The tier 1 starting instruction of the jump target BB. + * @return 1 for error, 0 for success. +*/ static inline int add_metadata_to_jump_2d_array(_PyTier2Info *t2_info, _PyTier2BBMetadata *meta, int backwards_jump_target, _PyTier2TypeContext *starting_context, @@ -1211,13 +1384,30 @@ add_metadata_to_jump_2d_array(_PyTier2Info *t2_info, _PyTier2BBMetadata *meta, return 0; } -// This converts sequence of instructions like -// BINARY_OP (ADD) -// to -// BINARY_CHECK_INT -// BB_BRANCH -// CACHE (bb_id of the current BB << 1 | is_type_branch) -// // The BINARY_ADD then goes to the next BB +/** + * @brief Infers the correct BINARY_OP to use. This is where we choose to emit + * more efficient arithmetic instructions. + * + * This converts sequence of instructions like + * BINARY_OP (ADD) + * to + * BINARY_CHECK_INT + * BB_BRANCH + * CACHE (bb_id of the current BB << 1 | is_type_branch) + * // The BINARY_ADD then goes to the next BB + * + * @param t2_start Start of the current basic block. + * @param oparg Oparg of the BINARY_OP. + * @param needs_guard Signals to the caller whether they should emit a type guard. + * @param prev_type_guard The previous basic block's ending type guard (this is + * required for the ladder of types). + * + * @param raw_op The tier 0/1 BINARY_OP. + * @param write_curr Tier 2 instruction write buffer. + * @param type_context Current type context to base our decisions on. + * @param bb_id The current BB's ID. + * @return Updated tier 2 instruction write buffer end. +*/ static inline _Py_CODEUNIT * infer_BINARY_OP( _Py_CODEUNIT *t2_start, @@ -1296,6 +1486,24 @@ infer_BINARY_OP( return NULL; } +/** + * @brief Infers the correct BINARY_SUBSCR to use. This is where we choose to emit + * more efficient container instructions. + * + * @param t2_start Start of the current basic block. + * @param oparg Oparg of the BINARY_OP. + * @param needs_guard Signals to the caller whether they should emit a type guard. + * @param prev_type_guard The previous basic block's ending type guard (this is + * required for the ladder of types). + * + * @param raw_op The tier 0/1 BINARY_OP. + * @param write_curr Tier 2 instruction write buffer. + * @param type_context Current type context to base our decisions on. + * @param bb_id The current BB's ID. + * @param store Whether it's a store instruction (STORE_SUBSCR) or not (BINARY_SUBSCR). + * @return Updated tier 2 instruction write buffer end. + * @return +*/ static inline _Py_CODEUNIT * infer_BINARY_SUBSCR( _Py_CODEUNIT *t2_start, @@ -1344,23 +1552,36 @@ infer_BINARY_SUBSCR( return NULL; } +/** + * @brief Whether this is an unboxed type. + * @param t The type to check. + * @return Yes/No. +*/ static inline bool is_unboxed_type(PyTypeObject *t) { return t == &PyRawFloat_Type; } -// Detects a BB from the current instruction start to the end of the first basic block it sees. -// Then emits the instructions into the bb space. -// -// Instructions emitted depend on the type_context. -// For example, if it sees a BINARY_ADD instruction, but it knows the two operands are already of -// type PyLongObject, a BINARY_ADD_INT_REST will be emitted without an type checks. -// -// However, if one of the operands are unknown, a logical chain of CHECK instructions will be emitted, -// and the basic block will end at the first of the chain. -// -// Note: a BB end also includes a type guard. + +/** + * @brief Detects a BB from the current instruction start to the end of the first basic block it sees. Then emits the instructions into the bb space. + * + * Instructions emitted depend on the type_context. + * For example, if it sees a BINARY_ADD instruction, but it knows the two operands are already of + * type PyLongObject, a BINARY_ADD_INT_REST will be emitted without an type checks. + * + * However, if one of the operands are unknown, a logical chain of CHECK instructions will be + * emitted, and the basic block will end at the first of the chain. + * Note: a BB end also includes a type guard. + * + * @param co The code object we're optimizing. + * @param bb_space The BB space of the code object to write to. + * @param prev_type_guard The type guard that ended the previous basic block (if present). + * @param tier1_start The tier 1 instructions to start referring from. + * @param starting_type_context The starting type context for this new basic block. + * @return A new tier 2 basic block. +*/ _PyTier2BBMetadata * _PyTier2_Code_DetectAndEmitBB( PyCodeObject *co, @@ -1829,6 +2050,12 @@ compare_ints(const void *a, const void *b) return *(int *)a - *(int *)b; } +/** + * @brief Allocates the 2D array required to store information about backwards jump targets. + * @param backwards_jump_count How many backwards jump targets there are. + * @param backward_jump_target_bb_pairs Triplet information required about the backward jump target. + * @return 0 on success 1 on error. +*/ static int allocate_jump_offset_2d_array(int backwards_jump_count, _PyTier2BBStartTypeContextTriplet **backward_jump_target_bb_pairs) @@ -1854,8 +2081,12 @@ allocate_jump_offset_2d_array(int backwards_jump_count, return 1; } -// Returns 1 on error, 0 on success. Populates the backwards jump target offset -// array for a code object.. + +/** + * @brief Populates the backwards jump target offset array for a code object. + * @param co The code object to populate. + * @return Returns 1 on error, 0 on success. +*/ static int _PyCode_Tier2FillJumpTargets(PyCodeObject *co) { @@ -1955,7 +2186,11 @@ _PyCode_Tier2FillJumpTargets(PyCodeObject *co) } - +/** + * @brief Initializes the tier 2 info of a code object. + * @param co The code object. + * @return The newly allocated tier 2 info. +*/ static _PyTier2Info * _PyTier2Info_Initialize(PyCodeObject *co) { @@ -1989,12 +2224,19 @@ _PyTier2Info_Initialize(PyCodeObject *co) ////////// OVERALL TIER2 FUNCTIONS -// We use simple heuristics to determine if there are operations -// we can optimize in this. -// Specifically, we are looking for the presence of PEP 659 -// specialized forms of bytecode, because this indicates -// that it's a known form. -// ADD MORE HERE AS WE GO ALONG. +/** + * @brief Whether the opcode is optimizable. + * + * We use simple heuristics to determine if there are operations we can optimize. + * Specifically, we are looking for the presence of PEP 659 (tier 1) + * specialized forms of bytecode, because this indicates that it's a known form. + * + * ADD MORE HERE AS WE GO ALONG. + * + * @param opcode The opcode of the instruction. + * @param oparg The oparg of the instruction. + * @return Yes/No. +*/ static inline int IS_OPTIMIZABLE_OPCODE(int opcode, int oparg) { @@ -2014,6 +2256,11 @@ IS_OPTIMIZABLE_OPCODE(int opcode, int oparg) } } +/** + * @brief Single scan to replace RESUME and JUMP_BACKWARD instructions to faster + * variants so they stop warming up the tier 2. + * @param co The code object to optimize. +*/ static inline void replace_resume_and_jump_backwards(PyCodeObject *co) { @@ -2034,9 +2281,17 @@ replace_resume_and_jump_backwards(PyCodeObject *co) } } -// 1. Initialize whatever we need. -// 2. Create the entry BB. -// 3. Jump into that BB. +/** + * @brief Initializes the tier 2 of a code object. Called upon first transition from tier 1 + * to tier 2, when a code object is deemed hot. + * + * 1. Initialize whatever we need. + * 2. Create the entry BB. + * 3. Jump into that BB. + * @param frame The current executing frame. + * @param next_instr The next instruction of said frame. + * @return The next instruction (tier 2) to execute. +*/ static _Py_CODEUNIT * _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) { @@ -2132,7 +2387,13 @@ _PyCode_Tier2Initialize(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) ////////// CEVAL FUNCTIONS -// Tier 2 warmup counter +/** + * @brief Tier 2 warmup counter. + * @param frame Currente executing frame. + * @param next_instr The next instruction that frame is executing. + * @return The next instruction that should be executed (no change if the code object + * is not hot enough). +*/ _Py_CODEUNIT * _PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) { @@ -2152,6 +2413,19 @@ _PyCode_Tier2Warmup(_PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr) return next_instr; } +/** + * @brief Generates the next BB with a type context given. + * + * @param frame The current executing frame. + * @param bb_id_tagged The tagged version of the BB_ID (see macros above to understand). + * @param curr_executing_instr The current executing instruction in that frame. + * @param jumpby How many instructions to jump by before we start scanning what to generate. + * @param tier1_fallback Signals the tier 1 instruction to fall back to should generation fail. + * @param bb_flag Whether to genreate consequent or alternative BB. + * @param type_context_copy A given type context to start with. + * @param custom_tier1_end Custom tier 1 instruction to fall back to should we fail. + * @return The new BB's metadata. +*/ _PyTier2BBMetadata * _PyTier2_GenerateNextBBMetaWithTypeContext( _PyInterpreterFrame *frame, @@ -2210,9 +2484,16 @@ _PyTier2_GenerateNextBBMetaWithTypeContext( return metadata; } -// Lazily generates successive BBs when required. -// The first basic block created will always be directly after the current tier 2 code. -// The second basic block created will always require a jump. +/** + * @brief Generates the next BB, with an automatically inferred type context. + * @param frame The current executing frame. + * @param bb_id_tagged The tagged version of the BB_ID (see macros above to understand). + * @param curr_executing_instr The current executing instruction in that frame. + * @param jumpby How many instructions to jump by before we start scanning what to generate. + * @param tier1_fallback Signals the tier 1 instruction to fall back to should generation fail. + * @param bb_flag Whether to genreate consequent or alternative BB. + * @return The new BB's metadata. +*/ _PyTier2BBMetadata * _PyTier2_GenerateNextBBMeta( _PyInterpreterFrame *frame, @@ -2250,6 +2531,19 @@ _PyTier2_GenerateNextBBMeta( return next; } +/** + * @brief Lazily generates successive BBs when required. + * The first basic block created will always be directly after the current tier 2 code. + * The second basic block created will always require a jump. + * + * @param frame The current executing frame. + * @param bb_id_tagged The tagged version of the BB_ID (see macros above to understand). + * @param curr_executing_instr The current executing instruction in that frame. + * @param jumpby How many instructions to jump by before we start scanning what to generate. + * @param tier1_fallback Signals the tier 1 instruction to fall back to should generation fail. + * @param bb_flag Whether to genreate consequent or alternative BB. + * @return The next tier 2 instruction to execute. +*/ _Py_CODEUNIT * _PyTier2_GenerateNextBB( _PyInterpreterFrame *frame, @@ -2272,9 +2566,13 @@ _PyTier2_GenerateNextBB( return metadata->tier2_start; } -// Calculates the difference between two type contexts. -// A positive number indicating the distance is returned. -// Incompatible type contexts return INT_MAX. +/** + * @brief Calculates the difference between two type contexts. + * @param ctx1 The base type context. + * @param ctx2 The type context to compare with. + * @return A positive number indicating the distance is returned. + * Incompatible type contexts return INT_MAX. +*/ static int diff_typecontext(_PyTier2TypeContext *ctx1, _PyTier2TypeContext *ctx2) { @@ -2347,6 +2645,19 @@ diff_typecontext(_PyTier2TypeContext *ctx1, _PyTier2TypeContext *ctx2) return diff; } +/** + * @brief Locate the BB corresponding to a backwards jump target. Matches also the type context. + * If it fails to find a matching type context, a new backwards jump BB is generated with + * more specific type context. + * + * @param frame The current executing frame. + * @param bb_id_tagged The tagged version of the BB_ID (see macros above to understand). + * @param jumpby How many instructions away is the backwards jump target. + * @param tier1_fallback Signals the tier 1 instruction to fall back to should generation fail. + * @param curr Current executing instruction + * @param stacklevel The stack level of the operand stack. + * @return The next tier 2 instruction to execute. +*/ _Py_CODEUNIT * _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id_tagged, int jumpby, _Py_CODEUNIT **tier1_fallback, @@ -2470,22 +2781,25 @@ _PyTier2_LocateJumpBackwardsBB(_PyInterpreterFrame *frame, uint16_t bb_id_tagged return target_metadata->tier2_start; } -/* -At generation of the second outgoing edge (basic block), the instructions look like this: - -BB_TEST_POP_IF_TRUE -BB_BRANCH_IF_FLAG_SET -CACHE - -Since both edges are now generated, we want to rewrite it to: -BB_TEST_POP_IF_TRUE -BB_JUMP_IF_FLAG_SET -CACHE (will be converted to EXTENDED_ARGS if we need a bigger jump) - -Backwards jumps are handled by another function. +/** + * @brief Rewrites the BB_BRANCH_IF* instructions to a forward jump. + * At generation of the second outgoing edge (basic block), the instructions look like this: + * BB_TEST_POP_IF_TRUE + * BB_BRANCH_IF_FLAG_SET + * CACHE + * + * Since both edges are now generated, we want to rewrite it to: + * + * BB_TEST_POP_IF_TRUE + * BB_JUMP_IF_FLAG_SET + * CACHE (will be converted to EXTENDED_ARGS if we need a bigger jump) + * + * Backwards jumps are handled by another function. + * + * @param bb_branch Whether the next BB to execute is the consequent/alternative BB. + * @param target The jump target. */ - void _PyTier2_RewriteForwardJump(_Py_CODEUNIT *bb_branch, _Py_CODEUNIT *target) { @@ -2514,21 +2828,24 @@ _PyTier2_RewriteForwardJump(_Py_CODEUNIT *bb_branch, _Py_CODEUNIT *target) } -/* -Before: - -EXTENDED_ARG/NOP -BB_JUMP_BACKWARD_LAZY -CACHE - - -After: - -EXTENDED_ARG (if needed, else NOP) -JUMP_BACKWARD_QUICK -END_FOR +/** + * @brief Rewrites a BB_JUMP_BACKWARD_LAZY to a more efficient standard BACKWARD_JUMP. + * + * Before: + * + * EXTENDED_ARG/NOP + * BB_JUMP_BACKWARD_LAZY + * CACHE + * + * After: + * + * EXTENDED_ARG (if needed, else NOP) + * JUMP_BACKWARD_QUICK + * END_FOR + * + * @param jump_backward_lazy The backwards jump instruction. + * @param target The target we're jumping to. */ - void _PyTier2_RewriteBackwardJump(_Py_CODEUNIT *jump_backward_lazy, _Py_CODEUNIT *target) { From ab2145e19d2d739a606976f5b0813d84386ebf34 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat, 8 Apr 2023 02:31:59 +0800 Subject: [PATCH 263/280] Add instructions --- CS4215.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 CS4215.md diff --git a/CS4215.md b/CS4215.md new file mode 100644 index 00000000000000..5cba2b2c0f459e --- /dev/null +++ b/CS4215.md @@ -0,0 +1,20 @@ +# A Lazy Basic Block Versioning Interpreter for CPython. + +# Build instructions + +You should follow the official CPython build instructions for your platform. +https://devguide.python.org/getting-started/setup-building/ + +We have one major difference - you must have a pre-existing Python installation. +Preferrably Python 3.9 or higher. On MacOS/Unix systems, that Python installation +*must* be located at `python3`. + +The main reason for this limitation is that Python is used to bootstrap the compilation +of Python. However, since our interpreter is unable to run a large part of the Python +language, our interpreter cannot be used as a bootstrap Python. + + +# Where are files located? + +The majority of the changes and functionality are in `Python/tier2.c`. Doxygen documentation +is written alongside the code. \ No newline at end of file From 59f885d0c7ae1d8d58fef25e0a4f98d969a547d7 Mon Sep 17 00:00:00 2001 From: Jules <57632293+JuliaPoo@users.noreply.github.com> Date: Sat, 8 Apr 2023 17:20:04 +0800 Subject: [PATCH 264/280] Docs: Added typeprop documentation (#36) --- Python/tier2.c | 61 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index 4dc65af081e0b2..8ade0405756cd5 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -248,12 +248,21 @@ typenode_get_type(_Py_TYPENODE_t node) } } -// @TODO @JULES /** - * @brief - * @param src - * @param dst - * @param src_is_new + * @brief Performs TYPE_SET operation. dst tree becomes part of src tree + * + * If src_is_new is set, src is interpreted as a TYPE_ROOT + * not part of the type_context. Otherwise, it is interpreted as a pointer + * to a _Py_TYPENODE_t. + * + * If src_is_new: + * Overwrites the root of the dst tree with the src node + * else: + * Makes the root of the dst tree a TYPE_REF to src + * + * @param src Source node + * @param dst Destination node + * @param src_is_new true if src is not part of the type_context */ static void __type_propagate_TYPE_SET( @@ -298,13 +307,24 @@ __type_propagate_TYPE_SET( } } -// @TODO @JULES /** - * @brief - * @param type_context - * @param src - * @param dst - * @param src_is_new + * @brief Performs TYPE_OVERWRITE operation. dst node gets overwritten by src node + * + * If src_is_new is set, src is interpreted as a TYPE_ROOT + * not part of the type_context. Otherwise, it is interpreted as a pointer + * to a _Py_TYPENODE_t. + * + * If src_is_new: + * Removes dst node from its tree (+fixes all the references to dst) + * Overwrite the dst node with the src node + * else: + * Removes dst node from its tree (+fixes all the references to dst) + * Makes the root of the dst tree a TYPE_REF to src + * + * @param type_context Type context to modify + * @param src Source node + * @param dst Destination node + * @param src_is_new true if src is not part of the type_context */ static void __type_propagate_TYPE_OVERWRITE( @@ -421,15 +441,20 @@ __type_propagate_TYPE_OVERWRITE( } } - -// @TODO @JULES /** - * @brief - * @param type_context - * @param src - * @param dst - * + * @brief Performs TYPE_SWAP operation. dst node and src node swap positions + * * src and dst are assumed to already be within the type context + * + * If src and dst are the same tree + * Do nothing + * else: + * Fix all references of dst to point to src and vice versa + * + * @param type_context Type context to modify + * @param src Source node + * @param dst Destination node + * */ static void __type_propagate_TYPE_SWAP( From badce84b8a199b66b4f308686de27bc69756a5e6 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 11 Apr 2023 16:49:07 +0800 Subject: [PATCH 265/280] Fix type guard emitting --- Python/tier2.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Python/tier2.c b/Python/tier2.c index 4dc65af081e0b2..7b2428cfb94b2b 100644 --- a/Python/tier2.c +++ b/Python/tier2.c @@ -1074,9 +1074,14 @@ emit_type_guard(_Py_CODEUNIT *write_curr, int guard_opcode, int guard_oparg, int _PyOpcode_OpName[guard_opcode]); #endif write_curr->op.code = guard_opcode; - write_curr->op.arg = guard_oparg; + write_curr->op.arg = guard_oparg & 0xFF; write_curr++; - _py_set_opcode(write_curr, BB_BRANCH); + + write_curr->op.code = NOP; + write_curr->op.arg = 0; + write_curr++; + + write_curr->op.code = BB_BRANCH; write_curr->op.arg = 0; write_curr++; _PyBBBranchCache *cache = (_PyBBBranchCache *)write_curr; @@ -2460,8 +2465,12 @@ _PyTier2_GenerateNextBBMetaWithTypeContext( __type_stack_shrink(&(type_context_copy->type_stack_ptr), n_required_pop); } // For type branches, they directly precede the bb branch instruction + // It's always + // TYPE_BRANCH + // NOP + // BB_BRANCH _Py_CODEUNIT *prev_type_guard = BB_IS_TYPE_BRANCH(bb_id_tagged) - ? curr_executing_instr - 1 : NULL; + ? curr_executing_instr - 2 : NULL; if (BB_TEST_IS_SUCCESSOR(bb_flag) && prev_type_guard != NULL) { // Propagate the type guard information. #if TYPEPROP_DEBUG && defined(Py_DEBUG) From fd338dfc1d32f829684af06dd1c02c15e2140d06 Mon Sep 17 00:00:00 2001 From: Jules <57632293+JuliaPoo@users.noreply.github.com> Date: Thu, 13 Apr 2023 16:38:13 +0800 Subject: [PATCH 266/280] Tests: Modified dis.py and added primitive tests (#37) * Tests: Modified dis.py and added primitive tests * Docs: Typos and more documentation * Test: Fixed minor issue --- CS4215.md | 22 +++- Lib/dis.py | 10 +- Python/tier2.c | 4 +- tier2_test.py | 322 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 350 insertions(+), 8 deletions(-) create mode 100644 tier2_test.py diff --git a/CS4215.md b/CS4215.md index 5cba2b2c0f459e..78a71fdd52125d 100644 --- a/CS4215.md +++ b/CS4215.md @@ -16,5 +16,23 @@ language, our interpreter cannot be used as a bootstrap Python. # Where are files located? -The majority of the changes and functionality are in `Python/tier2.c`. Doxygen documentation -is written alongside the code. \ No newline at end of file +The majority of the changes and functionality are in `Python/tier2.c` where Doxygen documentation +is written alongside the code, and in `Tools/cases_generator/` which contains the DSL implementation. + +# Running tests + +We've written simple tests of the main functionalities. +Unfortunately we did not have time to write comprehensive tests, and it doesn't seem worth it eitherways given the experimental nature of this project. + +After building, run `python tier2_test.py` in the repository's root folder. + +# Debugging output + +In `tier2.c`, two flags can be set to print debug messages: +```c +// Prints codegen debug messages +#define BB_DEBUG 0 + +// Prints typeprop debug messages +#define TYPEPROP_DEBUG 0 +``` \ No newline at end of file diff --git a/Lib/dis.py b/Lib/dis.py index 65fd696012718f..501035389a1d81 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -474,6 +474,7 @@ def _get_instructions_bytes(code, varname_from_oparg=None, for i in range(start, end): labels.add(target) starts_line = None + ret = [] for offset, op, arg in _unpack_opargs(code): if linestarts is not None: starts_line = linestarts.get(offset, None) @@ -534,9 +535,9 @@ def _get_instructions_bytes(code, varname_from_oparg=None, if arg & (1<locals[0], int->stack[0], int->stack[1]] + "BINARY_CHECK_INT", + "NOP", + "BB_BRANCH_IF_FLAG_UNSET", # Fallthrough! + + # Should propagate the result as int + # TYPE_OVERWRITE + # Locals: [int] + # Stack : [int->locals[0], int] + "BINARY_OP_ADD_INT_REST", + + # There should be no more guards here + # if the type propagator is working + "BINARY_OP_ADD_INT_REST", + "RETURN_VALUE" +] +insts = dis.get_instructions(test_typeprop1, tier2=True) +for x,y in zip(insts, expected): + assert x.opname == y + +bytecode = b"".join([ + # Tests TYPE_SWAP + writeinst("RESUME", 0), + writeinst("LOAD_FAST", 0), # float + writeinst("LOAD_FAST", 1), # int + writeinst("SWAP", 2), # Stack: [int, float] + + writeinst("COPY", 1), + # Should generate the FLOAT specialisation + writeinst("BINARY_OP", 0), + writeinst("CACHE", 0), # For tier1 + + writeinst("SWAP", 2), # [float, int] + writeinst("COPY", 1), + # Should generate the INT specialisation + writeinst("BINARY_OP", 0), + writeinst("CACHE", 0), # For tier1 + + # float + int + writeinst("BINARY_OP", 0), + writeinst("CACHE", 0), # For tier1 + writeinst("RETURN_VALUE", 0) +]) + +def test_typeprop2(a,b): + # Dummy code won't be ran + return a+(a+(a+a)) + +# Switch to bytecode +test_typeprop2.__code__ = test_typeprop2.__code__.replace(co_code=bytecode) +test_typeprop2(0.1,1) + +trigger_tier2(test_typeprop2, (0.1,1)) +expected = [ + "RESUME_QUICK", + "LOAD_FAST", + "LOAD_FAST", + "SWAP", + "COPY", + + # Should gen specialised float + "BINARY_CHECK_FLOAT", + "NOP", + "BB_BRANCH_IF_FLAG_UNSET", + "BINARY_OP_ADD_FLOAT_UNBOXED", + "SWAP", + "COPY", + + # Ladder of types guards + "BINARY_CHECK_FLOAT", + "NOP", + "BB_BRANCH_IF_FLAG_SET", + + # Should gen specialised int + "BINARY_CHECK_INT", + "NOP", + "BB_BRANCH_IF_FLAG_UNSET", + "BINARY_OP_ADD_INT_REST", + # Don't care about the rest of the insts +] +insts = dis.get_instructions(test_typeprop2, tier2=True) +# Assert the value is correct +assert abs(test_typeprop2(0.1,1) - 2.2) < 0.001 +for x,y in zip(insts, expected): + assert x.opname == y + + +####################################### +# Type guard # +# + Float unboxing # +# + Jump rewriting test # +####################################### + +def test_guard_elimination(a,b): + x = b + y = b + # First a+x should inform the type prop that + # `a`, `x`, `b` and `y` are int + # So guard should be eliminated in (a+x) + y + return a + x + y + +trigger_tier2(test_guard_elimination, (0,0)) +expected = [ + # From tier1 bytecode + "RESUME_QUICK", + "LOAD_FAST", + "STORE_FAST", + "LOAD_FAST", + "STORE_FAST", + "LOAD_FAST", + "LOAD_FAST", + + "BINARY_CHECK_FLOAT", # First ladder check + "NOP", + "BB_BRANCH_IF_FLAG_SET", + "BINARY_CHECK_INT", # Second ladder check + "NOP", + "BB_BRANCH_IF_FLAG_UNSET", # Fall through! + + "BINARY_OP_ADD_INT_REST", # a+x + "LOAD_FAST", + "BINARY_OP_ADD_INT_REST", # (a+x) + y (guard eliminated) + "RETURN_VALUE" +] +insts = dis.get_instructions(test_guard_elimination, tier2=True) +for x,y in zip(insts, expected): + assert x.opname == y + +# We only wanna test the stability of the first type guards +# later on +first_guard_test_until = insts[-1].offset + +# Trigger generation of other branch +test_guard_elimination(0.1, 0.1) +insts = dis.get_instructions(test_guard_elimination, tier2=True) +expected = [ + # From tier1 bytecode + "RESUME_QUICK", + "LOAD_FAST", + "STORE_FAST", + "LOAD_FAST", + "STORE_FAST", + "LOAD_FAST", + "LOAD_FAST", + + "BINARY_CHECK_FLOAT", # First ladder check + "NOP", + "BB_JUMP_IF_FLAG_SET", # Rewrite to jump to float case + "POP_TOP", # Pop result + + # The same as above + "BINARY_CHECK_INT", + "NOP", + "BB_BRANCH_IF_FLAG_UNSET", + "BINARY_OP_ADD_INT_REST", + "LOAD_FAST", + "BINARY_OP_ADD_INT_REST", + "RETURN_VALUE", + + # Float case + "BINARY_OP_ADD_FLOAT_UNBOXED", # Unbox + "LOAD_FAST", + "UNBOX_FLOAT", # Unbox local + "STORE_FAST_UNBOXED_BOXED", # Store unboxed float into local + "LOAD_FAST_NO_INCREF", # Load (unboxed) local again + "BINARY_OP_ADD_FLOAT_UNBOXED", # No type guard here + "BOX_FLOAT", # Box to return + "RETURN_VALUE" +] + +test_guard_elimination(1,1) +for x,y in zip(insts, expected): + assert x.opname == y + +# Perform other polymorphism stuff +# We've not implemented type guard elimination +# For these mixed types (e.g., float+int) +# So these will generate more type guards with the same +# mechanisms as above. +# So codegen wise tier2 takes a while to stabilise +assert (test_guard_elimination(1,0.1) - 1.2) < 0.001 +assert (test_guard_elimination(0.1,1) - 2.1) < 0.001 +assert (test_guard_elimination(.4,.5) - 1.4) < 0.001 +assert test_guard_elimination(2,3) == 8 + +# At this point all cases should be generated +# so check if the generated cases are the same +expected = dis.get_instructions(test_guard_elimination, tier2=True) +test_guard_elimination(-192,203) +test_guard_elimination(2.3, 12) +test_guard_elimination(324, 0.12) +test_guard_elimination(0.12,32.1) +insts = dis.get_instructions(test_guard_elimination, tier2=True) + +# Make sure the first type guard is stable +for x,y in zip(insts, expected): + if x.offset >= first_guard_test_until: + break + assert x.opname == y.opname + + +###################### +# Backward jump test # +# + loop peeling # +###################### + +def test_backwards_jump(a): + for i in range(64): + a = i + a + return a + +# Trigger only one JUMP_BACKWARD_QUICK +# i.e., perfect specialisation the first time +trigger_tier2(test_backwards_jump, (0,)) + +# Make sure it looped 64 times +assert test_backwards_jump(7) == 2023 # <-- Hi! ~ Jules + +# Make sure it jumped to the correct spot +insts = dis.get_instructions(test_backwards_jump, tier2=True) +backwards_jump = next(x for x in insts if x.opname == "JUMP_BACKWARD_QUICK") +instidx, jmp_target = next((i,x) for i,x in enumerate(insts) if x.offset == backwards_jump.argval) +assert jmp_target.opname == "NOP" # Space for an EXTENDED_ARG +assert insts[instidx + 1].opname == "BB_TEST_ITER_RANGE" # The loop predicate + + +def test_loop_peeling(a): + for i in range(64): + a = float(i) + a + return a + +# This triggers loop peeling, because +# the first iteration `a` type is int +# and the 2nd iteration `a` type is float +# This should triger a JUMP_FORWARD in place of +# a JUMP_BACKWARD_QUICK +trigger_tier2(test_loop_peeling, (0,)) + +# Make sure it looped 64 times +assert abs(test_loop_peeling(7) - 2023) < 0.001 + +# Make sure the JUMP_FORWARD jumped correctly +insts = dis.get_instructions(test_loop_peeling, tier2=True) +forwards_jump = next(x for x in insts if x.opname == "JUMP_FORWARD") +instidx, jmp_target = next((i,x) for i,x in enumerate(insts) if x.offset == forwards_jump.argval) +assert jmp_target.opname == "NOP" # Space for an EXTENDED_ARG +assert insts[instidx + 1].opname == "BB_TEST_ITER_RANGE" # The loop predicate + +# We also need to make sure JUMP_FORWARD +# jumped into the float-specialised loop body +endidx, _ = next( + (i,x) for i,x in enumerate(insts) + if (x.opname == "JUMP_BACKWARD_QUICK" and x.offset > jmp_target.offset)) +# Check for existence of float-specialised instruction in loop body +assert any(1 for _ in + filter(lambda i: i.opname == 'BINARY_OP_ADD_FLOAT_UNBOXED', insts[instidx:endidx])) + From d1f3a740d88247db5ea0036f5c864f02cb1d75f6 Mon Sep 17 00:00:00 2001 From: Jules <57632293+JuliaPoo@users.noreply.github.com> Date: Fri, 14 Apr 2023 21:44:09 +0800 Subject: [PATCH 267/280] Test: Added test for container specialisation (#39) --- tier2_test.py | 69 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 8 deletions(-) diff --git a/tier2_test.py b/tier2_test.py index 499de3b47195a0..eb372b87b6ac8a 100644 --- a/tier2_test.py +++ b/tier2_test.py @@ -25,9 +25,9 @@ def writeinst(opc:str, arg:int=0): return bytes(inst) -################### -# Type prop tests # -################### +################################################ +# Type prop tests: TYPE_SET and TYPE_OVERWRITE # +################################################ def test_typeprop1(a): # Dummy code won't be ran @@ -83,6 +83,10 @@ def test_typeprop1(a): for x,y in zip(insts, expected): assert x.opname == y +################################################ +# Type prop tests: TYPE_SWAP # +################################################ + bytecode = b"".join([ # Tests TYPE_SWAP writeinst("RESUME", 0), @@ -151,9 +155,10 @@ def test_typeprop2(a,b): ####################################### -# Type guard # +# Tests for: Type guard # # + Float unboxing # # + Jump rewriting test # +# + Tier2 guard stability # ####################################### def test_guard_elimination(a,b): @@ -264,10 +269,9 @@ def test_guard_elimination(a,b): assert x.opname == y.opname -###################### -# Backward jump test # -# + loop peeling # -###################### +############################## +# Test: Backward jump offset # +############################## def test_backwards_jump(a): for i in range(64): @@ -289,6 +293,10 @@ def test_backwards_jump(a): assert insts[instidx + 1].opname == "BB_TEST_ITER_RANGE" # The loop predicate +###################### +# Test: Loop peeling # +###################### + def test_loop_peeling(a): for i in range(64): a = float(i) + a @@ -320,3 +328,48 @@ def test_loop_peeling(a): assert any(1 for _ in filter(lambda i: i.opname == 'BINARY_OP_ADD_FLOAT_UNBOXED', insts[instidx:endidx])) + +################################## +# Test: Container specialisation # +################################## + +def test_container(l): + l[2] = l[0] + l[1] + + +trigger_tier2(test_container, ([1,2,3,4],)) +insts = dis.get_instructions(test_container, tier2=True) +expected = [ + "RESUME_QUICK", + "LOAD_FAST", + "LOAD_CONST", + + "CHECK_LIST", + "NOP", + "BB_BRANCH_IF_FLAG_UNSET", # Fallthrough! + + # Type prop from const array: No type guard needed + "BINARY_SUBSCR_LIST_INT_REST", + "LOAD_FAST", + "LOAD_CONST", + # CHECK_LIST should eliminate the type guard here + "BINARY_SUBSCR_LIST_INT_REST", + + # We haven't implemented type prop into container types + # so these checks should get generated + "BINARY_CHECK_FLOAT", + "NOP", + "BB_BRANCH_IF_FLAG_SET", + "BINARY_CHECK_INT", + "NOP", + "BB_BRANCH_IF_FLAG_UNSET", + "BINARY_OP_ADD_INT_REST", + + "LOAD_FAST", + "LOAD_CONST", + # CHECK_LIST should eliminate the type guard here + "STORE_SUBSCR_LIST_INT_REST", + "RETURN_CONST", +] +for x,y in zip(insts, expected): + assert x.opname == y From 3366ecac548412f77530c1e480274d7df1985db5 Mon Sep 17 00:00:00 2001 From: kenjin-work Date: Sat, 15 Apr 2023 23:33:40 +0800 Subject: [PATCH 268/280] modify test --- bm_nbody.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bm_nbody.py b/bm_nbody.py index 51c2d383a47c4c..f9642bb9480318 100644 --- a/bm_nbody.py +++ b/bm_nbody.py @@ -143,7 +143,7 @@ def add_cmdline_args(cmd, args): # Warmup bench_nbody(128, DEFAULT_REFERENCE, 128) # Showtime - print("It's showtime") + print("Starting benchmark...") taken = bench_nbody(DEFAULT_ITERATIONS, DEFAULT_REFERENCE, 50_000) print("Time taken is", taken, "s") \ No newline at end of file From 223949acd1b7266936c17a5e2b352101a97065ed Mon Sep 17 00:00:00 2001 From: kenjin-work Date: Sat, 15 Apr 2023 23:40:25 +0800 Subject: [PATCH 269/280] update build info --- CS4215.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CS4215.md b/CS4215.md index 78a71fdd52125d..a1e03357240abf 100644 --- a/CS4215.md +++ b/CS4215.md @@ -13,6 +13,8 @@ The main reason for this limitation is that Python is used to bootstrap the comp of Python. However, since our interpreter is unable to run a large part of the Python language, our interpreter cannot be used as a bootstrap Python. +During the build process, errors may be printed, and the build process may error. However, +the final Python executable should still be generated. # Where are files located? From ce3724f547939958354af521563fa8f53722bba2 Mon Sep 17 00:00:00 2001 From: kenjin-work Date: Sun, 16 Apr 2023 00:05:21 +0800 Subject: [PATCH 270/280] Create bm_float_unboxed.py --- bm_float_unboxed.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 bm_float_unboxed.py diff --git a/bm_float_unboxed.py b/bm_float_unboxed.py new file mode 100644 index 00000000000000..22f586eca2983a --- /dev/null +++ b/bm_float_unboxed.py @@ -0,0 +1,17 @@ +import time + +def f(a, b): + for _ in range(10_000_000): + return a + b + a * a + b - a - b + +# Warmup +f(1.0, 2.0) +f(1.0, 2.0) + +# Running the actual benchmark + +print("Starting benchmark...") +start = time.perf_counter() +for _ in range(100_000_000): + f(1.0, 2.0) +print("Time taken is", time.perf_counter() - start, "s") From aef35162896c7c4d1efcf251445a5b4ee88bc998 Mon Sep 17 00:00:00 2001 From: kenjin-work Date: Sun, 16 Apr 2023 00:19:26 +0800 Subject: [PATCH 271/280] Commit pylbbv results --- ...e3724f547939958354af521563fa8f53722bba2_bm_float_unboxed.txt | 2 ++ .../ce3724f547939958354af521563fa8f53722bba2_bm_nbody.txt | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 tier2_results/pylbbv/ce3724f547939958354af521563fa8f53722bba2_bm_float_unboxed.txt create mode 100644 tier2_results/pylbbv/ce3724f547939958354af521563fa8f53722bba2_bm_nbody.txt diff --git a/tier2_results/pylbbv/ce3724f547939958354af521563fa8f53722bba2_bm_float_unboxed.txt b/tier2_results/pylbbv/ce3724f547939958354af521563fa8f53722bba2_bm_float_unboxed.txt new file mode 100644 index 00000000000000..7be97a697c0e16 --- /dev/null +++ b/tier2_results/pylbbv/ce3724f547939958354af521563fa8f53722bba2_bm_float_unboxed.txt @@ -0,0 +1,2 @@ +Starting benchmark... +Time taken is 29.23269283899981 s diff --git a/tier2_results/pylbbv/ce3724f547939958354af521563fa8f53722bba2_bm_nbody.txt b/tier2_results/pylbbv/ce3724f547939958354af521563fa8f53722bba2_bm_nbody.txt new file mode 100644 index 00000000000000..7600d9f45e9409 --- /dev/null +++ b/tier2_results/pylbbv/ce3724f547939958354af521563fa8f53722bba2_bm_nbody.txt @@ -0,0 +1,2 @@ +Starting benchmark... +Time taken is 31.180609329999697 s From 6ee3fdb95310319bb055f8c0de898629aff73786 Mon Sep 17 00:00:00 2001 From: kenjin-work Date: Sun, 16 Apr 2023 00:43:17 +0800 Subject: [PATCH 272/280] Update bm_float_unboxed.py --- bm_float_unboxed.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/bm_float_unboxed.py b/bm_float_unboxed.py index 22f586eca2983a..604cfb543b5a5a 100644 --- a/bm_float_unboxed.py +++ b/bm_float_unboxed.py @@ -1,17 +1,18 @@ import time -def f(a, b): - for _ in range(10_000_000): - return a + b + a * a + b - a - b +def f(): + a = 1.0 + b = 2.0 + return a + b + a * a + b - a - b # Warmup -f(1.0, 2.0) -f(1.0, 2.0) +f() +f() # Running the actual benchmark print("Starting benchmark...") start = time.perf_counter() for _ in range(100_000_000): - f(1.0, 2.0) -print("Time taken is", time.perf_counter() - start, "s") + f() +print("Time taken is", time.perf_counter() - start, "s") \ No newline at end of file From 19e6fe237454730984a14c852477339fff923d19 Mon Sep 17 00:00:00 2001 From: kenjin-work Date: Sun, 16 Apr 2023 00:52:14 +0800 Subject: [PATCH 273/280] Remove old benchmarks --- ...e3724f547939958354af521563fa8f53722bba2_bm_float_unboxed.txt | 2 -- .../ce3724f547939958354af521563fa8f53722bba2_bm_nbody.txt | 2 -- 2 files changed, 4 deletions(-) delete mode 100644 tier2_results/pylbbv/ce3724f547939958354af521563fa8f53722bba2_bm_float_unboxed.txt delete mode 100644 tier2_results/pylbbv/ce3724f547939958354af521563fa8f53722bba2_bm_nbody.txt diff --git a/tier2_results/pylbbv/ce3724f547939958354af521563fa8f53722bba2_bm_float_unboxed.txt b/tier2_results/pylbbv/ce3724f547939958354af521563fa8f53722bba2_bm_float_unboxed.txt deleted file mode 100644 index 7be97a697c0e16..00000000000000 --- a/tier2_results/pylbbv/ce3724f547939958354af521563fa8f53722bba2_bm_float_unboxed.txt +++ /dev/null @@ -1,2 +0,0 @@ -Starting benchmark... -Time taken is 29.23269283899981 s diff --git a/tier2_results/pylbbv/ce3724f547939958354af521563fa8f53722bba2_bm_nbody.txt b/tier2_results/pylbbv/ce3724f547939958354af521563fa8f53722bba2_bm_nbody.txt deleted file mode 100644 index 7600d9f45e9409..00000000000000 --- a/tier2_results/pylbbv/ce3724f547939958354af521563fa8f53722bba2_bm_nbody.txt +++ /dev/null @@ -1,2 +0,0 @@ -Starting benchmark... -Time taken is 31.180609329999697 s From d5f2da4be505c0146b64dc3d490e5784a14029c7 Mon Sep 17 00:00:00 2001 From: kenjin-work Date: Sun, 16 Apr 2023 00:58:03 +0800 Subject: [PATCH 274/280] Add benchmark results for cpython and pylbbv --- ...703def37e4fa7d25c3d23756de8f527daa4e165_bm_float_unboxed.txt | 2 ++ .../7703def37e4fa7d25c3d23756de8f527daa4e165_bm_nbody.txt | 2 ++ ...9e6fe237454730984a14c852477339fff923d19_bm_float_unboxed.txt | 2 ++ .../19e6fe237454730984a14c852477339fff923d19_bm_nbody.txt | 2 ++ 4 files changed, 8 insertions(+) create mode 100644 tier2_results/cpython/7703def37e4fa7d25c3d23756de8f527daa4e165_bm_float_unboxed.txt create mode 100644 tier2_results/cpython/7703def37e4fa7d25c3d23756de8f527daa4e165_bm_nbody.txt create mode 100644 tier2_results/pylbbv/19e6fe237454730984a14c852477339fff923d19_bm_float_unboxed.txt create mode 100644 tier2_results/pylbbv/19e6fe237454730984a14c852477339fff923d19_bm_nbody.txt diff --git a/tier2_results/cpython/7703def37e4fa7d25c3d23756de8f527daa4e165_bm_float_unboxed.txt b/tier2_results/cpython/7703def37e4fa7d25c3d23756de8f527daa4e165_bm_float_unboxed.txt new file mode 100644 index 00000000000000..13c24db7b66454 --- /dev/null +++ b/tier2_results/cpython/7703def37e4fa7d25c3d23756de8f527daa4e165_bm_float_unboxed.txt @@ -0,0 +1,2 @@ +Starting benchmark... +Time taken is 14.229669059000116 s diff --git a/tier2_results/cpython/7703def37e4fa7d25c3d23756de8f527daa4e165_bm_nbody.txt b/tier2_results/cpython/7703def37e4fa7d25c3d23756de8f527daa4e165_bm_nbody.txt new file mode 100644 index 00000000000000..24d83b8ce7b5e5 --- /dev/null +++ b/tier2_results/cpython/7703def37e4fa7d25c3d23756de8f527daa4e165_bm_nbody.txt @@ -0,0 +1,2 @@ +Starting benchmark... +Time taken is 30.047266386000047 s diff --git a/tier2_results/pylbbv/19e6fe237454730984a14c852477339fff923d19_bm_float_unboxed.txt b/tier2_results/pylbbv/19e6fe237454730984a14c852477339fff923d19_bm_float_unboxed.txt new file mode 100644 index 00000000000000..ffb5ec08375952 --- /dev/null +++ b/tier2_results/pylbbv/19e6fe237454730984a14c852477339fff923d19_bm_float_unboxed.txt @@ -0,0 +1,2 @@ +Starting benchmark... +Time taken is 13.191304593000496 s diff --git a/tier2_results/pylbbv/19e6fe237454730984a14c852477339fff923d19_bm_nbody.txt b/tier2_results/pylbbv/19e6fe237454730984a14c852477339fff923d19_bm_nbody.txt new file mode 100644 index 00000000000000..fcca05abcdc198 --- /dev/null +++ b/tier2_results/pylbbv/19e6fe237454730984a14c852477339fff923d19_bm_nbody.txt @@ -0,0 +1,2 @@ +Starting benchmark... +Time taken is 30.5506420720003 s From 3d44cb4dcbda80c750e292a9598cfddb41a92aff Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sun, 16 Apr 2023 15:04:02 +0800 Subject: [PATCH 275/280] Test literally only float ops in bm_float_unboxed --- bm_float_unboxed.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/bm_float_unboxed.py b/bm_float_unboxed.py index 604cfb543b5a5a..0c79fcd6311c8e 100644 --- a/bm_float_unboxed.py +++ b/bm_float_unboxed.py @@ -1,18 +1,17 @@ import time -def f(): - a = 1.0 - b = 2.0 - return a + b + a * a + b - a - b +def f(a, b, loops=200_000_000): + z = a + b + for _ in range(loops): + z + z + z + z + z + z + z + z + z + z + z + z + z + z + z + z # Warmup -f() -f() +f(1.0 , 2.0, 64) +f(1.0 , 2.0, 64) # Running the actual benchmark print("Starting benchmark...") start = time.perf_counter() -for _ in range(100_000_000): - f() +f(1.0 , 2.0) print("Time taken is", time.perf_counter() - start, "s") \ No newline at end of file From 0e81dc427532d0b14020d0565187824e8ef34b95 Mon Sep 17 00:00:00 2001 From: kenjin-work Date: Sun, 16 Apr 2023 15:23:40 +0800 Subject: [PATCH 276/280] New bm_nbody_float results --- ...703def37e4fa7d25c3d23756de8f527daa4e165_bm_float_unboxed.txt | 2 +- .../7703def37e4fa7d25c3d23756de8f527daa4e165_bm_nbody.txt | 2 +- ...9e6fe237454730984a14c852477339fff923d19_bm_float_unboxed.txt | 2 -- .../19e6fe237454730984a14c852477339fff923d19_bm_nbody.txt | 2 -- ...d44cb4dcbda80c750e292a9598cfddb41a92aff_bm_float_unboxed.txt | 2 ++ .../3d44cb4dcbda80c750e292a9598cfddb41a92aff_bm_nbody.txt | 2 ++ 6 files changed, 6 insertions(+), 6 deletions(-) delete mode 100644 tier2_results/pylbbv/19e6fe237454730984a14c852477339fff923d19_bm_float_unboxed.txt delete mode 100644 tier2_results/pylbbv/19e6fe237454730984a14c852477339fff923d19_bm_nbody.txt create mode 100644 tier2_results/pylbbv/3d44cb4dcbda80c750e292a9598cfddb41a92aff_bm_float_unboxed.txt create mode 100644 tier2_results/pylbbv/3d44cb4dcbda80c750e292a9598cfddb41a92aff_bm_nbody.txt diff --git a/tier2_results/cpython/7703def37e4fa7d25c3d23756de8f527daa4e165_bm_float_unboxed.txt b/tier2_results/cpython/7703def37e4fa7d25c3d23756de8f527daa4e165_bm_float_unboxed.txt index 13c24db7b66454..6d7260a34045bd 100644 --- a/tier2_results/cpython/7703def37e4fa7d25c3d23756de8f527daa4e165_bm_float_unboxed.txt +++ b/tier2_results/cpython/7703def37e4fa7d25c3d23756de8f527daa4e165_bm_float_unboxed.txt @@ -1,2 +1,2 @@ Starting benchmark... -Time taken is 14.229669059000116 s +Time taken is 21.911415401999875 s diff --git a/tier2_results/cpython/7703def37e4fa7d25c3d23756de8f527daa4e165_bm_nbody.txt b/tier2_results/cpython/7703def37e4fa7d25c3d23756de8f527daa4e165_bm_nbody.txt index 24d83b8ce7b5e5..20a86e19604e7b 100644 --- a/tier2_results/cpython/7703def37e4fa7d25c3d23756de8f527daa4e165_bm_nbody.txt +++ b/tier2_results/cpython/7703def37e4fa7d25c3d23756de8f527daa4e165_bm_nbody.txt @@ -1,2 +1,2 @@ Starting benchmark... -Time taken is 30.047266386000047 s +Time taken is 30.735117989000173 s diff --git a/tier2_results/pylbbv/19e6fe237454730984a14c852477339fff923d19_bm_float_unboxed.txt b/tier2_results/pylbbv/19e6fe237454730984a14c852477339fff923d19_bm_float_unboxed.txt deleted file mode 100644 index ffb5ec08375952..00000000000000 --- a/tier2_results/pylbbv/19e6fe237454730984a14c852477339fff923d19_bm_float_unboxed.txt +++ /dev/null @@ -1,2 +0,0 @@ -Starting benchmark... -Time taken is 13.191304593000496 s diff --git a/tier2_results/pylbbv/19e6fe237454730984a14c852477339fff923d19_bm_nbody.txt b/tier2_results/pylbbv/19e6fe237454730984a14c852477339fff923d19_bm_nbody.txt deleted file mode 100644 index fcca05abcdc198..00000000000000 --- a/tier2_results/pylbbv/19e6fe237454730984a14c852477339fff923d19_bm_nbody.txt +++ /dev/null @@ -1,2 +0,0 @@ -Starting benchmark... -Time taken is 30.5506420720003 s diff --git a/tier2_results/pylbbv/3d44cb4dcbda80c750e292a9598cfddb41a92aff_bm_float_unboxed.txt b/tier2_results/pylbbv/3d44cb4dcbda80c750e292a9598cfddb41a92aff_bm_float_unboxed.txt new file mode 100644 index 00000000000000..09c519cefe8e5e --- /dev/null +++ b/tier2_results/pylbbv/3d44cb4dcbda80c750e292a9598cfddb41a92aff_bm_float_unboxed.txt @@ -0,0 +1,2 @@ +Starting benchmark... +Time taken is 13.180637167999976 s diff --git a/tier2_results/pylbbv/3d44cb4dcbda80c750e292a9598cfddb41a92aff_bm_nbody.txt b/tier2_results/pylbbv/3d44cb4dcbda80c750e292a9598cfddb41a92aff_bm_nbody.txt new file mode 100644 index 00000000000000..6192c2d72646ee --- /dev/null +++ b/tier2_results/pylbbv/3d44cb4dcbda80c750e292a9598cfddb41a92aff_bm_nbody.txt @@ -0,0 +1,2 @@ +Starting benchmark... +Time taken is 30.82709504000013 s From 3a4c75db2d0fa6a7fcf322116361c0141dbf6a1a Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sun, 16 Apr 2023 16:55:06 +0800 Subject: [PATCH 277/280] Add tests for BB_TEST_ITER specialisation --- tier2_test.py | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tier2_test.py b/tier2_test.py index eb372b87b6ac8a..50de7692fcbf70 100644 --- a/tier2_test.py +++ b/tier2_test.py @@ -1,5 +1,7 @@ import dis +print("Begin tests...") + ######### # Utils # ######### @@ -373,3 +375,49 @@ def test_container(l): ] for x,y in zip(insts, expected): assert x.opname == y + +#################################################### +# Tests for: Tier 2 BB_TEST_ITER specialisation # +#################################################### + +lst = [1, 2, 3] +def test_iter_list(a): + for i in lst: + a = i + a + return a + +# Trigger only one JUMP_BACKWARD_QUICK +# i.e., perfect specialisation the first time +trigger_tier2(test_iter_list, (0,)) + +# Make sure it looped 64 times +assert test_iter_list(0) == 6 + +# Make sure it jumped to the correct spot +insts = dis.get_instructions(test_iter_list, tier2=True) +backwards_jump = next(x for x in insts if x.opname == "JUMP_BACKWARD_QUICK") +instidx, jmp_target = next((i,x) for i,x in enumerate(insts) if x.offset == backwards_jump.argval) +assert jmp_target.opname == "NOP" # Space for an EXTENDED_ARG +assert insts[instidx + 1].opname == "BB_TEST_ITER_LIST" # The loop predicate + + +def test_iter_tuple(a): + for i in (1, 2, 3): + a = i + a + return a + +# Trigger only one JUMP_BACKWARD_QUICK +# i.e., perfect specialisation the first time +trigger_tier2(test_iter_tuple, (0,)) + +# Make sure it looped 64 times +assert test_iter_tuple(0) == 6 + +# Make sure it jumped to the correct spot +insts = dis.get_instructions(test_iter_tuple, tier2=True) +backwards_jump = next(x for x in insts if x.opname == "JUMP_BACKWARD_QUICK") +instidx, jmp_target = next((i,x) for i,x in enumerate(insts) if x.offset == backwards_jump.argval) +assert jmp_target.opname == "NOP" # Space for an EXTENDED_ARG +assert insts[instidx + 1].opname == "BB_TEST_ITER_TUPLE" # The loop predicate + +print("Tests completed") \ No newline at end of file From ea992b35bef5c688c6c8851a22d132f0f6384739 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sun, 16 Apr 2023 19:56:42 +0800 Subject: [PATCH 278/280] Create CPython_Tier_2_LBBV_Report_For_Repo.pdf --- .../CPython_Tier_2_LBBV_Report_For_Repo.pdf | Bin 0 -> 2634616 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 report/CPython_Tier_2_LBBV_Report_For_Repo.pdf diff --git a/report/CPython_Tier_2_LBBV_Report_For_Repo.pdf b/report/CPython_Tier_2_LBBV_Report_For_Repo.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2a0ee715f55a68105ba13957cec83001c22c1ced GIT binary patch literal 2634616 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
06@`u!G2gq%1qZk#{I};jS=`KR1GY3rYDFSV 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
^hh}tfJA6_=o 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

aSFHF|b8)P@c)xkOf4=!~yZF_Qwf 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

}7iV(Dmt_HvZ5%ggeZ=n9E*Cj=EF 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

8rOL5vkFKE_LvT)nP`s; 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 z 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

fXeb=D>c3V;e6U}vU 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�bn@jT@4CU@=8HO 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�?(cJTy=cj}jcOVuv9 zR$?#-#{`T^S|2JmB`~oPeCIZl&T$V zVGiKoI=j2sj)y=B9+bNloaWF(ONol!mXe2mE+D`{*ue19c!eXa>3N7da==;MZXn{R zl?&M;p=G7_79wqWloBewI+l($r-JmKG%ZQm#o)!r#W}thqQQ(gXLO1HKo~)o+2aLt ze&MSQkA^U&t9T==8CbHCa0U(T!gg0C+dbK!`DovEP`*;%XAgO&bXS7MG+N9(a3#Au zXHs)CmuQGZj1+$BU z1XG(-Q70jlGndm1;a!^v0v)c^;nGqd$dg;jMqMASh}4RO6@{}52T~3sjKAB}I%-Bn zu?giy>%%+Y{tt7@UB1s({I9i6EPzhkdcwpztyJf>KKRbJ=3Nm0L{KA?3VPb(#xXPn zHj1G$Bk3(A#%RTky~C)qTS+JRq^Lm+WRSuUN?h`i`I>(t*)7Ubdi3#kh(nStcGEI5 zttYzRW5QypM1&fs&=VftyxYzWlQKsnO9u`>I84Re}G=?5uip;wJpYxcE4_7vDmA&268X2&m$ zMRT=kI^}iuu7#&Nv~BdaHA+XL+09l~T0l-L@G)7y=m|5$`PCaH-34gQDVjI+F1x;` z)%P?m5D{sT)}KTK&vGaKuSMh#sEKahU$6+!ht4g*BGiYfig*Q3GLMK#1eJo77d0(0 zr|@?Hk($x6RP$vPq&DhAvpB)pl(wf80Hp#FDHn7`$PG#=-YF?l?B;gJ8vg3G)gEJ4 zV86lnK4z^&6VqHXXC;PnyHPd(iXzTLFC`_?&&*MUuC~+48YFiObCnG*7ocKCnWn}D z*UOd{n-UA}za(1p@niBLLD7n|No=bAw37X>M~A0%Z>UVxEv~vgGKc`wb&ISmU5ost z^VHWfq41NN0}kb%*HynNO%qZZt;KV011>u`~L8J9Y*ndP=1 zN@v28)7v~I@5`@DlpBD0?oAOO3X76#T>ePrTNl!>d}2~1D|(J4IYUIfcop#x#?6a7 zVv(6za4yU$a#j>tTGJw!YV1oH?)G)TbgnGBy%E?GX4Cgq3#S)0oB5my9f2r41|F}+ zhXI0@Xo*e%>swqaHMsC~-57*H-*Yv6m$?1Z zN?*QxCzW`K-eUPw0Ri7ajV-WAL#lLzIm~VvbuU=ZW*QZtBhR~vJycy?wy0&Z16BDQ ziwmwCy$%|LGri;j-)zE!p7K++L!dlM@?4}{`emi%;;5_uoHv*2YeukGvLajOkur@^!2_#h;EWnM3qt6nugvwBs;z$Ac}QU0H~DK+ejz0 z)0$w;Qs`gWWL3>o8qpi&&=jFRoz&RwA4yf6ViPd~ZPiS*q*TYt=9w$z%_6_rdWV*x zM%I^<&<2ovtYw6C#hnSIrG5-Z!#kB=S#GyXv~SKZg1mmfF%Sr5t)615eXP_jLnm}k z3N{S0+i;#Qi&J*vbWiSz?|#^$DGTp?zR7?qy1Smx=F&zift+%uzc?<=sg%tRW)Lp% zZY~XZ+;Zvi!l355E?N;^HwNF6nA>)Px-iw z*$j`t&QN#vThof0I7lSmvd<-Rop3V|Wo#zjXVwrp+KD#RqIf2C&9!8Asz~>X+IRcu zTbAGX`M*aR3TkRkSJupmjf-I}%wcVDd$+|%-f__^ucouCvXu9Y97q*?JzjV*v0Cm)ZnYq`UR~8+VYLbMd5wtb6&O}?50cWaAvX^jr9@Zyji2P(t z>K(o<)R5VmSXI7LJX-iI+a7X4*;k7cOc)aY*}WwJdi7-?&t>cMr;<>~<&O!X-^vBG zhbI};ySbr~ZUlsdfd(a`Sl(zDcn*~+4$l;kYwG^lj0UFkA!0B9E>x2ZnZWo z2ge;i5(f{YV4p+iPx`+qMO9|@cy=(^`^Vjv%Ag>`)m42)U1OPJO6;@#p~!NkPR*k#g}p97MV@n5{tzC? zuL`)JXJ$(`tGr82mTgpzdhl+qe`;s-?AN1H=I)JtEm^uGXD7o15(tnBiPYb zlnxj2Nm8Q^i6KMQkkpveFNK%;7_WfzTba1LJ^~UJNh0NXE?)&sOxs-;1+hbliTTjl zLmfI%4r@bbCKcXdV9gi|CANRVomV2g1p0rl&vo$c4ZW`+Jo8zK%3hdHXGN7Qm-RPE zEH~ZDkjjvyCrE5~t1YMY_fg=4%M?qp0DuxuTv}Dk=_IoY@-~s}Lt0l*IDY~w&|9fRZ@&u0S$aEW5S5xqQ z9`^^N;&Z@Xo3eUubcgZi3A!ndQ=n%*E>c=Cu@-b|5Zd1;ZFEvtQ(Z+glz-xfLssyq z14V>^Aoc~=^qe|5sZ(AJE~Yy7upbj+XYm?~WomsbI(3~p6gw+^R_8AI&=$u~au-n8 zi9=k+y~rIurq3!D_En;a`$1)E2I;f5T*Zv&$uStU9o(}V&F$Jj3_Bi8b`>l^zCrS1?Bjx-648lV z+2Gb&y$o+nivm-kth2L(2%^(uW~^vuOIvgC%;Vy3Mn@Q)5FhLSMPcV|yJ*!gjNrUn z38^?WKD4Mn!Zv5ObI%%u|D%P>0a6rH7arSSg`MJh);D!FulyRO%tWY8nr$4Z3Pyq< z?${@7^#3B+=hFNa__GJ$2@)IJZ2$!+5s{Mv*TSVDOxVB8}N=a#Lmx(CS9T`L&x3hYPK}p z_idKB=Snr*2}Z-h`3CYS?^i(}S654obG@OU9R7Pj;S(Xd$tIvmU%!4`xB#G$g8+cp zbJ+TOvf-N#7V@`@3qWriMq`Sr%ZsVFzR^8OIW~To5#cap`yAAkW15 zUp+Psv!}-mIhxuY;}x<3S)JRm9qi^H1-VfS#42pszpu>0)2@{Z9L3_qbtNpYgU{`- zPp0dJkg;!#BIOMwsiwmmw2w0Y3AsKMGw&hM#%V3xfr-JBf+Z}bEc1o>K&)Bc2V6>Z z@v$q?+U<@vGzg!=Gm@3$HC-OOAmqUYtz7Hx_iD7#+5_&DIqMyg`c%@hv&l}P*`hOx zFo666G3)C0x?5!PH!3Et1z`MV&$sUeu2^ zygX#?I)yR>*zxrayv^3o-D)})kAYo1VfH<_E4lu49~uwpB=)}se%(u#)1gU_2yeyGU?NBL(74aQb1#>rA>NR+GSk>=Ya~EzXSBg>}30B;6fCp5l*^>+V zfYQyGE1gKG11zZuyeY_R!c-K;z#B?@J*Xc_<#g9`X>KA!RaQi7%DH$9!CD1$!JQIb zIKLL-_25>WKJOkBvuLZR8ogiz`~<*l0r0)mj^E(8w_g-hFoeA+wf0zf=3z7_3|`b+ zYem|sU1<-S)w}rBA6U>pA4!rfoudCoZ;DNI!Yu^i#vv83<`=>nk ztQ#55CfTvuk?Xtxs9Ij&93Gjc{9ZlY-g~<0lAbA0l=i$<@7~-(6FxS3f-_mk#b=!U z*rFJzDn>dr?FfRv?o)c_Byzis>>y zi7aYPedv@S>-6p4>OsE&aMfPbZJN)zB`);Vpo+Rut|~_c6nUy#ec3bQUQgr{xo>E*cft z2rqwTf)d7|5|3$fUh}w~+FKBNJ}7d5?<}-&e!3e6rEx>{rcZ;o1tZ8~ z1_a+9yX?>~31*bAzvc7*cyeo4z@Qx{9^snJtkCHLFnQcbcR7U>htxQQwVUBW^j#Uu z9cnA~wjX5=fT3r@X*zUiUN(`=dc6{+t_v6yfFHq;-39w*yC5xuV1txZ8jgp+S_0O- z+z#(eQjBQLnp)Av)oY~AA6lr@TYR?F*EtL!c@{iE{CT$xtevS&T5aB z$xe~gj$Zx>^fJ)czv^YUV0jX91;tM&}vSqM<2r(`) zRl8+yJ`zgPAX9VIsdWP5vqD1}2a_02~;6<5Mkirkc#8KKqv6!xPbGilxVQ4S$e{9T*^9&zq+d*|rn zENHT)+I)=ZOdn7d<}*|dO^zo$Zjes%0PfX*=r1$`EjPv)HtSzK>8yq;_wG3ipxHgA z2fn-BU+K{cZhsT5yh%nG5w1W#bF~U|hG}Wl4xPGg%86*`Y{rY2sEi}aOjJw_6*oGc zvOc5flo+C$qmrR&pDXa#G!pKi@($1DH!gYH5xoSXU50Gh zC9ugUyUn=ux$=s=2)?n;J$0_M)6;qUEL4*81VMA+%{X46?Dcip`szdv%tM^!R6Wg5 z-E?ChagB}?f1S6Txfq%$Xz4y@lq9FtQPtNwVy|_DAq8Wz-yWV2Evy8pOiUDTj=3}I z`r;3qT$i@qk+ESx{cUQ=OHz`byuQMd7J-JB-)Vg2SKWz{+WY#x0kNKfL9%7_)1!LlWhfC8t&)k&+{;l-HxbwZn2xe*rUj{!k}! zmq10i&TzKagg4S!haD21?}ja2n&qK$S}0A zPE118uHnc9&YdE^oW_l9kXicfpnoa`h2X#x z6X;H!JZUxDyjzj-{0$Z_{$I|w=GPUXey*@BhYXEcW>)- z-cF<&7aLo-X8rSVT74d6|Lt+wd8Q^AHd?vHK3KHqkJEdSolS80PxQUF17pfaOM7C) z#C9KdCz}BKZ;#6}ZEgUn$hiI}8t(Yxd3$2-Z()@G1{sarxt-~Ut{^Lnb;ch^!5+YU zfk5C$o?c!QXb61wfouI9IsfJSu8kJ-8iWf%l_xj7&MSuWm6z;lh3wWfzsUchW{%!U ziHnN^ipED~hs=asGCwgXG@O_D>kelyy!=;=0nGgp0o(|>aN|FNxeqkyPiz~#$_j{hYJb|JuK14^>{+OdM7A}|MYKZqRd z$x;{a5?Gs~Y2Y35pim2pos<##t}EI>MaLf?$aCZ{CI(EBH^Gq`8-N;fTv*(F5qB=( z0Y`&?itNvq?8!0Na^OA83A&Vatcwij9}3U{1yVOg>B%%ZH}IWfeaJUReD~+ib&)`u zP@*b;Tk7?Ovz-N50tA!k5yXt+Iv1>x* zlR?$Aj;*cjBw1_UH8ixDIZnn=cRrskp!pnuxi{wc@f$FvLbcFv>bF3^IG`V$Jo6ho z(nkZl=bYru(ZziiqyV#Bm3!?5A^*?Yu*UrV-$u0KFVt{%FMItz*!RsFTJ-X-1epfh zjQ;mD`S|C}WDNe#%`E(HG-=UH?(w|b3?^D^MemP@^I207*Co$;Bheo6iZ?Qzl#3`U2#(D9pBmu=XrW_ZWQ6XB(dz2z)8Wxw-ss!m4bDWX)?cJ`Pi*|V zKePFt6yC2|-WJ8In$i^^VkgiG;nvB&xc+~$ws4|47|MCbE9V54idNd~P6k?$5>U+4BfY-T8k$?$66~ z`oEUB`?yb})}ctmO^0&_%SmMa{KEK8-RCC`Edr;wtn?j~9~v ze1CHXtA1bp~lv3m8V zuOWw&>f6;bVC7^!{JsJ5PZ^#8@~AL@b7-0yApQB((X$PMv7Y(Y-ycWQ`1$!Eh|AG{ zlB#NIJZ1ko)9!Ngo+rt&LAQ z9&k`rR`w|%1{_|*@UMl5za7R;efGkI3y)AEpPuf!_pf=mN(K<&(xu-AVPql%8~$5a zsM14K^1pij{yh-JeU!8pEB-ANy-FNC@2IOEE5@9*hr`qUJr~V5dK#Soqp!gkQqrEf zEC|;)uRC#FQYGCzU+rV=7%c`N61{H1vzetp_k69 z!qU6Hj@NfMOLu8YCw0^HBrC1B)0GYp5fO0+q~t!gi-QV1P|U)%n2zBqJvtI?>g~FS zlDrG3f>}2^2OT?W<+OE@kRjF*C2}#-?u%^8c2^v({P?&OfPl1<;IkwKuwAUWbaCf^em#!b7TUcrrGojzZzO&UtaQ z3hDQ`k9}zwO$g1c*f5+jkz3-kdqc?KUrw82kQ%Z~op$enjNvzeRct&g+DH7A@Xv0V zdYz37LYfxSzOq-+S!s=6sPaXKrK3Kn2@mr6FTJ=~;&VNX_uDaAf1?rIeYTe`2zuWv z>+ES}Kl9SHau74s2QL^o42@qPYISc+re~#s`loqya~&3=IUAJ7OjOYKT-TMnpy2Cp=<=nL!;M8S#7Nf6Cm_R5aMW4FaB+_nqJJ0@7!SW z`r=U8D6SpH8LhcYTnkmRL1(Xh;R#Ez87Hhyy`@6g=t*?1w^d|&GDMBkYKGachajn)AJCQ*k%f!p z=1EeVg0?r-%HLyG&0J&Y@i&s`dF4|I?7T)}kJ{hTRJB2iBwqD_!iEVsOZ4#S=WvP8 z%-M}xsBTY5D_3gAhnu1oG|Ger%lj_anJsoCOghCfJAIQk^%~8+-b>xP_l3VIvs`V4 z(FF8s2T^yRm%)Bzh*_ij+eJ9hPK@{4=Tkvdc0G|#Bi1d#L{9bF)+0q^o`=j4CUNC8 z9jq8T&B?pNO$D8J6?gTJY!PX!r(WqCqm65|D_d`RhHUmKG##$96k)k-Lp53+5@yt& z<8{Yo!_mMs*}v?pjbU!wt2OS#+LO!*TfKGmVdc`{?ryc$_qb)S2dCZ~U)W#JYPiw2^`P)`?H;R`f8ukTZTeMB za+TEBopc?bv3!Hk6;P>pcQ2|$s!J3$b-|Tu-W-xHa>C0tQ(zN)z$)CEUyHz8=uA@_Y8_hG%vWKmBYJ@U|!r|f<_j)!CX ze0bLy8j*;ETbYXyat~1>^?}>Bl^E{b5&5@h`GcfphLO*;gx%FR-8!hRY@>qalRf8~t?m*|awx|NJ z1WdL-i<{2S@D23^*>2TF zgnoD47%y|k0(kXOAHLxQsv6^At^2y+aWl79$q}Tr#0QP00_HEt;%MVmYVedt%}6_X zo0n7ZYf$eK=Wj|6jXMG{@Q?#SAZ;Iq0dbbsOj`Uz;HpC~j^X+JQp9A}%{R$H+vtZ` z*YKP^=kl4GB$~jv!>VsZe=NfAOY$=-8{EOhfNvUg|6_i?_$O=q_MwQkAe!dE7n@rZ zj;ZZatJ+15&_d=f@_iAuXUCoz4zs?R3*U#PX?)m9rA_lf{~q742-a(2aV%Q#qa62O zt+3mwrf8L3eB|m=j-9=_bCk9{C7G2{_~UgPK5Huui}pHIPOfTfA+HKb0Vs8!0K%$JC^_t%38v$ zP)5$iZrU@BvY&clj@0h_PtJ*u-fVvDQNRQcsfGDo13@#)+bVlpo-aS+d$6Gp9*x^Y zfUM2t1x8-9=8%_~1CLsQWj!4|Gnq2?*4Z+qYr;L4arVGqA zXssYGj}%?b$c(9qJMS$mzIQBIGn>lAFy2c7Sv7M6D5khXnm`j}Gl-JEq~xYI*Ff}d zDs%%hWXGwEEToZSAw78OarDL~=?Exh?%?=6Som8@O)d(oR{+r01bKQJo?1%N46TKr zc^gR68&o*~a~`WQo#;EIxC5uQ ze*1{nnu=ru_!iuchmOJA20~rIt-{gRe8LE)7{i+$oG6!b{^*I2M0Ey_0zSaZ+R5| zl7`klY54Blu@^VHxKzPD2AeGIqSoYr7~MrAs$mD>wG;B0M};C5N;5oeT5m&HR z3T#oBNE3n@wXl#%b9ve*Kd|+SllXz&%GX;cviCZPrYXbA1wUv0vV3Lrb*Wvn#xa(1 zJA#$kZAVMOM9Ty_aadz29NgJc|0Ye6N$tams-t|75^BdS+_AUxcwkj7y4nv@14|^D9Tuemk7M9(VjeGECte6`!hnD1L1|G6?35 zk2?<<6f}lfL9XZpy7=fuK)%Ei?k=o+^1KP6+6Mn&iLFrIJNRV8W_QihYKne=2;LV} zrCpb51mhw;0zTRL2;qz(G&v2!-?wzp)-pgsexJW*MGHN>Wd`eEmAxBdEh;=~SH#oB z?F_f`j^>}bPNpWi`nHqGBy1DMazN~;?)6+uHa^kHw&0^>u|6wi%DgPl3gWhfQarf; z_m5pi;uP|kfBSZ_JO=IG=r4iJeP8fM)V>8Y)VWk;L6&h*R&NKAJ_%QsiZ0 zEM9lJlzk{8Ycoq1DAJdq*XJhhb3UwmSiS1Cjc72-Vp8>3@zz&EwsPJ0XR6ToPhwO+ z*)8h~ZqI#K*=ZmMIQJnwM9FSzVd8xEbE(%14QNmasxPOgflzjH`26womV=b#F@!D~ z@k+KaFfdPEXyXaFLo0llSOI3+)$$!LAP2iG}F?t+@J|rrXOi+QaG&z5eS}LuWO& zJ^TI-Wp4rwh2Fl8pK~fLl1ivXq%7Hs7`u>!BqjTj>^ouXrV>KPo@^13ecuLivhT8I z8KOa!LH1?veWEsJ=b-vt4n8TKA&f~@B6u*&nSyHOgzFp>*vXK;Uu+= zmnmsx$T_!(=kw80%uOh-(vw|c4>F+8+#tqq*gxULmUFwvU9`Tp{?;>J(B=gdIL~4k zxoPX_;zKP|a>f7zp0de%pxfqAZxD=gfiZGVXFwdTq_(L=ZC19$ z)wH8(j`g=bo`~M|OQfYkS>1^_7o)~cAu>e4G08#;v90)p?#U-$LOvFKS+*?7E$}b+ ze+&`&;moIO3qbKuPD83KivWPsv*huJXfD4YDbEkAm9dw1tv9HSG>jWu_I%*_`J?Xb zQoGc5(ob}xt*B7kl5((ZlseJZ_IVfO<@U+II^bI=g#@l2Nb51yg4TuQ^$`Tu7d6aG zv=k{5@@`^&4fzSRepw1Ne;yyL(~%P3^fuH+xtHZo+mB7+)E@h4uHN#f#*g@(B&Vpy zk0IslQCZnEU8LY9vkxY)HjG5&2qrYS?ir>~+Gl<0c`U<oo#nN$nIvqY?tPh|YG=pHt!MRS zjJPtsYOlzaGr2qTkEnEZmJkCfo29-H3Lg=4ge4AY+76IG(p9JE0Ldrfp1%IC@Lg^a z?qYa&I0%JDbaa}Fk^M3T7|BIf_e0y}(u3{`i#8Efn`wEti_XVw(nK=$7I({WmVI}j zBUX=BoHB2`I6KSkO_htqUEFZ@Y>F$)@@xx<+N~>k7k1}M>=?==5`X^SV<57l?aXQB zNJCFYT++G0Ve3-+kC%Ij76#v_dJ?nyb8YO6u^po-oo>#uzY@rF_-aoR$ZoQbT4#L9 z@>*_d^vBA@Zu*5lqx-Ae*UD#ZUFVk1=PfpWY0+7=Z6KiZP+JzqH6y%XEWQs6e;h%( z&Y`*b4V<&oF%$%!_vq3~Wv!qpf$o_e311HRzno7R?$Oy>mX?-ZQPT4A{?xw3VIwH7 zuj@P$tiF*pZ(P%iZLU=kd{PqDzqbcvgz7mD*I)0?97<}sN%`}~1s7Ni^IV(SRH@7``bD!P~8 zv-{y%(;@$;oWl_w$D;n{gZft>MOq#-K@dpCQj#x`|Ne&Oa-~}xPCh835_hqbRuuYo zQ%+@(>+j`FH;)nsWct?C)LlLqfDF=4WM$xTSC;v9hDLQl^&AyZ8B0R9%k}yYT^i>Z z-h^nY)CI3wYI)zmjDgTKvZ}pE;lI4rr+!Tu>Lc*>DD<3PNd8Xs?S|w~=^?04;qP!y zZJQL_ zT??QA*O6;}mOyQk98!(Flrco%BF7&}`AfjaN1=mI#Y~YGnf@z1G}D5lhawON7|Mi( zKJM%!jJ*ILt|@jAyJ-k)LH-0N3|_W5rCOfw<%t5C!qKK*;Rp9zisg1abFf_>XG$UE zr1ZX}5!3mw<<@m{hK587qtDZX!8ZaDMWst>Oa*6TQD?psAB#rSY+`lWw#wPRGX$W; zasG-ItSpcY!{;N>U;RLJYOnojxzSL>Kp?v!2}S%R39Iuv_69b_MnZX1-Suz%@T2AZ z`h40BhdC$V=ydum?K-ivxdL?j5h{YuJ7i2Le}+KnL*w7t`gDN-g^9uQzR1USA<_C&<{q8^k+u(fD-e-$kY; zo|R3B9gX38e%GdVemztxF5nvIEge!YWE7*IH2R?9a8vR6l-yb&Leyvdv({$ldeB+8 zZ{I!8d^l6(agnUf<`i*Q|Hl-C44n>~tR{`)J|Aad_5JH^`!|5+LAa z1__r!@fA=y4e9tZa0+N9hsTqyeNPZwYml0-C@BP_c?t7lw@$2YSB;ziz(N}HD`V$> zGhNm<`!`HB%kqfdw-E7yX!y~CzfO=i^c%CR!)=UYBa|QQZOVn5p&er@kkq_viC&MJ zw#A@A8y)V&!FQm4kI*hU3*9x~!>QflAOpt}wIJm}1JXt9N8`N#)f0D9E{hy{zS{&6 z?o=xE=mj{P`7;iU5_q6YHaX{1@`brfkvEPGQoOuLQX)j#rdF9NW2shR>2}*@oT5T$ zTcJyB5pV)}#+VIOSsh8=xNa{g5GzJ3L6~En7FSTiy&Npk8njNkYY|zou9b1PC%eV$ ze>@GzD{O2>VLB)*e97^_&8b4f+nhDId9Fwh0Yfhfr{eCR%N{%-_>MG}xbn`%+YeHN z#u#LHoHVyVLhbnx)5T0H-XoyjdHuIW;!Jt#FpKXLoCJtK03(};GTm;@KJxjvi@W$N z?T-|DIq{Y%BGQOK3h|tUuQ8jU!N_a=*etc8|2T;(jOWeC*l>5OtAWdAVE6WX@IZ0w zfL+way7F%Ni?8Ay#%tF ztB(x~V9>or7&4ir%lsCLsu{*V$B#V5phFVzFWb$KcaFEpXNwt$Y#;Y+0a-2H$2W9+ z8(`1F3o34qD|rR#PsV^QWyRD3h?TCWe&Z&`De5l!Lr z?AUQDQ{?r?wc8_XkLh-5sDpN&TYQEjx_f39zKZr0zD~L` zM5LH&s`-;Jq{xCNdO-cvT*ligvVR=J3kHefyYW)T?Wogj36aH!ph~qX1xY}a&SW=6 z|4%XD2ovM|m>3)y%8K`)j_oF?)Z+{$aoMU9|+wH!{?rL-|Fz7m@V zN0045;|U6(PW~HFMrl@3V>5;CaKA7^H#kjFmvj9)W)*gg?tZ2U1w9X)m9;>*aOJg7 z!eLKG%>6c@HmC&FEo*&%?jyyI&8|mpHjUGA{K?niNt zv)9XJvcc*O`Jzk_ zKu-vG7`f%+w@K85+};}3eHgYx;@4Mj448FmRYWBgq zWBwcciHnPIgXCENPrn`D)Af2u8QTV%)K;GNR=x#(Lsu@ft*xx@wv>(TF?5_aTiBf< zVy((h-@WQ9F25%@iU%jUt?i5Sok2hCG{=FngA<~@9{f0SLnR$P(PbBC+!bE>VyFbf&Fz~cxc?*jDRx_n9%P>cpc$#I zP!ZhpTA^#2H0a1jepCNz8gtK7zmIFPjUxsl+Qid`BaDqvB93bh$lBM8EwKt$2MtC`b%!yEN z+lr|NBSUt?r7L#Gj~-Xmugym|%!(_ar><4_4H=@}ZsD)o{@5$#6h;)^yEnU0^dL~8 zLhnq8{aNv?+<(#^E|u9@ZX|SN~#)C1q7h-dR9+^2VlSn8d_fg(ZEOl51A(7cXIdY+wI# z-YK0{v*0z6jxGEJ`9x+Omvj~&RwVb-3ae2lpU`4Pz_@>VSJUsH?UVA3K*sn@kHd)N zfpgm3ra>+%Bxx#wuN-yHQfhia7x34)cdXOenFcsB48eeH+lIpI`~gD*zaAmr9gjqZ z63<)lqrtAJMXeg3-YvcydV?}-NQvE;fk1%aFmbDD>QyQ*967hPcV)~>m9gKJZ?(1z z=0lkbeNPdJP8WuE5 zXzc2)WFweO?uX$Xni`Lf zY3tvjnWEroX$S)*j(0>BEI!6H+J}Hp)h?_T>9v(Y zTBxX7IX_9p?&&Q|(p}ZIFQ+~Bv+A9c`R5f}43CT?xk*W1Xy3-_4n?hT!2pfTRBJjF z*KKW@MgLmc%`MPFYamAres8!rV$ewE6|}^k-N*}XUH+J4UP1;wq*qyMxx*$=Ca_2t z=9rGu)=?}j((B{zw0`4q9Xng*5Z&Z7LVp77(^rHTUXI_GN}nMHPb=8pJAElMXR~8AS#<$2#-zXv!5b#A8uFa>*6bj~l4L9hOfJW5 zHZ1Ip{J9!&FvUDo(mN!k=y}-D`(x3=u3ePklM~~;9Z5pJ1IdLNlnydOOgB4U0^n|% zsTz+MGr(K0=o<%3A&0>DNa*hm+FOvCmdd6X9iiO&a>%v{Z|YUepqxJORwJDF>1#nf zT$WaN42i5aZ|veYoC3<-b$v%#W)TE37wGY0nU?^G1nMnOrsvqLV4S!uusKnH@c3bZ zJK?TtBaLd_lpwMqswp_$udS%juRotp*>{v=qWAqZUk0pC$}1?4tlMjAD3R1NC*aJh zwkvxYb`GQCQq2v7eG3spar6wrg_log>u}40H%UA28k&$Be#^`k2CCZwXKm1+3_4@L zcV&FS*XfMKcc% zs3zIzz*GM(rOCg#=DtqFR!f|u&5WcG7EfK*8y2XVS*N}@x9i;#QE=8{y{1yY%l@ZS zpj3jOVL*WLVDv#HZuep<34fhjC}3LHnaB%5zXeM^-5|vgzyHHK>}`tVoXutc?-Me4 z;ad6yR#c?mGRBHRt-M-W^Py(JPB%&u3<#u=6ii{)5(0sEN$P@O?ka6pzhJuCDGOU3 z=cO?7ae?pH_i8XL=Wh_+efE@QzMo3^P|{zy?fZUrefxil zbkeEADdX2aJlIGq0KX25rkMLZ0ULEi-#iMxGp{}Kx?(hj-IbbN%?(}{tAB^DUJjcZ zQo$Cv-Y}LQuzSc`g5pp!-*dlat!G(atvvbDlo3+G({x9CC%`u25}fvls%Rb;S^%8h zWye5b`V-%R@x%g}Yoo(^T;Kx?We!&Im$bZo739~#$`N^)TZM_o>& zn4-FL{sv1E?b8$jSwepaOa-Rwj8tYf_!B7pw!D)iLRrY3>XP0fdrxh!pfCW<)FI(j zFUf5+Sq}8obgwWDeDL%zZ$QjO7w^TAtnH!uTE9Mb^7q9HxLI{8u-*)f%I%ncX_o{e z9E=tdr^m7@u-09t;a{bdaI;1g>aCmYAGvzRA0@pEboz*hL;EFNpre_N72_9V6 z1OydGOzmGpqXkL~tAXJj+nqhBwZT>8oGrbea5{=A3F6X8^!?4w#8V{M5MzuP)9(+* zyJT>DKVm{+`y>JDNFCb!RNA_W#~5exv%fj|d*LOdB#y3ix@-lx!nYk$?~o9IW~Hb9 z(ZP|XdFMpOfT%rbnolwoag?;>5QaW?dZWCO+lOk#cntR}%7R=UtzQ?tGyFDXXV=3O zoD-0J_l%57IYcJWrpJ+-!Q>2kqmNn2mG&+9znA~95U}$vp(Qjd%ql)Y2mnft-h4Q* zcC$y8eO<^&3NvPG9DpC>+b!xUH@is6PeaX=Ya|KQlq_0rkVv*kbDT@Y`ND8#v%ENK^-xcj;Z^M| z{9^3%In5sHQkIgM)Uz__Lstg>tZ1Bs^gDnpzhY01$9@%)sJt=~&@?>RDRITKg)_1M zippID?a(qE`XX6h-JkbRKoWQ=LsRb(<+?3O%Hf-+HVd_%Fe(LA@)(z>QogX){u}As zOR5v*X0G?woYVz^YptTG4vbmPX4P(D<##k0zYFe4=C$z!zl32V3|EBkRk{tP$VQms zfm)-Q9~t_d5gjmc47YmuM~8yd<99~;32!w!Yq z;f>FU))^+^TqWi@`h|#k*AL9(mstjnad5&2(OrYhWeG^=9i+!;A34x=f3Nw) z){^7Qd)_7m@*iueV^3JfOqhe+9-H`8f2%%fiac03U{VBnzZ#K>XY>A7q}!6EDe~2N z$D7^gJA+tlYMbxXLgmtbJ#v;zOtT_k2(?u`$ERryqhY4lJkE*I=(Cs`8uAB1jv@T-sl(kLW}XV;g7DqId2mlojA-o924eECaSR(8$k`&tSE{ zZ*vc9Sowz*11k|NZpUrLi(B74@P}q4GJkA3l5(&3hH)O~9ZqeWnt6q=#PWPYqN!Cv z-@bl0xrz2lz#s(#x14yF&tTuiF~ytkC;X@AdNG_XD@y37ni9W{Ljl-@LZfJU&DxGd zbpw@ND)siAIYUo-7rdX}+r%?)7gbW4c5~AzjT?stLDD{=rX(Lh-bXi1VX1q+t@Vrh z8~e|H$Gv4t;IY8=+c4>+(t9wxr)fQ%=L6J965A*&GM~=zU2xfKll#Hp)0bgK#C2T) ztJY<;wH-UiAOS`wFx;KBPB=Ij ziuv@f92B))xZPj~W`&LQ@!=`zafYDOU}{f{&Z&4%s0c@i|5b}M-!(^r)g z!ZSMV94ktHz22`VRuttpok@W2z7 zxq-;l#j7LihdHXAzYpJ$G z!b(L%EY?{JiInCTgzUsE}-!ofu zR}v^7e>Lts<6ljhMRIIL#NNZcb^fYGi)eAZ>XKah->^dUJkONg|yPqg>=JDp!U3 zY8Nw_Es?ZYQI#C!g=ODe^bEl(L{IDC*p;8Cto65XTsGSFo>@6e0uXPzh%1j{$(B_Slk9HQq|Q1GYjd`um&xClmL9=w~nl|En?UbcX>M(6@e)$ety%8O7+H#Q`&P zj7+4Zr8WE<{4+31f%evtbK zb%sq3>ve3T#pCu9upRqPON4%|%uK?Y9^?`+(Z-Qy<+CR=NSg=1(GP3Y*CYhD{T)OtECTesHyzv} zwIlp^^9N?$`!y2j*=4%k(<#yDd2QRzCeZkGfpUM|B)yxl9ux>2zJT;eFKWOKGw`L#LK5Ia3e8CX-Q=AG7buI2 zVu$O9$nD3i;1{l*y_Ba>_j~JC2+ly~u@e0SHs$9)n1v4wp)C(h?h;OC7 zUZUV<#i|tP?qe>nCBZLVzt8)(o}NA3l$!{ST#Y%K^B9jj!mtT709M}>#h4e0=RgWQ z*1ydJW6|XY0br{s63T-8sv+v}{=m~EhEUenwRs{3K3jtwb#>%I)?KtMI6a4bPR=`A z3)O8uXX%n`Tbc2t4~BHab@_5>oXHZ*RwvninRKQYji=2wWD&S_6)_VSz(?}=zUWxE+mM@4Tle{e4MQF(^))a|{&OM^r zd#7H}?Sz?gYq$W4%U`NZXRHW5>DLEzhNEP=T7;mF%by@ztEd~5_xQ2hWVgmc?RjA| z+KO{FBznZFc{j26Xj2g^kr@vW2{y<~Fvz+Kt*&KHNo@;lE(xA{z)sKFoO)&gunP0C zTVW~16o~yrw3^IHlQr3FTo!WML;Ra2!w?vqLqm{ zJ1ILQuwB><`+>m>kxZ50R^vnb90?ngMT+Vrs3uemX-1yCGqk0^CXuy6)XRY_p!{{2 zWsAKvrzikwSz2z_!$>yR?UvAWH*mIqkF0LTbAH*MVT9+HiI&Wd@I2R9QHUGzg86dd zS`C)#h~p+q8+YU2qw~tGH^|d zIW`SO9=<1T=mdN?1MeOjoLt@tMMqPu;5qjm8P1FuG=*vW_$Id9e<>k!b8;%-F!+}T zCFFeH<4*e33opc@r}n~+UkPX4YoFD<=lFfVw{qaxo{spaE#Yf|%7yd$b>NTgZiRFf zjSrUC6|}`Lva!j1JAMFe^ouC$ZC1GEcM^CxbufmQPm>{~`~@@a1%5i88JmXtD>Lbv zu&p0kY=F$e77sWvJEj;I-dI%)s(BLUVS^HOuwn!c*de;#=D-%vB0qSD8(Xu+Uo_?1 zcI=~2;Fj14kS|iuy5DK7evH}MRwPHP=Nx>!IIK4@35~Tdjy$>f+7c;9$|pOv^u*xYav zEA~VTh%Lx{IYUI?ruDSJ^5^Zl(8y^B?XlrO^IE`(JK)V&+(vIz#P zh#UG%P7B)N8?zPA_#3S5E!JY~Ki0(afRHE^gRPUyvMDEi1ST;UmL;S2fCc6+QkEFDV3H3HhE9D{|;iMFDk)j(K| z3B^#nq9pEEOhuT)Fm+75hhwq^I_n*)xEJ29UcQi1dNsn-ZhbKFQc8tT=bGQEq_?Qaq zCA6jr5hr$qbCxW-Ti;x$J0_TlTO=%S_ZpV8D)9`Kxr1dsj^qzF&ze3=O)-*bP1X_GQfce&p%TaH+!s+pQ*G)+>cX-MI14{@ z!QYo)*A#S1?p~61TR<$1@%j+l<%GVoG!JVs=XaB8Exhq#`QLho_rb98{%0EU?#pG} zSGeh=-X=zZ)t1ytdwm&{wC#U(WLC!>o8iC1VJn3QPiMWgRBxy?gBCuVaj!Yey#uP=jP{MPbSFF=Rh@z4cE+>@L8 z#wB%OQ=~fl|F4%IU@g+HFTRwyTm3qEld!xQrq>iA^x8Q92^8I4IXJmwzC$7X=(2i? zDN^tlG|diEKd>5ZedCRmV*wxYv{?oicr(Eb$E$Ae7+lyT&?7AB`)ct8f2XTlF+)1^ z2REW+v+<^ldcX36Be-bFn{!hGq>W;IRRxK?cy4|BTc0;$x6Fo!+xSu8mB=1sxz+AY96pLz_j$Eo z{w0V3`J$GU%o=yD;4n1{C5x<{1(e%eqkB1_VP!G)zn4e4t&(@31q6}yv z?9fTyzaKhpmi-A}w#_a9Aq(ybcqu|rtk7)sD(JtFvcwN7u=4aUh2Iz3#QOY+6wG1f zMnYWx2Mxxmx>Z?}v?>#PR(RN_SZFP^w!?l}lapN!f-|*7=(Cbu&+r*yz}uGK!|TtR zd8pFONfJf#eDnb9dwKe(79vQhrBE-xpa1g;nMS*OMw{5bus+;9{SDp-c+(Ji{QgTj zq1u2H6F~Ife}6ubX^2V8u)eu;C(@mvS`@bU4jO!V;5nX+7g40TY^Pw{)JaCz^M*G5 zSMHxtoe=^sP~>$ z5;tG|0+moUG-K^9X3U1Gjm93}DEh4od(TyK*9jf{meNS^`QF)`t#cv6F=(TyGNb_v_ z`VKbCVST2`!=}A5qhq@0_xgJ0mlu?Ny#DeDHCLPG9VYH)aQWzq-=9jpBIC2TDRuhv z?b}kPy?zhM*WtS_y`ATpE z`%x<9IPgrp5@XFfGRl5aBxvu^~OtOWJ+audb_f{+RQ5jj1U}z0b{> zeW&ER5Jvx@apxKX9r3#q1cV{-_mipU|9H>I5NUdba)81~vtfc9KWM&X#ld+tJbUeU zQKz-Y+9PAMhvfZM{8yz&4Od!sgqn%m?!D4f9x3it>wD(pk$UXzSS!!zWRnpK6PG;y zIUm-eWY4wqnsiW_^b{hmZMI5Zd$z>qwc>QnM22I=LdBS6*zyrcjpMC1w+`=JYLYK4 z-6KcLXuLV!Li|4Z;s=FCf3wwIQl(#nwZ+}!O_ zCX6H-4-aJm?p*ih{OXlIb>Oyh}^eqdElA1eq4O zqH?Ql9hoWewg2Os4@CxV0k-P1sy*xX;jyIkL&RroJaOUSIQK;4(!4P%?P;|S3grqe z+(Vc&E3251IUm1g=T^UlzZ&1rV}H?KcnPDwu;A|<+!SLZkX4vRH9+zC`5c)7Vt|5% z5yNO*fM}-luj-)JQOi!j#NO-_%}{kJ7Yhv4~D65%R_Gg?O=o0@Zw_&)P$acZ?^-;5$klhrp)90L9hXX@>uJ z8Ek;!e4RVW%Vea)&N0&VRb}91fhgMJ+=RWauW~DFblZzu(c@XmVxjWsK_l)fHa6iS zG$)eBw4+kqt3R@L_ zWJ+@52cHWdX8d#wkvBtT?!lUs6*Vm~jIX z)#N^dkG5anpQ{=o-Pc1_PI>NFrY3U89{TsPH*Abd%TWk@w)Z;6M8C|PZ99*L{nB*W zd(@3D%1!gGT+)zz4;!u3*YcO<$Wn@Pbp+wjp__IYP=$^}$7!dDK3R^5vgdN8Nv+iR z(tXu($hHwo*K=fN$5$x- zY~S*<;-^x@w5YGW zdjD1)L+OQIot|&9z6VVY?&L~VR#L&&xl_~w6tjDF+@pjo$x4G@D6Ok|>iwNVf=Nzu zKRDU*5h_EwgCFxo*a$TxQ08|eR4oM_t{%J~a)0I8iw0MdU7exd8sEm!j5$nLS0raV zAPi7Q$A$TE+x^*Lhh3X>tS^wvJcg$Vp*JPXm}s%gWCm)pYW_Adq~RyAS>oX3CO)5W#d`@JZg)Qh5Czdk9B zVdUrUo#x%6gyw_fnMy~qS;`Ed8*#R5-)thFXAdpwhPWS9+$e_9JU?4=z5#-jbTFG= zlx#5R_3^v?%{6G@lI@aI$3QV7MOE~2T76yv-`L0GnM96?>8Uln2kSeAU3FA@j=P^z zr%;t{!kcED&$3&Jv#`yG*>1YgM`)CE+DDUG({-IngKMl`DJ`LF$+aQnt!HN(9zVJz zs2tO0xLx5ISz^{$4^zit9;LJ4fBvzC4j>Dg9^pOq?T|kScd5 z3Bg;uYbij?&sxzbGhmUT@24d0hhP9ZM@aX}EPzaZp3kyKYQ#Wzym77d1+ww~kU=6$J=5ku?OP*~BloIEtfMUc@ zA;Jcto`!m;Pk!mt4DWqQ?p8iz-0mmrZF7;GiDiNQeRs)8gFmY1LzLHjW#v=i7)diL zD?lU+M+*>Z=trJH53Zh!rHd_dteTq3F4tM0IfmXsTSEJ?cxR>E|HXTN0z!iiCv)*+ z?AbSFncu|=3IqsoFYDvC9=DqYPZ|)vg)ORdJ&56snXg_Tf3 zp(I13AjjQ&L})_0^Y^&+cmaOlsg>h(EMv3i<{3`edAHx8l`wZ1j&k#S814FE7U#_G z#?+GQE6nO$8GEOz;K3~qE#%G-+W6z}&(T4Fz{Vq5t<_^!KZr&#yT%dQrj6E7G72c^ z#_Cs7=DHc_vK#MC3-Bwe+FU$sjGWuGx>H#s6ZDrwTm&OowL4IouM{XeOXls!k}Y_R zFYl4^x$3YlZq`Af)5n~AO&)rO1{k6}J|!u?C>6!%ZxlPURhXY&k7!_p%0PYmU2Sw&|7G(=^`(b)IocqNG(8-Dr5lw~%t;)wg}K7;Jv? zL`#2~r&`$4zCZM19X%PBP+YM87WmV%5Y6xw=!>Cz1kn>MB_*{nM|xH^wS^c$F+f2X zefCY6?RXzx4E(G)y(I)_Z&7Zu&zz6%t93;+`ZBYvt9#Ig_1<*4ym5EWXT*##dR?GO zahok6E+v<3@4|h1=vvLjL2>H$7fEn9gyp%~BlK}svQMoS0N?RIW;-KS_!QZBZ!Wu! zGi+)PQAs4@u9yO@eXTnY-OkgEJLNn>6?7HYql#|q>f2eFUQW8W zHKi<;w1$Xem3##LXQRFa+@#B+_gW=#oTZG1+~? z_Aj*%LeLtRh9hzBR8&-6bXech)Y6LMUZ&rMw)gzmBYVe%`1KS83wq0jz5Azn>_iiH z1}GSx-N?KNUO$1T3wG*epr zQ6G4#-E%mXy&zRzz2ElL{f;UCkr6#E{7TCTD?mkT{qO5F!X^Xfp}Z@Y#EHiV8+Mr1 zYgvG|Zr{3KKBIU30%jX{6j!75jq8^%j3){ZFHBrBa&!hU;u}p%3Hnl5iJ2|hw2&;` zI;CU1Z|2AVC<4%8$wz!>nCvZ4?u@BxU>@V4PJur?pn$>ZH6RM7#Otd|peQQ_wri-c z4^T`(dz6md)&J+4xumW+8G?JKeB1o&g!ADz%)VU8vozk zX1Fm|(t6r66CKlok;e`{o<41{Zh};yFJp^MGtg5Jd}wHS5i_RD>^8$p^`sJy+L%3p zyw03`CxJeu#Nj5@0lsQX=3sPOQ6vpjFI4bj6scWIO-E?g(fV3)Kqm9|7RjYQQKa+J z5K6M7e)jUGU;ao^@`C?J(uxM)Bd>21K?$b$zy>EwTp4xh@W{UD~#Z3Ibb+Z1aq z+aH1W|J@yG=TsJi&hQNOLgfZC7?_v0u5ee&S?m_TsDvrppd0Q(x}A z8pWtbg*?7q#Mr~`_0eykgg^$u2Bd@?WN{m5;=~J~pn?%_PU>FT6Y+Uzz zODzUQdk|Zzgg%aEX^`SVC_-kZ>F}Ram0AMw~EI$(2 zojS&)15Ge@CHSG3N!JX%MrdWa?5RXoYVOfG5p$UwX9mqBf36B4qGX@PNTHJ^iwT(Y6^9v!U*}wA6c-13^rTv$h49Fvh8ES ztH@vmojxczAUTznD1KO6P2%N05^gddQNR6x%1HUp7;>fV7PQ6M-(PJdrB6QCcog|%ir^GrB`9{ zIYOmHaYHGCV_(&KssD#iz=!#?u+GZF1eNlqh;v5`qIAbVCv5Te-fe=hMsmQX;n%o# z&XexGdk*cNzYLjgadEK~moZ`_qt7Lb?&yXjZj1K_opZrL&b+vNH@9MxJ9*UKUC;*- zC@TjqZ=NAe&u#a6Atc%u9-wejV*yuYi}j-0f$E1L=G7h}tl519a9Ovet;U#aoLRa* zy|?C)`bm3!?R+`sl~&7Pw+q79FOhq3QamSKrxTx@8R;3X(aAoc{B=h=CF=B z+>Kisql$--!xjsBttH=q_Uu>2D?rIe@I?et3*HV~gimT=kx?L14l2(Nmz_}iiiHxd zgz%eR-YeuI&U8Gt0qJGJKw?eCyO+7{DhOLw3c|>T^hB7k3vd{I6%P~&5WhWp=W2V* zH>`r)V58XQ`Y|CF2dOs?gfAyfnk*}@dh~@MB*;C@?YJOl)76QC{r}IO55tlxTlT#QSHTiN1LYyje(APUw5=z-`H*hgGWW(xpY-1;qBWph-~vQO*=@_a7>)+tP|GT? zzGu@PTIrn5uj-(X-RGoG9?Qcs5jyg0m=>ryzffDXU%s`|4N>S;lApeImDu2UM5z5Z zk~6G$Oyn5q9lZ&WC#*7UG$Xh;S$fvc&c?>ogE#%s;7_r=+7o&E@hN$MDl;955$`gE z!@C?wJwAKZVLLCV_8;GWb94Vk5 z=e-qDP#sXxj?SKJ_DO#nO8N((lsh85*GY5}Z^Eeg7Wb}IiOYKDVZ80l(Y?Iurr(s` zLj`1dm{O@@szY%o#^Oa7)#hU|v*h($KnXP3`;9p98R!ip?Ye`=tWq2!=(k_rS_zL{ciheeawrZR9Iz4h;3eM-;X zfcIhN3t!27kn+riw+{+!U4yeZN*ql6XQb3ych=fk%K8XZez!p57|lvrV2VDX7VK%I z{HxPpVI}ltMdVkqUe{TIVAFoFyU6l~WIYHnRZ`L=5CXfp#__IPpd((1DtJ3F`zt#o z@@7|52An{xEVHks;@twVhjsMu`<#Aib}uyXQ*oMcpr!V%w8-|TcU~BK`QrJruf=LI ziKkPxk27$y_q%Ec3z3-ZE!4>jz+?)ybn{)$`!Kj2;>ai6QZ4loZI`Jg4;N$%2s%G2 zTWPa(nt0!pb8{c23U;cV%J3ibQW(;cU?w(ps`OeU1+WiXeaPW2xXd91!vI;Bc}E2@ zVG==o6Rf1YJM20~{TRqrGzMe(xZ~~&xlp`Ir}a(7zbkO+ZPwqbu5r?-ZGM`)OS}CZ zGF!h5Xbk@v$MA|1v4eWag2sxLpr@L((|jS&po|CfED|W^v~nFGZs`MGzu07M+nXND z-<(qhK)#7TEWY_of@Yz$sr>fCY4gp)TI0pPxye;p@B1PWb;s|knjGbDxsQMLx_5xWJ}dx{&=!82X*Oe~LH84Y znF$gQBiPLoL=yo5EZA$hAPffU)FJ&h!R8JE?m+mvM{+ch~Z)!zPV>QR8m}8 zfciYMG#orfw$6cDDQ2QdTzET4B~`K9-HVaveKUB{9P%rx#-MoY(OEXc-sGA#fPtuTK+;r(Kp0Q`ZZXK+XyI(Y{#sfG%}; zt|flXXQ1hjiT@F?x8C+yfE2kwo{u;g2xKE+&Ig{SA47ONc$kwC0UG^j)zBsFNWUHO z8IWo-D zo|9R-NzqJ@EV^3Ikgp`%wJp*eQ2RxQLCcNBDc!iSCk~Ts)_x|b!5$a`(BC}hzp7*3 zPX%g60L`R-rvQ!sz0aQu$j~Cka(S0_gha?OgWM-jvlNEAk9J;?iZWY$`VspQvfS=4UMEZQU{;3#?(XZj>dg*&-1oqS= zJl@cIA+fA$(4?i;iaZ|={9Ak-AgJSIxwhXj%wr0kqkQf4@*g4&d)dp1D$J?Pi)xv# z07#V@s-0*n3+iQHkrOOh0jebUJa<-udc>l-Fp8KNGj(`iu?|^%ggY0cGpvM(W6b<@ zr{|3uW&V}7U-U9}*~+Kp5Hwz(ax=F) zHSB@Q<+R?(P`Ck9@fpX}!PX@A3ZgK<+w$q*aqSl$YHig27hvc`C1|$YKlb#>&nZJn z5S5rP=9Z2**zsUBr^|bJ7A+ zF0=g2w;xzizFt2iQ|m|3Tx%i*duyzBcfRZX6-gkv!nwS)_5ODx!OFSe8&>l_tVIE0 zFE~?bm#o{%ihz{6yzuyy?JTt5v%I_}@E;87Z|K%9%+=oz%jJW0L8T}gl62TD#r+yC zCi*}qeX)40-F6GFDX9KN!5K4t_xiNK*=~s~1{)Oha zd+A3=?Mu$CY6b9|NCQt=7aPLoz47ltf~??hqL?EN4!F?->8j~*oj#JvkSv#F2~@9h zYsJ`DNHE94tcr!7*jix9+cXeoy^H-v#b;&yM-eiB);;(t5C`wuL&??i_}4EAjSOlT zU7fvb^xKy|=f8w}`-KVrg9rrXdu@+K0VQ*#pD)8^efyq`F){dQuI9*@Dg=Ng`hpIr zbmPnrsDjUH&bWQxdb)?3 zvcmojFVe3W6}1p|<{8UA3d-$sRsv45c$D3gGUR<-_uN(#UGX@z_1dXQY6HEoJVDj% z`1tno_S=~{Ri)hdj4e<}6POl+4kC}`B1M<$1Tkazgr}J={ITQyZ5J%@gB;YFW@<(9 z321rUbu<&~Ijx$mAoAcHqn8wrz# zRXaOmI`RhnJq~Gu-u-8P^f(w}dqD@K_thtZ^m=Hr4Ee!psD@E3Is(`-!)7kXb=Dx~ zxy;C;aAGQ>-;}~Af?1kX#r#m1xT*JM7Y}H3GIyUtpY@R%m>##yHv*6Sqjw~vmmadU zujzGhVma}*Sf-Z4yEgK=8=+#S=(eCqv1GV3yT$~4@ zQ}I)+@Y7HC?DE!Oy(#eRNyR69{3|ReFqbQ_lHGW@8rQjAXxoik|E zevu31_)Bv6xi!rI6V%suwJ1Sjazc!>nqrg}{ zvTe%1vAu^Dexvi#QH8oaA^%2tK(()VpKTJiH#py;ZRAiI>#DcZeynmvugRj|*Li_W z3GR!v?BO}4SD<^oeUMzv%UqUg)k{w+6bq!`=`Uw7T9iTdTBx_X9y>H!d+y}^Cq}P+ zcK61|z|8Z`sGhj*U=_(;BAd{kH(N$@-yoy{C)>X|<1hZAs+H~b0RRq|?u01D<$L^> zp)3WPB7WTF<^ADeY5kk`*I3sZ?n%lQ_s*%&{Lqn>R#|b&9jIOYO@g+ZsuQYmS(Xg& zrPrIq0%|wivjzhG7%J=V&EF3;pQ*4$`ES$@*+*eT-u1oRXsvM6m2jkpfpMWyT01(j z;{w%L0{=YTu2ip*A>B8}NwZVMHnSY}xiE+#MVlk6sI)v0Snxba5byx;d13QbZUkvlp zRm=byh|e;-B^!N|S^h7fwFu;tlzIaetJ8B&@5dsM&gQH#uCH>&LP7v@7P8^8`%X~T z@nv7SMl;{;*|qZ28po-Dq6%7c#pg0N0Z z@IRSJ9y&euSann!-j(D}+Pg6{0p6X1Yh(Cb@FCuwQvez(7zQ1xqK_g^rnb73eYL}xVIy##*=RQQg zzLTqD)h2f!`<#$-6_+FKnV4Ro_S4zj;TC*K;qe?)XUROl`FN_G6p3>C4@5MXNPB;$ z^yO%dL41r0Wg@sDCW^W3KhNz^{lD9+d-v{HW;Vq1(g$y zJv^+28~!xwT5-b#%e~v=)YSL!Szj(rr3tv-M-wGc1p2+Z!^=H6v6HDBY6XA=GooB| zdg+^(+erEaM|D&-J_2Oc{C)&t{4ljKviAhMP*qLtEX}3gA}O zPITjwQp;ZXc;~AwfB@g%6`X%J+01C@z4wKQiiTP3-$`(m(v}CL<()1|_8!+*FgtJ;w07 z5^hak2fDU2(au>WHomQ8pPc`d3n9#J85&?K*RPx4P2Yi_eY- zRq*Drq-Re^-bLw6m0JY9?^bOW;IRRiaE9L+tZnzQ$6i0=HNzcFwUPWJ{ijEx48rVl>Jqnj&sh#Bw60S$X znx22aYCS+eZKGDNo5w4CB;$^uW@me@m^EbGiNExaOvaXENj#?9n4h31*u6{nlzC%f z*H+Ry$-hk@9fY>?&k9xLOV2XPTMyB*#oCB?199vi0LRpme@5$`3N$3Ku36N~$7F)w zZFcivSpTkcH6Kh}m&xJ#Hg>E^WpnwNqbg#gJM;}_oj^V5Zg#j;n`@vl{-gTZq!Mq_ z7CjU<1R1NgHdS!joAnYnuWApcs?otW5|v*ItQs4+cTzmpO8TjnHY+Rf(MPNP*BcDb z$)Dd-A!D{FVe@jK{aLZZL1@!f#WyCUN7ix)N`0!`Ub+qGvDqg>AMg;Ki;&^ zPSlN;4dlF-^&LWo1m6OLxbkBITx4Lbv+YonTm^3{peX&;jN96gu^}#x^GzGxeVPJn z(t-w#GKc6kR znv$MQM>Rj@_Y^*(wom{DD%lqilI*Ppp3vkn&qN&xBmvK3m3FQcfcmGIzPAhI>;&O9 z#%|VnV9BI-^`h^Ge3{!N$gJJBXpwgGU~jKenbsr2^-HFR^|GfRvflK)?>cI-bxsk? zf=-poDTj%%OI?3yqkfnow42StDl$rn9kGI?NrQ6rRvW89l;X-~Q+m50$BCAtDPBxV z5g32eAIHW0=5TRD>%-w;_zh<@^i&jl?HzPnC$V*aAbN-%0P^**4>=w-a1t zX#G1}p-RvMNMWZv6C}dtbXF{m#oUz&qFf{JsXUQI2!oknjX?W+jxq2Jza6!oS`9&S zne7SRzZpJi?u9edk$e5B!&jL}s^!}H3=`QZVDz4mPQc&t8&rxvBS{AK+F7l_ISi>9 z2Q5qxaTN9AH|61+k_F}u1nP{unpv!cL!4lE6-G){&Bu&hUc+C84~|nSfP>g5byGb- zpC7=Yd2n?6QlDq{&-jkgJ>5SV%~(4|Z;KE5^RoIzTRvowgT@lnoMz>Stae;;cOSN z%3Vip$|n`RM#e?oYRzuRzlS_`uK+;NJ7*>;T@>pYXKOdxKf?-kr=C@o)=WRb=fLko zF;u3u=t7vk=R0T9KA`>FzUAJVj=c(Z=pB!E zt_H&)r7L;0YH{}^>Xed?)bEn-D<~sw54To>_jW6m&i^%*@?TP8>GG@3_VOxe>twmp ztW;0;dffRJMitSWmRc$osK*2d^Y8#(Yl2e}*8$4?__XfEvuITNoTk{3@^UW8(07Du zft*%VLXnl1Q^efbCl}^gtQVknloZfRaV#5M3tsJ|UlNX1Mw8I(1G19E9EyL5DN9oX zIDhYGbGRWuO&I&`hq_}C@84NSJ}1Du=XlK1JTu3oAYowQV*ud}%Siwqt2$|Q;^4rd z|FJuly3cGz!~hpq{6LBb|GQDsk(!GXZpBxk+6^yZsiI+wGE!mlLax$ zk9?FYRwyuLN+we-9_+Whw6Pl5>Sa(c&90Dnx$ju(JD%-C_!uf7{PZdr=<`1bby&7E z$5RXK3Gm%ZRX>Q<0dj5O0D#Z&GBy$;grKfb$BG>%#E2MQCN6EK+ z1H1I7V6WN>{|=L78632jYV4_EHBSfxDY9e#9zE0Xd4A}zo=cdm)JoeCsAk#!Zd-yT zYpCx==dHCO3vrds965tAE0MO45cW<-s~c@KRJSy(6yHeSqDi@}_D-u2O}96|VMH#v z4*dYuWDp?6`Q|*9b3y&@-!GEb6$%^>A{WDpt_d#y4dba>5vIsF8j0^56~?U>Jd#Jg zN|YnWctvIEA5VLS8MNzOE)Nha`Boz6JXKN=al=ZKOl|>3Cqq<*Lcxl*;y&5o~ zzrP)R2fVjgrRvo`25d(R*#5mo8p8zZ=c{!qc&1|D$6c_tLh<#wT6p z&P}~EfUuezhUfW1k>Aoo)gjv!A7GG{M^(Zku{N*HD+;S#C-m4K_)ESNhan#B&(DX2 zD$?z;zn8urlXmm@P@JADWaj8A)d?=46wfzGP{L*Rd%7vQln|ph8w!N4uX3eN6Es5f z&OwF!C5^mEBd8mJCF92({xi~iqye$E1U|F(v%4W>J>gKK{Kxx1fhRe8CXWS`#Xw8r zcqyY9;_q5fnrs1j^?9QE!FkDgLaJtW5e#3@)~R?6qQcm|K*L3K+zM@^h%|>CFQdjE z-bPl7&D<`(tP&WrN9=fl`!Qi>2gl>Z`X_r-+r42XL(skQ(S5bpV{y)I?;EKd^6`C6 z^1zQce_UP(Z;9Gt{hcsMnMx6gUbuI5#=`sxCFPgxWAVv$+&%j7f8x$6xmu-{9y~~h z^h2zK49#A$#X+Zu)LCE9qre~FV^jgtIKIJ#p=r4+A5z^$XYQQ}5>mGlhMm@{Htr%y zqCHfL3}=Ih#yRP;(6z33Ah9ezg|7<*o_?>fQteEg^$07=H}TRi2HDzlAPTH3n;MCl zOQ~-%Eo4w8RVIJo-@!Qq%jbqtaV!aitm%2hD7AG1BjQZbZI7QZY*E;SH!F>H$(=`# zT7p08AeK&5V(z6HgI5!o8c2~nER`(P%-8JJ?=#qf&QVg0fIkb=G1{b)~*}z@%}7aeO<}U*tdyh@nt&6 z33br2GS9>uYQFtKoPIyJ1mIy$;>=!gw%L}4OsT#UXvlJDM(7LaOe)_xw&g~qv}7C0ROxo+tmgVv z_AdOT?5UT(Z?3j#EC?$OyRIaO7E z{V^VX-C}b-Gdo zCK`%4ut4*IVr&9d^Dq+PLI~V*mrKS44()ef#3Mi_~&rAo@UL_&viU8 z&Dq=hRKZX+QMw|wL~;-xmA2Lqr*_LNGK%?cY}MJO{}YoL{8e1N^aH!FAY(1XjTi9J z*xiKKX?9)+xwkb6U~VRPp#}a57>FuupDLHw4u^$NoomWLYmn`IWTb%Vp9%!d-lyz( z#DRmwFy05Q5{Bn62DK3y(_nqTiO=%gR;!>>aWIB^Qy&dx(VSAPM$4X8|0aenL}M06 z?6TOWa2ayfNaK2CVdE&T!jiu)Mp1RN%q+{F4ylP^Vrxm z{&n6AQ?EYGy?V3-;(SJl;&$iY((LhZRdv`}UI zq^wX-m>B`w6)dI(IAKM)WpgY|7vHsr;CT6av^h`oZOG6AP5~U65l-}JzX#e2RbU2% zvBhY~!>+q;+3TH^5{hOoUL(0nV`fbV4W4s<=Z*%vuK+q&HBnF6qMpr(j|xV+mK<&# zzqT4HjiH3JHt#m@t(2JqQPU`!=kv%JsyFnee5^(YyV-V74g+ljKOMRY#+V1Hs=icD zuV%VV(-=6kp*YK!ezQ^!HJjYA%>7sf8sneownOsC(79wJHlo~ypR#O8D;1tqUvtu^ zCZk7Ue(k+bRyUtaig0(JGU+2{WL*~4YdbYm*=^6|P^yF~_ZCNY@>Zln*iIkhXNcc} zJq5oLWkVO0EKjP3?rK)gD%q`6*ACrp|MuU9ne*XalM(qa)(CDtloM=lya>QmuNE~)#4PTYW-icR;?MgDc`_x)sY zP(tNnA1WpQ;c#vxf(>Yf@DfiRyLZ9nqK=3h)#+5hbX6GW&^P&$5ablG@asQW3flt9cho5J+Y`s$x_ z$tbdK|6nO&lqEIrNcO_x8aT=d0b8CtGiWG$=iLF2>g*DY#ZYaM?BsVXcch4I1AOnb zrHM1NZt|vzAVm$mII&)I-AjW8IshQW1y@db-)j%Xd`vdYFaF($vbF+Aicf@hW`4nP zPUW+oqZ zp+OCwaIA4kS|m>an5L&M2J7L#Kf6ROmV6V!9ocVQxF{PGb|_OHeCa}u%pW@_Rb`J7 zUY%bN$Y16s+y~POuJI8bv!}!#Q0??c8;q}P3)`>JfQ!FY0Fm22bCY>Vq)f}p_2OVq zq7mB9M(Ly z@W9l}C)2ge_>zz~l3!Tlw$10I%(mt9x()DyDk?{|bpzY0;m~1#|2`v8&*jbLbH2H` zYb~Wp3iOI#!QOm2K0Q!YA>_0t)_hvY&=TX%8QlOco1Ay6pNp|M!d!-{qiBCxe5+Ci zNBMc~bCPcIs>m^^HT(FP%!T2AF^nqR&$F)Ie7iivqA))_W%6G;_9mXEKIW*kz_YC* z7uw4&k{&MAKwHljD$y{pTBtkULP#ZiYmcqBwoSdp`wsJD5l4}I7L8yF%aj3@(19}4eyrQQ|5fT)y@;{nig4=j3gn6Y-PtZB(jZ-ZK+v*COr zHYx|#CM}(wAGc|+Zt|Tiigv;u=CR?(~)@13tx>>>RM`6v{-6b zcFN2FEz#F*@Q?EBMR5GAr%&q70SzarGo?gjf_aF*Z8hmoKsu{m#d{~aDmdN%&Zd$^ zt23u|5Ak&vs7==GpPFw{W!cA3;NE<88Mr9-?r&FYXR?-Fv=4ZCs=NQD8bzJr?9T?_ zxblJ&GKFb#D#ta+Zwa_aZR`BJtA}2`T^yA~hLKlj8fJE8ofrtrElns94=cJx`; zt!rRc7W6VDd=r|kLNIcB?_+Sets9ynI`P9GA}H9;?R)q-T!xR30;;Qx$e-XkTs<~b z9<`*6oVo?D%hcQR)2dws0PK4$!|8=7sq$qVmYT~EsZh86eIag}z)QB9xErK|yGDzQ z86JRNaN&zAOy?%LzgoB-KyaeSc%e5tK4;#gm2Lnq-0XsN0Cz*J^`f6C*c#2IbUX

z!1Fv#)UUg4iqW?+a0ibOxQG-qth{EodQ=CC6YdguXG^~24Ms(kI%8@2YSCHywVN#X z2JX5qgapGt`yDKPROMJ-_hu0oVJ=6W7Sk178DuY)G@BeQ@v_&n8)Ni-+*%pYR@VK3 z@w4vj7u^mLuygfV))Wnel<3^4abG3K?YgXb+c=Z`KBTspXm>&^PL4L>cqB|#J6lsk z9NDYlz9~38zkj6mN&Pn%hkp~Ff)}W_y5(LdSQ+>rZ}_Ak2w#lgVV?B`&G_YJB+JcZ zX4fuSZ1)49#YD@4Dz7$WdOD7=cXnLc=A!-ciQ8e9fydbOOc zUK!osQP;l@uc6D}YsPBZk3CfAF8Bn<_3DTcx^9X1J8YW}Fcx9oD7_tn&o#xuyb*yt(2wtH!4LR(O&EL-Nn@ndttVjgd@}Z|| zhz&q^QlXAW*@-ex4ca-^_d@<@7MHe?HJ2gud7~W1zXo@meK&tzHaJsYR^eyQHV<}1 z8+gMVJFcASquR46D94#fQ^aX*Zmo_I!4eKLV>d9(Rvslwn77YWzS44|P68`eT@ZB2 zQ=qLZWLGp3r5xaZuRp4?d)|FC>6`T0({7JXYQzPdV2t3;OZ;)K`{~0+)!63B&zD+y zKK66mDV#bn{xW+OFhRS~aAl>p{tF#hpN7bH$k zHlZrlX1EHYQr$r2N~4rHmM4`bj~Eg%f-$Spx*qse4VfufnD|sNpv#^#ijd8K!ML?! zCrdb_z$^X3+P3tVSQ%x(^t1g)z&M?zRSQwJvRBl*h$A?V-xM)}65z4O4fN1e%^tf2 zGi$Z4=YbG_-3QZ*#Pygd;zURq>{HF#QYsdF)GrSN~N`k0Z5b?_=+G6#C}kGSdWjriTu?-l_rdYNIU7 zQWYjlMbWqW9|2?bUk2Bp6z{>`P3`hD>H+$v1H^K5duUV{yQRVPRqWD-_UZF;!orN# z3!~Bqw$`v|uqi~uXdh^@R9n+`*c~Y?AjJJJ&>@E;;sLh-ZwtX@Kzeq{UkVxzR_Y{dxKi5~XE!)0i z{Dp4Z|BY^}t&yKCfSVl27$&mxQSX;6k}Fg6F;8Q#7JK2S#eP;x7~B^QbJn`xL7mco z*)j!FBV)pPjM6|<){>7qCy=DQ!!2t{zouA-sbi* z#}T@{q;qe6dx&_8IY8YJQU-m|E1&Bc{JMa46(+jQZWxS|c)N>LmS>I^Xudl&v5u+x z0xX*R`q8Xd<&pu(jB=l`q^|e#C8}$fRsX5NbNdIBDbn8dP4FDs26zrjO|hY!N+YG6 z)mjj|2oS|r@5ocaal>6|i`}kg+c7 zu+cdde5d@AlapGEqjArfL566mej3*ZJW8UO`&-PQR}y*ieeIxcLkzpS2~P8_Y12@J z!oJDU2vb?yRz2GBCr<~x74YLTT^Y1-n77f*s}DdPNoHo!_mu1NeYD7%!^OGFG5@wiSz*XM0|g;&{iTr`LaQ zXzwzADba-&LGu9>XYB&{~!Z;LYO?$ zIk6>-1iwKTJBB&8R&pRzR`-~C0a^6y>dd|z6|FlIXq+pb`t^Y;_xIll-^5WZ-`Uwo9U2@TH<=@$fT5i^ zUkq-VK6%#RrCDD{ONbmVx<)%!rz)V|Y6-j&UR}V(H8``sdVQDARi(CLvOkyU1ki)J z3%4?7jy51W`wt$CgYiZuJA+-StA>_NHejqat;d@VmQZaZjOHfIArBi{MCBe>PyXN7g+(@=e5kcTXWWvB}|#b7PETJyTKndPYJF**~kO>c#BkrgcBEuP!w z67|dF0DF48D!ef$M>rTzjtcNI;QWcM_Fryio0BPTDd?pK%oRQ0)G1`+vdDZ|I|}o5 z<$-^xzKNd};jhZivM0`A{ZzaV^+E-1}0qhZrsk@#< zN4%PyVdDZbxE*_ir@l1Ch7k-Ez4OLZhWYDZy@ua+31p2EtWRiZFsYr$h*+li#~nfD zptWQ3ZM9*I14IiRmZ}^wZu}0@nZj<1`nG0p?_cCSc0;QuM0v=gzbW0i-I4@CBDm{D zlVs5!spba$+8c>aIETUSYiBD*KAcC`DBnm3sWkjy#p9TGaz0Bdjp?G z6bWYw6f7F5jBP1h779ChS+f6p%IRf1#S16&Yoz`5FBAh~rthbxr>WC__V#%LiWsl} z5z9UYvaiIA5f6X`2+%?=Oj)MEb|9+vZge>p8ax(X94HM}PDTLdZ2S6BX7h)V5@zx< z_W`C1O^3PSCaNFabYv2>WSlh~Ox5tjTIw#rWLem}tbz;erS8+2wq)7CPcXg=sCGv# z3zQcnaGup6pR+gHgj;ESKB@EUM1r~1D8oTS=)Pq~{boL-GaZ)VchY==WN3_!t8rwxIu z`)lJ04?hf(J<`34eggIEH}Np0A~^2u5}!LNk{6JCV>^g9wdrQ)yW~L~GK1|y zG|Q=~i=+U-@Z-3sqq-A@av_pmgr-g4g`|77xA#=)H9=m3yUr5(j(^27StAChUqxdBU8K`}KbO=;$VW*4%bG)}p z?IH{5k%E`l7cjTfzN;-pejqmu*G0(A0W08tX}kz#C(0@#$R7@XFAhuj%aYe1@|}@26rD!d>b)P`5*bD8p)? zlv763nQLmhy=acHh4hSdmK>$96P)32nW zq#8R-t=_$V5LZ?c>$ZIyhKII^U=S%jK2TGGy>rSRJ~+gR&BMh7&<$J=m?s7F70hK` zD!_si)kM?HjMNdo-`o$KAB4XG7`2#%f3^Qaj_W#gvdnc8Yyw9V`(XU8D!uGo7CQ?r z3Tf&f$M?e}I4+D0vEQc7(bVmpT%+z(mFcX6c<+=u=><4Z6{r-AcTiLAVt?agle z=2hCPZ~dp<>Lbn4_Du!3xM**lt{Icar@J=5-=f&<4iiy#Pcr`?k5DXx|4diNPM0%N zDmPUm3%HP>zqUoX|LXMvY3~Ed`ps@wrKfJ^gP9lC zSiCwt#1Z}4*oa9x6!TGc6if_JE)6|lm;=N3-N023fEsaM;2^+WP08$04oC zvR0<83e%wl3&-=dXG4@4M?aFYs-%J{%8QI3loc@+tG!B|9hT{nYy5Jg0eVDr!D_c#P-c&v8HaAgD%U^ zRDl(+OBf0|4mp7Vti<^G2bp%h$Hu7QG86t5Fg>e#HQ6Rxd2%5Jt2MjS55X)i*e3#| zt?m?p<2EK%x(Swf)tV;o@WJZ0UkCNckVv!C;roVxQZUwkLA-I9|3^X=iTkEio)L_u z{MwyW`-^>t8+*&q(UIyiO__R?6wWes!>I}~rc#1-roc3?8|@+o7*Et&-*7Jxlr9)2 z^fpI64w1L#ytW42bY@XFlX5=EuXbtP$1EtX${EaR!_f%iJ7KmL;ifO;Bvl0Bm1whU z$+pj}WQ4A|td*N@&;J_mkEPD;HjoUu1Z3W|XW!hD2FGnOZ+c#+3k-i5I)(LgSc9${ zZtp==#s4_Fy7J_=+P6G;9hS+oun(}jbkoi$Pu3U~4nT^7MHf!dM%*s&{6j|q5d z?V+yoaAjZu>UL1^*dBTCcEAMeoJZQ=f~hg^Dk?^}bk^udbz8Te*|3yztT;X2nKtP3 z`y;qy5=TV_RF4r?dImdaWbYxdU#IKRTr+}nhYV2;ixG`#{C5I=aAm$#l&vbx6b!e6 zq6_Y)SKRM`oT4s`1Z&20lOe>@67iH7fH>%{RliuIPDgg*5B;CKDb!1S^F?KM4zT8Z zLWPOOk3iTC_ zqrKB})T^Z-XDlT~8%PR@-NCg^7A*tXOe}3o}4B-WVH#2iT7+Zx!M9iivHk%!~3pfHYk_=p6k68g| z&n=~CK~^Vb+9lTJS)>C!?QCoF2JPKETuK27HU(`&aZV>PINb&Z-6}uI)1VEMuKJIb z&FUJ_s}0;9*`C9#=fB&e#f)5(FMGYO?&1J~bzBUlhQs521lHY7bnFPJnOwHuon@Yj zXG?%7NtL?edF81Cly8wua?O&8K(jArJOkFcWi~y7&r+?h=QF;J`l`e9)NtPOZsF?D zjFPFxC6YsZ>qL=k|etUaKf$=O4{foB=%=b=l@zCpjec^j$hYZ~x zJ8RGPoNOdo*Aw}*2JoJR#*N7MgW{8JnOFM*Ez*a?zeH{Xn&@UNlRwRU`hXJ=3Ld*% zBsG!shgV8N?;o=Ygu==N(?rXp>3J_{602QRG)5>^M`ZkIqz{JCtK)6Gz(BXCu}k~s zZiJO?KCb_jzp=P9M;m^CpiyEXRWV-h$-bTGJhmG_s#%Sxi&87iTm6Z=KNf9Sbk0-W zbFT1qq_+<5py}+lE=F02uQhq$_`(x<((d?8weF-WMM8s=`$P$+%{Z3$tuNkHYk5rbW-m#+M|(@dyJ>XY^X7IxbIgxp z_oiTdXE{rk{V9bd;`f{L98FP)bR@sGd2>3g>dnuoxA*}&8bo}KRGSixkou0!&anY& z=F4^uXN`WpGKXp#cx;I4Et?6N)AW4UIPA$XF{gnp$}0@p+XtYBu*{B3EE>7@^fh89^N@ zamu)CxAb+RA&zrYa|%Ba$!R6;6st&4Z9_Rw;FQCZ%ydMZjBp6tkBRQvl&XdS%4L#t zqJRUzDwb?Cg}vWa@!cWf#4gKUGgCWu&^<)5yiP{J3wMsr(pQ+SFP52pIbk=QJpPq2 zk@B!y&tpEqvDKz_fYNmv`wr)$HVgY6>NAFz$~_vs5);#|6y#wRCcNVqNhJl8n3pSG zims1u@~rqReDE#x{u%mg&iAR|01ijnD}O^AY2|pC!71NS_It_z3YR4iBdzkcGbngi zAKZ_oPvO%-R!g1Pg4cpy|8|9@2ds-aoQ$gn_daD3o$(PFlOEa#nG3>-U08Tg(#=+n zpOJQkx6hU&$$7`;Q;~Mu4Y_?%=LKlvSILPQO1ehNn(yyJvh04nCRA68!K-nc-^=Jts1WZ%H#nr`ao1ug zg&axdG0SeQfmC>`TtmGNFOnPPd^>`<6zpse@kqwn^tsmiE`{12; zFH^lr460@^LwLG4lA#7J%o`qJolOk03)063F-}~asK}KfSoQdK!j)V?t?lc#jzE~` ztgi-^x>oiYF*P_Lr&T%8^jY*VEF@ySdW?iE|603-u=n~z%2PGZ`SqF}zouM_;FBN6 zH_G0IzOdWRl^#d1{O$@L95H9A^nPON9SbTyfUCRm(i~&`{o%#c)z#uc7P-I^$NuqS z4>cq--<3JDOLt_XP*K7@-vjZ(dt!0?>vPG+=y-oqfeGSj9ObIacc!>Y=Dkx@R(JR5 zg@4CO4TT~xKXdhQ3sFl&&ZKmvuJ;rA1s{(hSs?h?r5<_wR9bRIf|}qx@^0g)Ky}+< zl#%q8n#W6Di@z#(Ed|!+Fc7)W^gF*JH%4GlePSnlgG1=%1bPhFPCXZy=Dda8xc7vu zwMqqF|NK@r_;gUhcqbY2#xTB|pzX15I_4bde{E#{XiJUV=|Yx!^h#NKDon{ms9hM$ zm}qBUsGouxH-%GNiN5!HWKBzuLb+BZARpOe6bL!(E^#OBqJc zu=-_B-F92H`%Mq~zgCwki=ydeAHeVTL&nloSb6mkdP@{M<5$eQ*P5Mowg@ea?==n5 z`HtuKy^a>PuG^`}Cm!x*p7e1~q>*BP)V!CH8=8lC%jRDFanZGGrmGeLs43_LaNjq_#{ z4HsNA^~QRQt4}G~xp~j56DgNQPv2)R=4p?tW8QjCwr9>(i`>Uo1gC7%J?^$>=kz7{^2hzxs!$x=y}5(n?kB=l8k1 z|9a;|%9juRUQb;kAz}uX1s7XuhV+n!kSr)MA$wg-@y*1aOsK*fhL)LThw%9aBGlvW zQ!JpdK9z3Pa}b|QEvbVRIq8N-x_!vun2aIpdeZ*rAkP7TUTbD`#o0b)cwr23-RBdR zn4DVOn6Er;k3=nU*NB1x6}&&uGy-YzY7~3w#u1fdUN(m#@Zepb!Cq32+ zs~|ZV#uZ+H6Qfi~`;pZZw4^Q6W;rQvbAFrXL8=U)=|^xBG^bYB5&VvfJUv?JD>KnK zHJ%PzXJ@i?cAfv_>~{R^?4Wkr>My?C_rk(UqZ&13v~U462ibui|YPOmt3E| zLP>j4=Qb4U`!-8@BPXE-g(63g{X(BAeIGUWL=y-Fbi=R?P}nlclvt2p6LgBrH!T%j z%Ul_$z**^)n_$xnx%@b(YD$(OGco$qK6JTnPTO-m#oJAMlSP{Js0rTgcHzzQ?i5nln-?9w(k}r&KMd zbe3VV6Ak3QC(u_+WeCX&R7+W^4&qJvEMz8jdo|UXs!6&MN1b7PtkKv|U}LLpwStwJ z2>`-!&a04V{T&Bcpw=B=MVFiOdwPd&{T)=; z`tBW-|Nm@yPUmkaCuPnTew!C%&UvXUh5YgxChHcgPGxIR%Y{$lY!1=rD zWKrr$pB5b#RDJ-*Kp5X!oPUAg#~aT!0oFdJa|>h4QjazPmvQLjE%vIYQ7U5BYpV;r z3Ty$k0K!p0O1`HxdA;sWkp*v5Po7eth-i9V0J|eg&$=yCt=tqp#3DLR~!D;C(hy;>{R^Ix# zq?JFLFD0#gPyA{+4sDZ6x&EM2RXmm-(0f7_e{`_}!500h%oM&-fpb;PN>jT;isSgQ z#Q>qR@^`r_gy{hJaXquFmj?sPRcg@mOf9->7an@}j$hnZ)%y{(+}0PcymkWZnV9$Gdls&K=Y$$!mKmzpf=W^53S~xrrhb?$ zg<^@IQ&!`Tj=8wPz7%Csgr~UT)e2{IT6-`tbqzP`68xh~OD{q(i|gKbhd6d89IY5W zzeFw0<{|K^$R`INg}<$TI6X51`S1<%g;Q%6w%YqAuaEv`I;<>Yi7m2f!n`d6!f}-!X9_{`%4T>xs3=93j`Nv)PL<2g;n;Z04uGk0kaU{s@(|>(V@3X?_T? zrABI2?}rCJbQV2+6Fwf_%8@LY7V94uTLw0)2_jf`^Nq?J7AW~$sE3sDfV#k02~Vi- z#NtNQ@GS404o(g_<|V=8d}+sp&7rv@q=0ljR2N8d#Bl+pO?)ACexlGDAiyDs5|VL= z!C+sWp<6kczU&TVPI_KlVyvMiYlG+U_*dkrjr9Gm*Q#I8kh@dLLNBsY=c1JFY?qaH zbG{Gm-@gyl<$;2N!k<7O^!yr)IQ*@xe-1Z0$sF{tK~&E{286Y>{hg7nB&OxpcByv@ z@3;|4?#ERm4UNV9a3j;uPjSf8#r|x`+NhMI-WvY(>7x}nJfnBz=#G0Y-X03N=MXO7 z^rn<+B?aB(v0zc5KW2lVV;A-s>IuL^&R>)$6Ul@pIN!(tvcN81!4XcWEl;5fM zZiTxO`i}B7T6i()XlF9Vu0Y%$YilnP=U;Em7h(iIW_TE>8!XeC*^ofcr6V>sAp8oO zy{uZ6d_B`laXKRQb;I>6SeCMfD?iODN>c{2O4H0VXSu1-_))AEOm%ziLe`DEotT-) zk9Vqid63hPeG4+}NY?%ve%%fD3BI1!{5<}%UWXcSLjV-~PjH}~!joW?Gyt`%+of?9O;pYXp~!D`69<~=$6Ljo}E zS0>}86;?gsE`=P7a$9XD-(*pThHnxIO33c~+iKmLNx1Va4?i8YiXhbWv`}@;E1lcz zoD-7e-km#lpryFS$M-Mv{UG^o)g=m=Rr@-Da@&@b$!GD5G;BC1MwgD>S)m5VzTo`Ex4?OA=|NdSz((8I#$4rI}S|CAjFT z1FoMhFD%$dT%=f3^nLBKW~R*egl;P4fxioAjX1I%_Kj5UPc$K=rPfP|daqI=w5y6!Ni{`f3jE$zpguW32L%A)=0l0=-gN(KOu>7y^SJMx^%(HK@@x?T>H z3wZ9-&UGSdlx)89QHcR$!*VCLGyG_Jl|egnqy}e&X%RKYe4O6CEcf9dCMG6Q8~?Dd zu%5cpAG#8VaV5mEKFfi|86#=Zj`u%D>%!zHd1qAX@X-OJ6~=Fq?kry_@P;Zw6j|+$ z>idzgZ^%2jRomtG{7EZ2mD~T8_xS+q^|k1^LWkCxWewM;Iq+1!Fgby}X^(4>nwMA_ zB}ipo7TLpTP-t!7extp2$}P0D3q&L&l}p))zop8lSR>-4OXLP5I7UB@m*!tuGq4%F z3dX%IOzCl^t zTfyt5zh27H*%4}ktu<=(9;~JonmRASZ^>qVi?Ld`$B+}aY>;o5g{2xCN%K+n;n(QA zr@ibts6F`nQUF%_y*w`}aj(|3xI*vfw$8}<#e{RFB?c>H0ck8w4%%x1udd$@g?nl` zx34tWGb*r7YBu1`dW-DS@P)3da+5P3m*8#R3|ek$Jw8hkIV5=PoVkOeF0~(gj3=o? z`mqdTRBWt}yL!~9?-^HS+)kMV|B*5e`N2g_4V~L<9x%6i>v}v<|Ied@G^^{5IN=Tn zqru}YBfCz&Q)-!dc(#MbB>l7!tEgT&4PPdNpP#gQN!JPZ9-ko^prk_W1^}pvGz}_$ zFy>UHRiVjjC#&Q=5i@_=dA4ex2X*YzG9#x=r0vEv`9J}cdNjR}mxO)yw6=8mxqvy} zbN03)!#pySPZDYLHW+;Od0p?>hMIjOR%!|ONa)#0d(Z!NoTBhWl`||6TfK)$3pDrD zf8$du5!#)d?=&tIuhyfv!-wp2H>T2A&oeOLH@#8ba^Gcw$_sOfg0!>+`r8kzpHKu| z?}Q$Ams3@U^X=G+rDniPvWAniI6^-YkSzQKI>%g>U%WkU?qQ-bTeUVd9NAb!6TskM zcBvT?GNPa|?o<`W9vwoC#%2DTf;i1hWj*o()-D4 z)Gs#I$Z&+zle9mELE>v=&JjQwp2*A5{+zANl2({*(+o>3S${#>L`lrA?rkTq3jGZl}h$~8H`DG#y$o!X6APf zbNNaTJsIn>9`n?Omfy1cYSI+e;&*SR&D^%0BFh~+ z6X4*%m>3k6Rv~vIQRYEi0oCG%F=w_7kBhP{DYtn^u(1Aj5O1g^uvSH6FJS9S6THjI zZtzV`G7!!u!hd$>c$e~&=Ft2m_7xUFx7YtO&**xKFRE|ds9TVTD80ny68}bc{x|?? zrP>aG_o$|y&f9v-1y~`GN$t)Xk_l4F7fMc(0KA61D58DDx)G4N8rOCKQ2O>djQg=! zGl;m-bBj`IFU9EM53jZ>`AvTmpGg9agzAPsH7t+=Z&TNmma6TAsk>T@T9}SC0CV=t zJ9lHKWv!=>aE&09tWs!C)tc)j4lwHic0t!LpQL|L27oNdk%d-dnQ!J5V<4xhs5r;U zsX8*W--c;c03-F^uJ2(n>5yEWzG!;R!}R(1_>KPPJZ&~mZn#V4%H+a{;h2>qz|GH0 zpP@p{yui|=lgl&oGKoQ+MOi6yVM$u;1djaFowQ30XelI47XHU4aE61Sd}({?(J9i;GZ|vRz6=zSX750cXX@SrVB+B|NA#^2C&JzQ+Sg12_O=@dpLhVq_9x$My*i<_)W!8|uCQDq=TY{6pNPu`j+2{aV%2b=@JG0e%h z3I^y#9$y1xn-(v4mtq)1SD;ju?(OFs<%daIv85$K^R$?C9%npf%sf^*A1*OUq;oE3 z6b%owDYJD;+a=Naa_${Vuw3hkY*QVlGqA;nSE z!M)#EZkoO#;JwGj##l}q%o_isB4T5M+48`_2J?^wDrNZq>KuvrQ~boD8&E$0_OdYa zn14~fS^>ms3`UWnDaI<$=!^Grbb^ic=evr)Prm(AL16PKKRLu~1VJTLgm4EJmu40o zS8T6Gvbv#?r?tW=2$ZnOLo5$@BBd@&GK68P{W^5+94~EB^fv&0Tt>}(%E>*ppEk)> zKLk>%38?EGIp@wo;BbGEll*t3-<*c<)3u^aFSY>6QzCjsMzH|+cv~wlJv$qUys>er zBiO&aG0QK1x2g$eorAu^Y=8eto5}x%e9iY08KoOk+RWI#{K-{*CyZPJ3sTwlp70UXs}pUpKH^UX&@>MyF` z<<3!1_kV%>39;KC15icd4OQ%QDR;mZ+OT|9zlFd)x}VLD2e1Q+F7xT%E0g~&MZk6a z`{xTWBpWtv5P3X%s)%sjCg|V2-Jg$d=J>B49rOD~FaMK|W)XcOAOD5d$5vN$9TW3| zd>*!#hxG^kJ)HkPw{Bh>ZD4_$rPWHusph{QyYinLTNIQ*dwRw}8T2f453E(xs`g*gV-R{`HOaJY6W3VOO_465hq}Al2w`jkOXFaL= zt|yS^b=H2%4S^ty`p$s<*dGiqxce6jxCN5a+f1Tq2_7WatbB#_wPzDvDdnXW-kJT# zvWt1rTu=RIGT$GSQxBrTxIe2b%b0?%Kdy!Kb-hD}`S}@vtKC+eBiTPev7Pzx2<$(6 zgu6pcUt1aAs)jStTZ63l;>UHCfqniz^2CDFSYLnW;^-?qUKQA{*T5IpO!CME|p+qy*#1wS(O22#Il{toLo1Z298Eur@9x6?ZhXn3x&0i<9c;?f zInOa*$|$Yo${Y)G_9EZKew*@NQDuWS|01o}N>D0eeENeB$v-Y3+xiboDS0$t;}G<* zanI3TT~_Omo&~;)gtq_n7%r@e9XN(ddEfjnVlJ8bv8*z4kdOX9lC-^NlPwHdk|FO8 zVy68QX0U#Iv{$C7suS@vm z>C>M4|HHG0^Lsq@|0%yIimc9!&F}ssHrZdA7@5`#^SW<{s87(V-0NC0i$vbT*vzv&-s#*ic3TU%`~Ws z_*%`{h!Jv*HL+i_K`>H{$xRz!eV#-4p)wI|sMc9%0$*ZsqD7KfUxIIIGTGN}7}uP} zTnWQOHpY>la5(b5)9pf9p7pSv=8``?C2*qW#=(Cg`umCrZ`_>Pk)_8y1azeYSHG3Q zcq50kBKBd^`sYrE#$+z}wOR$&Q-er8OVeTQ zE>?{zjm0HQ z_0;udUss=Xp45Ud6m(MI;Q9z!GiLn+BQCcfPBl^+r>k>TRM33V?e&mjx^!!VcU^#J zWL(*&@}T$W)ToL26w(UqaUOnry!9E0Ylh=hA*wJ_*M!WYLzkeZAV+Tr%>^m%Pfc1I zS-gX-#_0I1VI2EoMg}rQR=-)#jaW|y*Y(}DT&Mb|ulG#!wOa-TdC!Pq%PGp1X0*?w z0u(|-I8XYxqhNzh@9K_%#`ZFsr+%HWS$=-|({W29v?r4-#fOL|h~kA)Jr^?LlUj(6 zTVSEg4+pEGanG1DXTJ79OID>X%~^hvn$^(BTm2SW2`Pk3>7vGrz7S0d9EYP8h?SP6 zwGpej`omwX@vYW#X(R2}ktJPrCZ^FtWww#=oBJL6LR()-EOWaj&r%~hLzv-cM3%|K z`K137Blxp3gak%iCRB{3h$7q;_iNWtVxxptYO4we&2LXj;jS5RF0c5M(Z%N2X4a}+ zLjs}mvps@hv;2E8I^6T^HhF6WFKV%UqsZ;axS!C-=har$RMop(1y_8B2j16xO7iBD zpygws499yloGs167j>kp@8~+6` zr`~%eskVstRnbD*useGB?rMEoVPO4=z=@!$v+UTucJzV8m!`?mfE_Mgy-V}D-o8!w z`yZQmJkAZradW&5l{!IWC$D8{j<=1>zb2VhqKTzy5_F4vUv!n=l9&m@^}e+Wu5^5H zacFdeRB63ps@c&(MJ%eVJfCbFea@IAM~j#Ix2R`dKL;}F>r4Q1l3qIUC6N>|R*&)o zWjLWwX)&Vs4bVEGC3s?F7sA5oA{AIj)UG_mB*jGG?rpHh%gZ!rl@DBvT zMqzErctm=DO1hvZJ8BQJ(V!#8GImvDUbzmxY?Jum>05$p9+$LeEsrg3lrW6^DY^&V z=n*gY%x&zx3&c#6?j}jkaN$pqSdEqMv1pzNnD(V!xPMo>aJ0gju`-NUG%(ss#_~E5JjOTOyYdilFo3zKV-yZedai?jq0N7fgosN6|gq{ZP{H;oC0# zshIWe+3#_XZk@UXviB*42q#{>98(PO6!uS0b;a>9d=oopt%g*A3I+^ODrMz1~SM!I$gf-c-s_+qXa(Pg4*$s6u)o3Rq?ZND^kRfT>k?2OqUx*CTh8;v+<34T$Le5g{{ zPUJlz?mQMwiqu%`u#gb+6rR5Pe0A#NUCfY{a$Q`BW{2)DZel7o8b|68PdvAOy!T)s zp;esTts<|CU=A&sA=I28>z0$~E3`~umJLy?$S5T2IYINxDqOF(#R!GZ1Z)k$5?s61 zn((;N=gdQI2(Hc{{!!g+3r4&?|NQ12;O5c(KyR-2HL&ijLOT&hBitW&^d_>5H)g={ zYmsMHg!eriKWEkfr#rX`iT)v;3KdY|h3?Wn3J4oNU2Iiix z_lY}zv)F|l3(B=oCrFx)N&`a^GEFH|*#^X~bfmU! zblY3$<-?`CE??l=wyFPJNE*@WGEwsmWJcI>;jg98XiC0kDes4wq#L2MJ%)?mee_+A zp@?dg%1GHkzVUgZ+$?bHaR`s|A?xm$IyRm~uZh{Bx@WLUeri6Z3|E2LS*63w5ZTs# zvi{DlZW{eMM6wt_#PTAD|B^bxF0mQIvcW zV?ow^-vJDW=3EykcyN5HX>#*iif7f~wS$v0AG(#AtEkXnL9d@6@_1zxO`k;s`ne8u zTi(rn;U4q5j}@yc`A``r-W&`&FeEpluy<(WAO^_F;zR2NE-jB4)<1HQMulHzSLbG? zKqrSq4AgAV=p$V9NI%DReb6JGtxJ?9T3&U6$Z~=aT2GLVA^-S(`gLHC!#wE*fx&uk zduFbC*-=v79U!~wS(ds4gFss~`SlV|y;Gff6`D3_t5*K*^ZPaP;ac;$M3|c2bwj2| z*fw zifn3$8R-KCLTK#{Wg{>cGyv_YRf*%%b3Q0b>gZzRxG z)l%MH<^K$0ZAQ17$nz6GAwf_g6e>ZOY0f?X-$)CVik^XqcM*0Xa>2VDgkiAM)SSk5 zmNV3qk!t`dD2tz-UA*oxf(2$bO*E{Q0F@jQmqEJT_eM=zN2oM3Kl!LM^AoJ)(K<2K zrtO}5oCo5%H2jDY8*waH z2eQP*TLg_r#kJ(h^mD9DYR0Hs>-(LRZ~Hmwcu=aw^n^(0HaP(A$e(LFK$XP+g(?orjm)3)20a+wRk)SqnVHTYB>{3# zSk!h;b%a_sG`aRVS4-&H*r5q$piQmFcX(G=^%;&TtISVh^-#*m^@|u83N+VZ8jJo4`0o8FRk@5 z9{~IbS&GJAq5bf`tm8})zKSm#HUhm8q_~^UifkgaXoaYwg7Fdbuq~d|aZV^XU<~?8 zPuDf~L{&!>GFOhdMHNj)inB#=Nk8_p>F0o0V;(*{_IDVu20->xUi5Pi#v?giUF=`{ zL?@QwB1uV+)wQ?!yGQ&fM+c~{X-+arrALWB!xpN&&A`4ekE&T3K~)h;^$!_UVU}!nf$+ucr!+BYNs@vqS2Z|gtzmc2=lH2J;Wcm7 z)XEzlGvm#zcY5BjPmDcAcbQTW@cE)!8C5|H0mN?2W3-UyXV~XKSoCzv8q7Z&gpO0G zZrG&iy$fyLb?QdDy`NhsT1XBGvjGbE9J6P5+clsf=uvhZC|l+eUDWd=Vq&ecx!Z(7 zT;s{lcEP)+zmktuJuym0-HBP62L_^++mDX6lhj4sqkV(gz%0RN0!qtccGIZF?5!yG zforCYGSi`{<_OSXm=d?8hY^Sys60p4CSB6Ie;YwD!ZMg~eqC`MpO|tMlY+{0X7JUo zb3&6`>kMf3GgF#JH68f%wb#Xt7t(uOdKbn?mc79iR8yNLWc3ST0@aPE8~Ww_Pjy?3GID!k&zJDM}TKd07*>t`2;lXw2R0w_%|DtZ}@c>qUq_`Kwu&@}8mICNzj zsvNoY0xhZy4W7U6YB$=t5OOs+X*}cna1&lI(p+@WuY4pJ zaYY*OM#G4|ituKkj-k^1P4Mm<)z3u_H%mp__g-Jo3^^-L%WUu2jUK}<-!*OlZH(az zhTgntW2Lh3Sy_9e(76f;kc>IZnUmF3`dl1TexUs4jJUH5CDJ+m=~5 zYaQg8Dso#XsLv#kFO}5)D>k>0W4xXT$ZcA^Opz*lxROxaT$_YX*nJtdeZZru z53X7}v`>c%a7OhDzXYb`?h5BtNyLdh#LG?)-#YRozD7z^9H6-NRNQ~F(@24qutvzo zIcrr|29pDaXydA3vDo+RD3$L1yXSknv?d6I0uOf!5Np%DS`&&OFX&`?m0;P@%?OJL z8IWg4B0s~c<9vIQR}5CJpx;i+#T<58tGQ6n-24`gZWIby+@@3|1A1#rsd-6^U4C|# z7w;Lh4i8>?>%wmd+L@X6X3CC>3uuNmYOB;SMf(kCgHqG|szTrzHMWAHONjb?u;2~*ddyL78_ASb`=EAPvqV9T&;3wdS!!@EDfm}b~=dAYOIH~d|V&g zG1*^ovxV{jr7bm6H`k_z5ak(evjP_Q>{2NyFBwWdGRMv=&$UDxI{A7V#|7|`r~1(B zLW=ZgDx%(#Ap>L47({pxcXb}Ci1wguukLNWHpXIqr80i8R;e`b3Q}OX$fVyzV+N7= zomwE>8*ImgRuj3&FMIkH9I}%i9tKyrkD5SLwN7`|lYDQJt&DU^d5>KEZ$YlA8Vo`% zT^+1~ArQA6*G=D<8*u=>4_wdLZwM@8KEyvc>R^~Pb0}ERpD{FB)Hb*cRGe2+)mDz1 zi~0+!PEdgQ(XljSpPfaKdO*WG&*W ze{kJ5T9EgHxH3AEL|8){FrYG-OpOy?(`%sdhw6t>djYIy#&9RiRdBHhaFj=A7 zne4JF1N>C<+ark|T-`J(&qRs1c{ev zzJ2S?`x6z&g%g#sPPFAY)tOY>oFgFA-6BA!6%Bdg#*=g#5vvPkOYu!EPo7slkHJzc zadOxFvcT0(^c>yw#pUIIIG6}fDKl$mZjhQSItk-(A)RjpYZjFR73zIWxmtSJKo^( zD^9qQkN-DJ!{s%w?eS}NFWoMda+8M0yB8RTc&86n^>Rz*M5l{+l90AzCGI}VlH8MS z5z|IOwofbNjyg{+ZaGtSW#4ngoA3^!wE0723UxP+DBorn?VtKe{Fczk1}L-7uj$3e zYFtgHgz#FUf!>FJN2mhWS7lwV;-8_`kclhk%&D^av$jFh&T^4uRZ!EBZYf*BNETF6 z#KUIyoV+V+39kux*o$(jCPvR8tRdHCqq9jn%<(IlH3>(_o=^zi_XUvxPV5uGTgju4gnSOSoLTl?WGbET*!NhNdeaq+-sJ5 z&I}W%VC(2l)>r?uD+CP2{Z1M1*B-Ea82qIH_Ccm(WV4denlasn2_|*1 zgg0~N+EPup6o@IrLSAZ15M07-2qv9PJWLbbYmu~Pm3Ht@lgpQzFE3-#XlFV}y;VFi zX;BVkm-T12Nm=~1uKwZaFBdube;GJlcm1Hagqb`2`osk-Vc1Q@9{M}>dsoN7GURhZ zqG?L%s<|ds492dD{Jxs*=Q5JFCaD;i&+V_yS$U?OI}hfj#eaHoG%v50VTP>-SH2rn zQes)Zl6BgFas^A;L3fQ(%D$|iPxTE{JdSyIzo79hWMWE5#Nj+W@~Z5zWv!0EOQ2FJ zVuYDwg(U*D^nazy4s-s4?QUI4cAswm8TDs0NrgN-4*&Tsmy zmyPqg+_Zp|iJ@5!pQuWoBc2De$*~FUa_Ekm>n>A+Z#!Z|4dnkrN`CsOcVj5w_y6+X z-R3Ugi(sge+HW?HL^Ek+qZuFcn%>t8!y8~AxVe~#zL|P(i#}l0o{V1xylvDK)TH?w zPP=mb+Tzl?^ay+|5(Re}?Bn1b;}_K1j=FENwq5rz8;`=m(}#-3&rQwqa!YyEB@D{N z6kQ@5jyRjalyQ7ZsPF|_esin!``Vj?qE%W(==;MX`3Cs0+)JpHoMX%w3w3&Rv%kSA zm|<)6usHWgx9VBZMKC;M>}VIN`9ojA{p#tEAVbYKLOAn9d^tZ&I#B8{REnPjHWk!Y z%Yd=1IIe+T4=lel$iI($c-{u`rG~K^eU_L91IG3IXEN9C@6fOa@dixz|ARyi0o6du z%p)*M3mvD40_b#4!U11xz>gTNV&E8tcemM$LgC;xPTR# z@iq%F=aI|MewMq{lueoj_Hr8yo#8$jM7A7*ezQk(CPhETb5O(jwJxE|N;~T~>sa1t z7|&sEc)wf+HMdTB2pFmo2O}Pzb1MDc-1YlH-u7`V)jcAgYcg-}LU+0pMuPF|M#vmH zb6ZaZd)AUO5$R+8iuI!TYCdKoK3}e$4(n>e3;L1QlJvuY0O}=Tm!D9tall z9xeq(aKO5HP0j9a&n`*U<81LuH&ZBKXobO^S?BZ>e59G(&8S(jZ|7WA?H$|J9gFAS zFikhdE7m7R8f7U{49bzJHd66JCDi1-@e9Y=@r%wZQI#7wNyut*iFQ$rZY%?`P}(NG z@2~@o*b&%0z5_dU@G~;4_#+ADD~$ZUxX8yJox0#y@3ujU0X}ZYv+ke%cUnk; z^}mH#alG3$-40l1lACw4Se8w9nXC(%wvZ$pAUC^s&S0y&3+$$gf6G*^W?K&@9I42cAVbaas*U^lp5+sUaY=Ie-(Hx`3%7uHm;u6OOE>dboZ0J1ThDzd@A` z*)2s7G7Ed6oqeq4##_=*i@hzmvjnWKOO6y>P!LL8velhoP(LLK5|wYR(%%jv4oh{H zJ`PaL;AQ)X-6x;i!)-2KoaeI=_=%U9jG@#K1eM7hh!rPOD%07-dnLwT#hFQdYCfH; z&72kVwiguWM!^?b*Gk#VGrrGe{%LE_h85e48)FH39C+l;4BTZLD9?`mi024oikb9< zY>BS;632;*B)l2F*Jd-58>Vm(f1|D2J`=Y>7MKT7Tvu&-)4Ao4r6S0vrfpAvbS`uHeUoegV3pLNhx)G_b^+9b~p{$r?k!zNBqha%#@=n-2S&~A&QrbZpWNq zDvGNeyEQ1THLyAPYjCPSaSXD#MIa08SiatNNA$BnxAGWf*%{;xUtTb7{}=_dVY?|{ zWue0Tg)q6uh)hEpi)wbQXD6A{K`$g{h-L>{ z4nVPp)+v#Xuk)DrG9-SBImVF3#?Qp$&D+I!UD2>{NTTv!dsp9d=h&~EzGL+dn+%B6 z@hh{xNop~1+J@pbZQY$^?90i;Np5tfrPP^jmqki2!KLg#$AU7)V!-m!ZR?NjwY#z; zUNtX3u)`ktQ-uh{Beg=VUWe{;P{g3>R1E1<EUEEHc)dc!@1+d}#MYJAJE|0y$gt$@wEaDRPqTsQNO(;^_E zMtpHZPB`P<)2^s2s2|x@x@BRI{CV(&Bz<-Ey;nx7c;UUHo=VGrebdayILgpa;j_w^ z0M1NG{Wc_Fo3Ns8K1!wIJzJK2=eaE^5@c!`(0_~ge2IY~r)VJ9oQ*1WPzSV_`!egCzEA%EyO4>6-gEyCON z^FTO1UNOmT%quG!l!wO7tPO=Ieh;A3O8xM)Yiz zqYg^i`8;MYvvBq)>~lp9^R;_rUqKb-P-NjFwhG7XMOYLe|2L>{`7U;JiOOTkBHkU% z!Ig(+&U$-9Vkl7Q%AW~cMI4bU;bcYA@zb8M!%L(9WnB%Na1K#WURn%o3)wkWyi*#t z^Loe0iXz@eD=B_2&n@PGErIpbi(rKJP>-6jU5H{LTKO8DLshapPX+CQH6{M1JlGJZ z@$m5>Kz_5Eqm3Z2xNU+Yx9Vb`68Vyqdk#~i4%Fl{$0RrEY7x!fd`j28=|QBd7l>04 zI|z1IFZGc0yE+0&bC-E90uvBZR=HHIy2Di4jx{y@)T^ReQ$H`lr=1U4lKYUdEWypbV6e)CFa**KHB+WSYI}*8pCpFuJBBE+aODi^oNa)+xI&jn=1P#XZ{J( z{`8`Av-QiLOUX+PzE_L81TMY%_Qlv?P1U6Z|w9X4~PSx6ThV*i! z*p81L(`fwd+kM|;LbwQ{w@U|U}oJ0%`p$D`Yo6g?Gog2nU8K#E86 zr01L_?>VgSwRu;FBDL#+*0Kdi?`T?ZK0NZ|2$_)1X2$f*s0z^)pn1Q6eZdPnYBn&p zfX6)MXDVQUz`sq%J0~;m}`)MXhBkQVY|s#(4jo}L$P7_QxzG=w;v zA4Dnw=9=fu#(-Q%d_i}hXiBYEzY99o|2IM>rp$ z{>P7-j{q1l;)-!`iS>A0MC%hhMSFwsQGvQKjJ`OJOWqfS8B$OoR5}Xs=8m63e}$AS z?~`mhL`YSQ;9&3YJ%nZeX$N56Vetg0w{L8=Ruv@-lb}Rlh5uZza6BtW;imTt0wS0MZ zlkAAaeH;RWZJ&#HIjfEkqC$6jmVNuG)eb4h5WGfXIC%#>!*tojI;}6vH+#8p9ly7X z-akWGeNk`Xgzf(=Gp&rcD(NU%8Q4$&7Wk;QUJG7hfBxJ6r&i4TP*eFBzoiV8LqZTt zSgdFt&oLFc9%VAr!F`#rAV?WtVH1rE-I%L=eILWpbVimdhcNU6E_TJlzWBw*Vr$ zOn@%>C{UC7u2!(iU4<# zpY-hh21+DIM6Drqz}-usi|`}^KhO6ui&q0*Iede(o=M{kcC+^o=BXyd{Qw27{tHHO z)COYq<+(r(e1v~V{hfC15o;DkQhh#<_#{^qq}P#>?PPxOLz2wvlQV5@^{)``yx=vD zf4RP`K1wM#2HAeMSbVe_mbu*iK7n1Sa!X`+`*?OgsnpdnH`~s{^Wo4)qB->OMwX9Z=(TuaZ!_*771oQ~(wH>0wHbhvw zkasIs475AM8f9^JeV@7m-aH}5v-8DZByq2wVth5c+LC0`@|UJw1gxoNZy%N|FgKW7 zY7*Q6$@>kg1SzANgxSTJ8{G4-Q^H*E+U;J4OWQ_~d$J?(S0nE*uX|iC0Cb5w<(rds zZRkw?++~JUdk5oKkY&*+uWscjADmt9+v$_Us9f}b!Rl+W!r9Rmb7yaS*k4rAUM9gg z+W=t4>qpniVfAt-kH~^YY`vUinrxj!;-fw-f{8vDjog`e1#*R%?%VqaE|lsvHamy z+iXDdJp$wTCH$qQoB%H-@QtU%u>_ zCne)|&-QgB+EE*(+k1ZQYdxk+zA*KSjdpU0_V-ugeiHfjYM2anR{n7NaA!cg0aa;f z97izTQs?poaVaG1sbQa?6Hc`VSZ7r+Q;PAgMf1jOFZ#L;OV4ic$8)5^w1^T?a;L0p zBn^9f(#-8`wA5B(lOx09UEDj8AK=^`d~-2l&E=Q@ExLFdRBbj?U`=c` z&=SH@fB>ndXPE%6e&(%W?xP)+QC^q@cn~hguhegjJ3u&i>8j2N)A+$39WN>W%li!-TOU8yt6}UO|H&`lXD}|+IyaRb)WrFrh9Se z_atpM4uBhyhDo&_Yg@Flj?KM*t~-C;4Hk#z#~=$G=9hgH$XZSZ8~UBH*BW25A1jL zZTwV#XO(=r41@{miX7&h(tx*uti_&(emxkZb9TT>mqigFVWv zH}Sr9j>{~@!eg6Crg;=RLXjtA3mI!y*E#`2rufao?lSGutS65KEDSJFt`{<5D8A*G z(mNDBv8g|n|C9lbPH9Eiw)c%LC)O&u2anmUB{or)vfNj)L9ATkpK^$8&JJs0>aH^0 zu&66Qw4t42zNbUsB@~}3$qpyeN+O)uF-50&J{q{nAAg0|?o!1;v@BFz^@UqefbtHK z1U7=@^O2jIYgiSO#|0qjsdRm^ zRrJmLo}rdadgitq!*kG>hgG=D@~Lh;E4LleTMX#7lEp@)vY#JRa0TdcM7J)PD2OD* zr&FiY5c$M0;1xZ2#fDCIn#>&nav+Vl0HcL$xvr(0*=QL*l6xlMQUdY06}^x%=yJEN z8szA?eV~$|?R&K{rsSr=U6%cb=6m%($fa`@?}1?{H#Lt%^7CVzmZlG}fN>j8 zSqJ#FtA#A=Q7%`|t-FvB=t+9&!4O76{~t8@a)| z<#?lumnVa}BdJmt#O>4&+#SE1QMS2n&OQaN$HdI!@uf)oLmR{7Gf~S;TIZ5S`3LM@ z!t6#r^oC7zp~C%QSP7{~@G&e+J=r>r${szbv)QpQ53CU2_Hh;(uqum5nLp&=jhhHx z*PIbPiA-LLBBmO+0&nf{JeXTiC1X*rs3YY)*go8%riHoxaq&x_#lDc&9tIVDTwZ8` ztE{lEUL8jwWZqBOujyhSef&;kaf$USqVy)uwp8R;2N8x?J@WGQc&fIJ( zpp+hg(lX8Iw_~&eAK9|Tg`Rc1H!`+$GFsAdcD-_+FlJ~Lj``nja|h=qQS5!g!)88b7^bWC@F6hGJdD_0H%VNRD2aU&=XJ%ezyi zkoUJ3LMy;NJ4E5eK3^wn^{MfZ$>Q`MWQ^)! zY@B1*3&6b}5RS&BKhoHFBe?2d%}@s=zgr`UQ>27D`x&N5kakvUJ4g#B1l!p?{mPO! zIqpK-je@&9){jm5w;1&JT=EYKt3Z6Si3f!P@32SyCK88m>6}$xXE`tBmez1nB}@+^ zySP~KyMJ+Pys`cL?t%HHV{JyT$}VCVl9rJ*lTZ_*&bP)<0J$5lWPKI{xnbM0sFUUlBL72>JbT=)E^*x3q+u)nK}24YmBs(31UKYN zdZt1BhrH?}N?2*KIp{^W>Y&iYSPnjC=!sYsgv%pBscob)F^6xSwOtwviB1XMwrltD zXsn9QglMkfwHON?W@q2|xz_kV&-(GE)wIqC?@ZZKCtzRc!iqkaM6R&!JbZ)1`#Ey; z(@N1Nv3r*40XdyNRhC1p z7;EuOs0OrqnVYFoJowh}ZjN@t(u)cQu+At}pO zzjo36!Fs2{_1+2nZPn)6a%cOc&_1Id@-jIs-5uaFQ_)yy^nSu%RCJ-2BM63%74`7R zi=sV&Gv#sY=Zk|J9S@dSBT+R+zjppAj1js8stjs863VtJG(8jbB?C5IyVp)S#>HJX zxOgq=co&owZoPq>u(?fAfzTZb7{i5Rg&`9F3NH8vH*Yx7|I6?la~yKHHB4DlUqTu% z3)d)?lWMPZO9oOvubKn?dbp9JQ>Z01#=S$~XIQ^iJ=hES3{x{HDcYUWY?XTCnd0M? zby=SWBlsllN=Z|Nnw{QZSwLf@p=AvtSE334!i{a(-RP-U@+h;w(VNTo5MCG05f}Vn z*R_iVj*XVjM{*x7r8dQ8?zoyuxiPuiWhsQu3Cqw-QMB9S30*OpNy$Kiiw0Uy!HV(bRpun^Lb9}r*OI=ev7Zd~qC;0E*p40?+_Vub)pW9t(D+aUM zdv2C*xxww?{MrfbFr`U1V#9fh)wXk{A>Dhk@nuzdC(tXoJca5Pn-kLqZxG*t0;Q`3 zUCPz^##PX7#&TjzM`pPxL&tLEs!vO_Uu}Q+&HmE9D~6$92wscg;AaxcP|F&|SY$HG zG1V{-Y(?T)ER4n$F7j;z#eje3kNyi_k_uL9&KY%~v&r6LVLtl}K|5UgSWb#osxXo7 zhVjbH=~fVR8b#ZwiT3pKK>>t!P9pw}?^PS(_%~&+`_~T7(_Hi--2umG>z3G`9>4e@ z6V4^q-{|N!Ab%whUmCneUrIpHGDgElbqb6W@;*g@h`qouKp>dX>=TD+dZz zYn=cv_ynE&@@1k-dVIHSC+wYgZ2o7cScVWrNFKzT5G|ve>8M)IWp{bOfjw)^OQRcHPfB05s}0(A8e;a$rD;(cWtUe2HGkoS}-MzY4g~d>EP8aMfu(4AoV&N96&!QucAew=8j~*_K z#~rOR%Ea+F`>8*si`|cT=V z-M0YLfbRTQZkI*5;kcQnejx1#TShORC>IJL1u%`Mn(_lvSD3HNSy+u$(gKE%{Wlod z9ZnkXm>>%cTeAiA`Y7IU1lw`U?Kd#HrW(ajHlH%{i6B&aNWqilSE2d~Vfof>R~?jl zK-|kMa{!L@{F0p=Tx!%XZVpOVgUwzo9tB@ij-lJq^$&m*$KfDlG@?G*bx8~L^a_{? z9h6IdZkrr~qk9+}l&$P*(f6mr(RC$H&*E3|qK2%sWPd?p`{wSxlvTO3O6tcgrOBi@RCGr%2hF*Z! z=g8XP+O&-cti0=%;ZLByspMdAK>V*t35g?L(DS&QKZg^WTOp6m=hcH&#f zLl^;pf%aD||Ebl@-vI3KFL8a>4E$oDmL-8d)9F;0!RT5 zK-hpX7eaaVul`zc0eXE@G7lj_@Q*o~vx1H;PJ`x&ShmAcw93N=mPeB%KN|l)JdYp! zBcV911Fw;0`{-c^T79~({o#@ zy%KAu+xLp_pSfPhJCf;)rgppLzJCo;LO$Q?KBlDyOeQvC6|iNFVWcb1;haC6n`~kY zxtgmgos0G9;Xae15So)})JR-g0O`|T_CAA}?;f{a7$fFPtKtg~XEfr>Xd^DQEpc2r zz&AL~6=Kpdy?N%cp1M_n6yuRw9u|hsRmUB3d^Q;fq3p!8M>9Ph>n&M;{LZ)e?obs~ zCMmbl36WpS#lJexrPfl6khV7Sf>%dWbI=Z^Vk*uHx)t#g~ z_)XjD!?mZNsYcJTWH!#dE>{J4Cl-?H%J&2Kc?veF0^Qo|v3X87WngI~KX%0G;o7Ug zM+X~0Tg#`Zv2eSgn!JL3OQou6_>UwROWgt*B@>;0mDZr=t*kE7)d4z^GGz+Ctdni&3p9^?4 z(Qa9HoDAJhQIeY3WE-m`%iorbz|0356j2~wYb6yelKl`W=5%{(>>S3BEVg<76weNh?i+-g4c9+5 zU0$j!`dlwFHNusMHah6t+TQxkwLZ01NE?`5H047z(Qr3UyL%47|FL}NUwNlXpkcp! zFn0>87Z=V64SB6-#UZc%N7$FgL%qLmpVOui+ECe&N)pO8c1e$rCGd}lr-Pe8H_vet^t&}2w z&5B!eSP|Ky7i{g!J?XO6_*NGWW&am_?_Wtz6m*nsrRw%WlpTyoP=HtkRpR)|gHz(M zjK_nu=<<&DWLJ$)+vN35Ne?;WPa|Pr8V+Nz>Z|l?r>KgHl}vwRPJx8NYq7N{hvdz| zyaSdkA%kX``v`dNtPI-7<;L2$cMoJe-X_RxBnA;o>#kd2Yf0&sE7R=>R#y^ohiIz0 zkJk^0j^A6ss5VJmI>>qdyEI9nIRSI*aqR1|5Z)~RJK&l|@*DE}2S$;q5??_C#f2wd zi^a`;*Q;Q7r?wc`#WMfQ_Cw9Wv8s%Sdro6VwFahK^qWHRl<}jHD+)+gp3XhgrxKuk zG02Y=pu&27Gi6EHwZibwD$pTw(DYk^arA6zulrKXjPbL9QQ1eBWU)_ic00%(UeXxn z5~xK_N}r>|f#xYF3V^{znUFl(mgz~eqf{*+MZ5b=nN7wBjl$sr)g+*~!RAcRN5dcz zAtgk4;0eJq<@;^HvScF- zvWMuX*kL8iWs}n1(!>viq;>)w`Ln6kI{X#4&UXy!C19;(J3Ax?w8GujE>sfQ99It8 z=Wk{@`gI^x|Ef{#nfp2t2Y7GmIcg&-_yF(OJA3a1V!x>fgE<6c{OHmXLLCkAtaJHx?jfz1?#LG_Z+bW)xwwQXrRIyc zYJH0P;N_^(K*>afcYpj5^8Ub9Ax}&o_d}(?w$$Q9OzcG$=uvUBQRlgy1#d8Npjt6z*v(6M!RBZaCS$o*?6ij(>-E6ln>;Ov&`oyp>t zETKk{UXJxSc4S<|#(Sc6HImOz%pU<4E0?GMLa=via}pXJH8q)%(fMC*4PB3Q10(87 zL87#Z1Mp1SpPP&L?qQL!vE?kk>%+r_=jQJh8o8OYQQA#)COI} zpptdBs}c*~L)*9P_phGkPX!ckMV3PB zIB8E6OL{jlRI$1X2N$tO1bvjSX>qb@s6u{*MOL4VqK(7QNOgcxCX#Fc0mZ&Ups~N@ zMWU}M_fCWGP?{ifl;P8}g9V#ugA;3;2XI`Wr(;vfh-yV|xm>@qiv=NfOJ?k5H^cUk zPFBxcul)2m1vR6hymJYU;16Wm-%&ZKx=fo?OM%_|aZPV+xelPG=aZo$_mveWa#6Q& zs9)d$2Q6h)@2uX0+zD#_^P6l4=u3)hTkI*m>7o;-#*p4wZfDb%BZT>m{cr0QK+*AD ze8I%oTXPFD`AL=G)$^oeKGu&{2-i-I{G+giXFv|J4N{uWTaccBDDOt67@r4D2V#_@EwWsfe@4nnBE-p+PFXA8m*k8gPGgGT#UB}H$ zqni5$3R&3occjT<{U99;=vXZBxZkITtgemC*@-sBNh@g`_`?r?^vA6;qtY)HT!Tpy z@Z!4ZxwN51l8C-i#Y8vU4r-Ic&D6LVX)99`JQN~KIu0@SpoEpHdIF&%7n`c88^Lsz z&X$-Z1i1?u**?TIT-3@`50!69lF>kI)Y)8siF{#PqViq+>jvH52HonAQoBIw2v+St zOLyF}jDTEWp>l?GKSfq^cX9=p0ls^P5!ANlluzpf=6U_E0K(Y<1i$X$N7u|dhJ~Q6 z@X@gar@dVYA=~Nx;!rUz^xAKYZ5-^zUP-VMBpG#5xYP+!% zSTOZt;V?ZNJ#yo-@W)pGbW5OF?*pm1JruIH)WAMIcZnC;!L`&dC}2jr>nL#Pt|1=a zbARmjIoXA-;KtY9dzD!a%R>f=;`sS~T>D)IbpiOKvx^Q6&eV~IQP&DzRQ00;Vx#E2 zh2;-Rbhme(7=U(#@}zG)_e^-f_vY*;80}L1M}OEw^SuD~^xK7)0eo7-Aj zA$z{Wtko|lPkB^`5?CCyV>SGo-LG%$8r8ej@9>~%{+b%LJjA?uIJ4jV!H{cd8sQ2D zXs8qw`!B6ZCahhnECCB8j-wUhlkGkq4eVYv0I2tR?{rHI$M3Cib*K51 zzxxeBKPhVlc|1_VtT8VqatAi!SS}RPPF$YP$gti3l`J z?Nf7Nopo}l4Zc{c5D1-jEd{O^N>q&3;w>s3QedctE@_eGcI zJa(giNz!jl!Za!#ISoF<@HRN6wZXTuLjRRfk_7v_1%=u@Z7UU-TG6axJ~ANSj^f$Q z#e3qgJ;ug+<26sf;O5ivdVIhasSc0loz>IhakV%xz~H+a*0u~j4jn8ZVs=vkdl3b? zF20p{6KoR=M4BvM#cJ~d1A|<6tfJh}2EZABMWX9C>Fq%uJgGJ97cz+e@Gt|hb zx0oqvQTF(?;QO;TAb|KoiC?vFPpzA1A_IOA%`S6DqF{9QgKi1Sedei#H>*%$MD?|* zYY!yqAQrK`fKZZ$ra9``M?9oP*|Bl0A0O;yRfK{qlzPS}9k-$!-$S$weL4U;kdverq_AVu19hGD+CVXzdP|?QT z(hj>4_aYusH@Zcqs8GRzDwL6&Sm?3(xi44nZ8%n-l`X+D5lTq$L!1>&%+C8Y5in_m z5Za()&CDkY@SYdE^ySQL6UbFitr6FcM>_9348v+FK6oJO@nk2%91!}IUgI@gS?*(F=#CwsGw01z&_!lz#PnO~Yu=_@9&0+~lYC1t}E=v%3dc-93 z;Ag@2iW0bIwVmqePV~4p0Oeu}>U+A#a%viLFbOFhOCPU z#FBI6dth)9>XZMc%(8trvMuSR!@Lizc!*o=vQN3+ZxZ0g9{>;ac`^3|{%NUL$L5CJ z)3yb9f>Y0-|4Gqnj)uJK*lSN4mv5oRA4O#hcRbSKzrUQFj4g?g2PABmI{Gu!pv?)M z>pf1haFu3^9#%JUZjJIoIVO2oaW#%6Rgmc+NBy81Xo$6aIv*{jZJY(t5iYcm$7B7` z{EhwkJx!Xd6%M)?(}$n;2g8r?1L*p~Csfaz~=Gsvkm`meW`(oX$CYMhy&vP!l<@3GWp>DfCJGcg?LaBWfm zZK-ZE_@*ekC@C#TzMPZCzcetQyhna+_-HM=BO?N7HD|d#Y|_pp>60Hwi8}-U=fi;o zUvj+M{^_us`IyMBNbrg#S-p46uXYO$2X$6kI)$28G&2WO=Xp&zs9#I5-m;ANZ$b6p zGw!sw7IFHUPs+FsL$oX{|1Z2`(FkKVM?OReSf@tV91gV%9ml zdg@mn$rM6pLEhJAPS_M1N-JD+GIhsgwE0-1s-ueEvmE|V{QYW%E?4rr;GMjlnJ6Gq zRU8c+Rb>|BqlZbL$EQO8AwMN+h6p?Sf_u7O>A{(f}Emigc)C(HO+2fSZ3|w{6$%H%K zKxnx<(e~Ha*EApNi_41_#=Oh?x44qQ?EuP+&w+SGNqLcPbO0}Op>qf{bwK*-0TvK$ zrr#P8?ShyXe+&(M>M4FzJ;z-Xw|sQy_Ss8k9=s#WRgO$PU|?(4QfGSP?gC`kV1gBv z-yW`Tn4q)Ui1Xh6;3$f)zl`S8E@A;g;xl=?Hr@h)>eM!kWq{*chpM#Hc^xo4`Lde# zC30wx@8sGxxx}OSUIeaWwk0jQBd=cicX*My(31z2%%?BE274MEXIC3*(n4`dl$*w0 zmxxT(KIEdcZ6SsU6=(S=i>C?aCPCgS%d1cG0IM|Wd10$4>Q3vHhKQXms@Pu}W}VNX zu^sQIf2KbnYEk@&$jJ37;qBmPU^|s{)J&fcjv^ndPrQQq|m}rf_1P;oaMGD7)8z z-9*49U3_DIpj`L)X!26Op@{S-xS=A&yKe&md$#>{AmY@eMdZI}EWgxse8JgP6gXh@ zlZ(DGq{hF85`o6_2F~-5i}Pm3COtL=uuWOE9}~2g#nBSOYgOC}6$ORZH1?0BgU8*w zO19gpLbXbS9do`!-gNzd;1GFU-Y;b)=PX|cei2d@W8VDzaqZrA-*qRt<1DJ$Jx|;QbS!INNEOS=jU3f&&F|ERILtz5XOs{t9UG9B+X~HiNWLLcw5nZ_1z|4oI#j zwEB7W;e*r^*y!Y#hGHzVRlZL^9^IWu03r6@bUE^EM$k6c1;zxkJ)lLT-xvluF2I9Z z&!E6aKYZ;QnAVex-HZB|;+WYpi58E1t^vvA33vY142Mj=E?YwD%zc~h55YDfL{Jd5 zyjW3-!B54c1|))!FNmP436`O#kuDAK8GW)6sAGY`~WAi%giy4BM!jvGe!# zFJf79|HdQWtlvhDGR0Ol@)@Z`|XI znE>*muI0CVx@ECF@|==mImw&s_=kRAc)O~~rAzeGRe-jOk+_n~Rr_F%p8zo`7oL{3 z0ven2feFA){ssO1pQ$hPDnqNx?4Op9V|9({EV5^U7JM_oGLPFfeU)%st8^1A!$WPz zs79S+K);Rs!d%1})8`F>$dAmgAFWwXi}Q5;_L0n~|9L8GBeR@3kDQBD6T(}UPiKJ= zPxDDf_|k=qyh&1N=x$>4g~-u&yYb*8CfE}aWO~;b8bRfZ3Or0G zKrM~qQZeaekeBsHV=xQF-7a}FdR`?d`F>?6^$r0jorGYUacG2Q!rUx<2<~O7JxOaH znpSrIzM{`|Dc8RhBUVwMz5(-!X5-{OZ=mT-qx>8l3IpUFI(HL<2D6q{%S0}Y=vg|` zgT5M@LG+09whT~g_j0I>FXO{4T5tme;c-droz|#dwV1w64z1yaTYtd@KuCn$nk!0w zjL1<7+ZZ<*FFBZMr9xYxuL>d7@0F$*ZQ4YPYWX20X8UyXz?VEQ$A9)s3P1_d)Y;az z!XbjZ0tSleyqkXlU05+^E)CSBf(Asnp8^rbs@ZRe%Wb7mhD9llq~fjG-)C4x!tny?}B~{mmI7s`B?s-Gf$G*CXfn^X%Oow>qaU zt^-uu^`!e&ti&^*(_DUBw#?W)+uKSS5*8kdbQlsCC_MpzPU0Q(i6(z_MV}0BDOn>N z^0TFlok291I@f{b)b=SJ6JdkG;?I*8%fAu5bydYg%!d?{zrQ~mlYNWMy`rF(yVE-T zx2$*ub^jw3sQBvhqYk{^+=)}Zm~+xt=)O&P94@3p%p>CEm7CxQru+Az1>eI05Am0D za1VqQkAu;gcS81<`D}lMIBSsT?NQs3g(Et|R}t&W&EUd#e@>VI-0;JUF%CRky5ZDa zTbcHuCUPh2G=j5luIz&4rz>D_nN1~hw2X0470Gune*ir(IB3FqHCh?%@tvw;sCfzQ zDd4Jks(6bFDbb7Kfnfcu}(~S zjf1gezFiEe7oQ!HB}F`5BkxPHYNv3ahIilXu42{EIM`P=y!Q6`M{NL=orDdY(9pKG z3%;p9VljPLgOj1Zy__g>;X&j_Y5S ze^4lv!{8>F7yMm6aOgpi!CIvvpU!BKbC8Af4Pt3eLnDX@uN=~)S*OjITBsF2b`eYG zph5WPc&;T>5>_boV_a2{^w2#P~ z^)v z$m-W`pljQzM5#R#=vodwRTfP>%oVmSkz~(NEOQh~R|8IPKMqjNN8^9Wuv4Efs028# z13q|;`FZx!8iRMisz=05&}x5V z_GX;)w~DzL4FyBYmjgk;WDd77=2sI*eL068sE8kmO#(J^BB4Xhl6{oN+#M(sle*py zw>t_OGCp|OW?)zqLX<1}!Umf5C~)58vEf`%-y6V&J>=-NAvu{mXild*LpRIq6seWR zg0&zA6Y;zQIV14+|5PGh@hW18woirT^ydg2QWl#!i6sr&!X{2QQw0}(&Y(+-IJTxUYU!m-8q))~QQ)sn`d zVx`;})Vnb9=d*)m5-^Z=YCGH|cBBb2U8Qqk0`p)v&<@RW>AGpA=qwKohMl+0Kg0hB zxf281fPlWv#~QhQ&v~!c=N=cw2qnb?wc4L6+Q4xl&;uw8J}pOfs;p0UvoZV*y&MX~ zJt=9}`(SGVX?ww@s4y%za!JP6V?`tH;4GO%b6E$;aSY`W3yNBV&rxtbYub}jppeDG zfRQ(qnK1qBQG!ijKe(EtX}bR4r8iX`WJi$$iHtsEA@atEUvohN;KJ<84BVrU&VUcKaBc2gA zyB2!g=rE9|NJu)xiefY_FH{m^=b<=7y$o|eix*YRQ?D?2@1Jlug|I(o2KkZ&R*ztd zcY%+acsk!N&j6nMHDVb4efXGDc) zXhjy+skgs?)-LxQ#SmiCX0}4JwYpU+h7MB*p(Zy4f}V% z_o$FXr_=dlXWVGP#G5pF!22u#iI-#qhnQ!oIn}*&lEqyKmEXb+XL66c{x0fi=Mx7> zs92#C!SObl;eO^hxPSv49O!pNEjGl1aes1JD>O1N$A3553 z`}Sd>#|i~`aN^_YcgKZRb4pr=gm$a*JDu|O{+Q>nB);9%>r6K(il#j4YMwD{UXmP@ ztlWRxd|heL5pt@DaKiHyJ z+*$@OeztM2XukbGA< z$FsWJ&tnGp${{gI1|ydwn%8KS=3p7$gh{8WCa30GUt_sGFdLNO=+c?EU$~*J7Zws> zVi?hyp+Rz1UvF6ceYm`u_KNLm+UCIgb`(ph3y&vUKGt_EKPSO}cgH&y&AIvx4$-r0 zL6r8RSS~*w_@Be7A@L;NR7c2~D>j7W`?C+z=lj_HM`H7OBTF6h1t*R!g_P$u)0}4c zl_XJ-U!8rNNGGYqdLp(NHH)T|^vAYGVA2!pCubH7M5`&zS_pEsW`#Y_Cfq%Hmu!slf*lls`Ibs+n|X{({a|c4AT`E z$vp>>mM)H2>TB=M%)$tANFwZu?5&-NqD1X_WRBVE4ena-<2&9d8$xn14i?=Q%A;iz zOGoaBXr-w6jLyxkpR3WF9q}hl43tmhV=E=@C8Lw}iZ--Pu$RUOnB1+7YtYr5W=kDO>o>iLk;J%SQB+4nT7877iQp*_I!zBsL|MsZAlYEWQ9Y^DP z^rXRs(NnysfXuDjB5n>oC&J9F+M!Pk&&aZPrPzEaDSIh>hW@075^a|4c? zL3^7|NpW&vl=3T`1s@;5sXggkWGeLqxA#-gNi_Q?k+aN>|rL< z#mx2XY#PTyxcoKKLI0#ObX%GWMWBx4dvx<1la|x4h|JVo)1SE0$VghL)78Tp-Dxo~ zYv*xvRVMYuNz%7iC?UJ6R5xx0-%Mi5LDacQWHY#Wg7}8y+g3!T+~e@wDrolj7heVs z_-88j+YSiAg3#Bn+U_-&1AasbK%ukDMjGzL@mHIU`gu*lqS2VkTuhHDPk0H*7EV6q z;ohkElvoxNvpN(!<5Ucfu>Z7n@4$_}>_iTISJ0Po5T9=*N7~`Pun7{o;aXEdkF=nJ zs|=kdFTU0yc1vmX4UKH{#i`3Te8e#7RrN&7*w&{UT)Iw_rTX>hD?PX_Z}Je%)(S@W z(=t8M6v?VrLh>~bTI?X`sCSV)wl**%gdK{dlq~(4e!n&;tCIBaI*!hczB1-zAPXW4 zYni%9fDxF*+4nfl?v7P_>aecgOc9V}h#MxCtz1wBk9?|!=0yCq{l*k?caP0=UH6O5 zkXXZ*m(3hy_g6`e#Gh0+LHbSw@x#==wiD!T2H<-B@A>Y_(l|OL5RR*b<2bNL5_?KY z*u6Vj_fWoe0geu$T5Pa3G*B9`;lXraSj^pK>^%z}A35{FM`W>H1w8c9RlR02r?l}o zp-nY4J9#aYQSCyd9!VVC;X?Fy6@GI+v^&nXcd8$EdP`|-&9is);#3n2RQ`eMTt{YZ z`_UWfUslo?y~-xNulcQVU8fwvq{0S?O<8E8@j?4w&BTVdsHy`e zM}&sU(pRYzbkNQ+sH%n1#@yrHFozZ|RZBJW;GW#kUc0+i50%^8AuP1XOy;rEd0q~S zxb;~VUPu0r#7iuN-rFf?$wiMp(I_lIE?IrJe!WT&F2AU~x|%45*}IbE`55kf{*Ja2 zO=|Ga1VANSN}XJHQ?!Q~So=@wyx zxs!2o1S1W;z+BG3oF%HyQ$|P5xvxqzd9IG^dl}~@RB$JFoy>Dv@ckZ@FoaA3h4RiT zCzS3saNGG{kqE2!zg_;g0Bwe>fkFO{8IE{RAqyDVTcDqh3fRzJG;K++pe@YEU1c~j z8kB{}yVdl*KJg!3j=L(K6XkS^jUPV+Sp>)EIm9UJ zC9f`o7NNy3xotUHO$GNbeAWQfDqmmfXR?*Dd)V z5n3(EWiljyfU3@Mq9o9VSguS22fV#C_o%M_jQ4fF0I|6|;Q!V~FBXse)8{ED7N${V zean;5`o!9=3!QK0gTQxn$hi61Ux%JC4Q@62^jHkgX%RchO(J5oX z6BCj>48|b9FOf=nfB5-xw4SZpV3t1Z>3GfYQG#JGlk8{wdlbvf>yge!aD-`ZZB_gF zlq3d|JmZP+BU=0kB;TrhZeG}XYqGKdSA-f|ey`+e=oWutLVA6C_>l*|OR-yiiFUHP zH?rJifCK>+a=!T++GsScyQCqp+n8-)yaC)FNrnG& z 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�BFMi{LCgnTuQW{{jIH)1RT-1AZ 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

E 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

(u!Ws~dLXDFDkD{=_c@=C6~3WtKFqg^}I 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/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�nKX_p8PU+vi?dn&_GYwt<;4RFkhE+Q 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�QmRaGhFg5StbuO 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

Y$vl$;U; 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

>7A2|LM=6h-d6}`llN(W> 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 ZmicgT;U}2tgWhrkZzXC z_kP&9#r*G%4a5wgsqz@&z3gBwⅅphR{(H-DM_p$Q7P!fD*lTb4se|$7h@gfui=* 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
    0*UOPOop_xbP>9*?r3 zeM%T7K~XT{1Fk`z9OHwbRy3BNYp!c}!A+*P;;I1_T4ck@BxJ8JFI0|FGu0IhKs^fU z(@$%5>458Oqe)(9x4*@?XGS+EH^RH4d1f8`U!CjnF-uwKk%)$oc|5r@NT1nZttoZL zybgDXE=fwqG{=G_p0P>SZK6C9{W}@u4;P=0%Omj$x@AXUj_J&*Oj1W1h>C zWb4UnOXpg0Gun7yXSxOHqt-w!mb)Z(x+564z;Y_N6LhS2n^2nh1+`;tc|6?P-E@b1 zI};6}Ow!LbarlaG;-&d(mZH1%!Mb+~zT4|_LN|cb&HeWc=I#AArW9sbwLriyES`(X zUZk|xlm3QoO>=y7z&Ghj@!y##j%vPxmAis3@X`|UjL?dZ+o^oIVhY=x-J&IZo96>! zB0l`M_F$U{6kD@Lg9nw)13KOy1dB@>lF*T{#0b|-q+$i%)f70qmn-<{C?6CYnp`3B zy#~7DV4%eM-!yzp!i}KROn6?hpzvszzWbM*RJUOJ>! z94p&p$@d({5oH}#>W~RDi7@BRvixS{A0Kyw=lqI z49QrYJtR0o?^rVdAS8BnJ@WA^JBX^AHD@EIJ*ZIbqm}hf1$r$t8zZr&WlbY_@20p+ zU-y|nPsA*b^B_oqu9=}N^u^&;AHkL%-J3~#hF59aHvb-ga{H{npP|8Z%Z7^H?;tTT z(qh!T4~t`-KGkE*BDgn#?i;fo6)fBJ#RS#{={!5?A!`iFAWsVT#~QG|hq@wE{+Zhx z<18u7E`W-5#0bOhSX`*|_b0^q(SVGw;=lHBSWX4ceImZ0kTfx$oDZd^+!Hhly-DgH z^pOByB3{P#(%OFm1Y@XItTRo|F%TT{JA4=q@VoPUkyx&$s~CW6U{b-4vzB>DDd;!8 zLatXMinQrYOHBEPHVr19M2;e{u@7B;)C?p$ty{^PF1NHO$?D+r`2^%OAAXn4f2w+S z;yh`EDlr43Xau(DD^U$F47C9DjuSc3EBRVvEf8U2{{&0}H+*t`eg;bYh&sVep&QTT z1Ao`G>bY8)U5=FVH+-x;QJ(E$n>)?2dOVz%r97{=!hU_N-m+%K)fc1O%6#EhIVvf> zP#45SAIq@KI=|@5HDv}8)BD$NBQ2s0+GNiQm>czdqDzwxmTlZ_lShX zf^E^yqe7LBiJ*b{%;dC?RG`--ya%p&<3VFIfWF9%+02wjG9!!(@&0&TjwFOd=WxHs zPNhZXP9=MeQG{)O7i}u=#_5xWfQ>VZdY!mX)UH?8F(%AIERYSf&0I#~H32Ib%`)#v z64ah#HzSgEPJ<21at<%A9MgbGKO=%F}?tjj)uCEa8sNcj^w{l1=qcPWBVumN3ZQ`b0 zlqDoIMchoTCFZe^ImG{961rEBVBCvyNV!kZ!&1@}iH)rBltoVxpz}>H;i8M*qYYDh z;zy#iE6jWkKROT=LXcD-Y6uHOjGN5+gw9gea<_3rzFDhM;arqeVyS5doQ>U;mD&Hs z9Ky>MZtg3R*7z5w?7Rlxhot$*0o$la`TifObJ;LX{rI+nJz~(7Hk$3+)68FMr!B*U z6FqsvV_FFH5H5pOP7m)dh0D;Uoov&esM-hO!_WGjz51C+k$Y7{eBoQ;~y& zMc<#)=vqfK${Z5TXs6*r6qP6&(i)4mI8dC1U6vWodld`$KlvZ2et-ZjG&7W3)3wV!_=?R5P%>Y~mJkyweeCDqf$`iE7w0qc*8LQ^ zU%?)HO7~3W@qNmU(YVCK1u+qUr9>Kx0djNTkKu3p?8@`G?xqx#b{3gZ`kMTfx^S)} zpl=C6f#TlEV&yy3M0i1?FTzs`jT+fYp2iRiRgksq(@6jB?fh1zl9 zA|A(R>IoJ#Xc=A*BtCljgI*HfPM6lo=!A>WbTaZ0);+3o?Lj@StPHzdfxN^Dy-=l- zu0x>Ku`D-a-Nelvt4RzCcvvJQxMl-0^Q+&eG>MgUo(_UP$91|LI+~_xfV{&mBfwjo zjFRvncxI}h&DNe*_lK$pY^YRS)W?mnu9fentTHD)#4hJO%8Q$zE0lL0ps^Ri=JCx+ z2kZN3J3!Mqt_Bz|$a6}2VLyYFP!>(_Em7CsV-`QKCtC+D*c z_UE9uW;q~o^nL4yDrUe-iR37crCMZypN9Ly{BhUlS>%M*H zSeB(+k8;er&E8XDF0Vb^PGng_@QQE)FDTS55;W5OS%p(QJ{o2jdf>m#7_TL|9SyIO zqO2Kw3~?FEu#YkgNfLw&+#%TKe%|_Biz3iS775{_9b#Z4s%)8}oO&0qD~1y~s2~D0 z$#o)bB?6f9AmG;}(cm^a7TmH*i#4uYSMkwO}9ehIMIYQ|Mf!l3zF z_76c7j8l0RDg`}WWGzG$FIf;e91mj#lEA@KF%H&u@A`8E(*(zRd``P`t@$`W)cN@0 zf1oeH1zH9?F8qUg!oj{Mq+pvUm{kyGZ}Xc7Ik45rE*v&g1SGawT-%xp$Sn!R^O^9r zG@7Ote3y*~0&)kh1nquIvsp); zT96mb(DXKL=E^(?i6Xd!Y~=lSZX)hZmvImO53fb~f&xPbEW6#&ovzH>_7s_XLYG{Q zd6xiidG-Qr5gvM%w2;g&&W_uX3_HG2`)^k;^gkBxBTCUZE1Ml_xdd~(3e->?u^t4O zc62SsO)uwKo2=9LVhkc_SOf@pUb|j>1daYzv#isexXC=sta}$p22)Dr;q6mLtYZS< z>H?Cbv?rHY^m%ud3^j*Qnrb}~_SX)sAD1OV>SoW`2Mh|$V)la(PGFCqojx|R-d)O~ z+c=q_O`&he?Uk*}0~t?CbWeQv22FPrW6#ZH7YOD!fDG=?t`AC0RxjTs%4YIPDE`Ec z8v-8lst9`keDY-*RGFZ|_WhT|<@a;+DC8$JILK#P5R8^14RN^1 zy%HkiLn~SMUT*2bPs%6%u|2A?kF6L1XF{bypU|M=c{PcO%Lkvgwu$v_YHI8H zq1)J>5YqDd(sZMmV*&IduVY1RP=J@uX~R(W2L^}(@c^Ru*L9JaCEBsg4uF-e3NFnq zQlKX200+o@{&BoxBe1^qQVrpa2a#6iGFYAd4}uWS?%I0n&uP!RK^QwxTTw(10D_=Z zehtTAeur>eCpBV=y^-q|8^*^C?Oh3N0fV?FC!+ z8YhfWgAGzhvb#B%t*4PI)5gAv%DUyDe}0aGd1iKl*1ynWLSpOM#rT!&FnMbC!V;tn zmSGUKhz7(TwPzDAlrGn* zJYLzOIkk#9&DV7LCBnJ*>Zi!8B)9QTemo{YHqoM7UD6Xl>`a#1 zk)3*zaD+wOI7U3&Sr=g>%^RIntSF(H%s`S7zQFJcZ-z;e2d?MzQZ`Wg+k%e0$DV!P zcPx13+duNX4FS^WQ-_$5N_~H`XU{+T&a*aKBYAkFlFcc_MI?)DC5K@WkFBD@B|NP| z^zvbRvfW_#os{c(@*t-58&K{GtS|IE3K)rup8nU{2>dm?a+_AksNfVu^psNMjK01? zPIrwq#XlO)`roODFRi44_|@NTiLTZzKLk*nHjwRi zzA91|nTwo5aJYdAU=7$u+U&(SyIq5_;e7J+VH|46Enhj}>*WnAQ~=ua@`@z{adZLV zg)(3@b#%_9Nt)i(d3W-`8e$y`FiL}n1ZdTB#0_lz*FYGBj6}2Y1?b7U$$S`w|BTx3 zt57a9*2(&YR^)J(Ts4yuHqfu;1k@XeostY8iaYXJ%|R3QUDg#B`e3U4lQ_qq81u0$ z!MAaPJzjTEd+Ru|z57cGTNWX09R2`jLo+I9hhb{QC`ZMRZQ?j6E2SmbPjVpGgyZDzLx><5T0xlp7*95A+WDBt3DG*#|95(UOo0|8ZaCFVzoO zU15=87koGw!G?y#nNnMA4DcfmWSrc5pi71ddCnNG-Nhk4DT3=mnb9uAJOTIasSCqXOzRY@vVtO+(AFm zxX-`yXbzQj;m@%wCCqS$zi_jLy@M+j)?09-MK~ms#n$JF0kbKv6Mn@+ zTb)=?PP|Trpv*Jv5iMtpFB4*MEMdXynftCIkh56lBpqe zerhoFVgF7nn2cMv8r?38!704O>&p0NkBN$Fwg*t!vIN}Wt+;--E2SWe6~bIuj>J9j z9fdL~>wJ~v}kE8Rv)vIeasd=bY`s@pM6YEz?U6D5D6Kx|9w0k8>oERi)~DVN8z z2VZ&vuPU%}q;$aYbfbYO1_h=%O4oMr#ig22vMjfzjLw6j7G-ZNHt^8cDJB{{TL0F+ zK0!3|uNhrtgBD{t@k+QSf0AKX*TxADkUg+45yd2Z!+pu zw`x0Jri;Td93K%f%l+*>iAPP)T|eoCM?;y^9Lq;8=O=<^ zfuHYtwvqVC5<_|mKbMRj*9D3qWwWCNHDXV>aG$ry1`LAK>cGcD2dmaeeGrZp%jSSy z6H()=Y*bqtn>($sI|kTAKJS*_8^AF0=+8>f9U?Jr$xHKxB}D@XJ32Q=))rmhx5~yV z)ac!7WQT7xldX_xTZj4BgQ4iaFUVdk>Wk(8ku9xLM({saVFuqj@LKDxRNMcQeXiRc zyRVHm65sxZ+j(RMh)1ZZyYa4AXX~$4tHJK#u+7+f3HdNSuUwO!WvkC5qnPf1_6-?3ETw@?~zo<7BUmkS5y&8PYz+)@buC>^C4deb#tNA zV;19w(#djwOv1nLjn|;mSP#ah3qt2b9M5n3xXRBZTA~jYnERD)ma$no!)Qc@Rqe$e z5)z0w=BXIYo%k-@;V!en-0Aawn}{*p+|2AvsR{oKD|0KbXEFUr}Ul{MYip)e~Q3ovkMmI`ggQXEHeYuvb zJ~iYeod2CRRiU-XRh3bV&j|fZa!{a77+u-RnPqvm)ok_xb>~EL6+78JD~1f_i057t zwq32%(@yw|oNIq-Hu;mvdWBgVNXQL~-X`X_s{=VD#qD@$!CI1HOX8|CMyA@Er1nO~ z$DM^{U@`q|n}Vp40}-~(>(jARj51YH0w=MbCNfrpa1lDNbcLVXpBPCVWtQ?+dw+Q%wX_5zR<)W8Jjj(iJFS^o9cfLbj%b9XGPsjl+cVp1XEXNF%+L=r=c?1&-wpPglO1VPg|%a4=@=v4yzpF0 zZeF1O^%`)2HFWvPAbglil{uctlh)(@lelncrsnS=mvCN!feZod>98?@0R%K6-ay@*(l_L&87Q){ zuiWf5iHAcMQ?6?idfLJMZ`ooDWiobC#=DXkwXQSGVuPcqR~boGo^Xbmn+9j1@^R^m z<6YWyg$)M#yD%jlj}DM_!oH0Z^J0ng$)Ta3Pt4dhXLZZ2-Z`!vM%b1u^dtN#yFA0b zPrMt3b+;pCXcH66lwNz{5TFe)GCmz|lao>T?&{EMn0DP@4)GMGQBf;4oVL4Casn9| z0!BP1EVQ{j^hk)PpSZZ9>$@{Kb2z=dpS+QWC!q@~hT~P#=0JoQdi?WFMpsf3`Lgyp z?`;-*e&Ib?5{a5!_*z{SaA3uq9Ae_>#=0^VmQ9Bo!?rw#nRq zFz4Z>B!>9!9IX|70!Co1nH=iwfZh;dYc}G0z|J^Uo3FVa>d0q{CgcyW6lqL>@#gR- z<5dsmkss?m+&%oMWo@#%9DGQzwm4E+b8b)ek?Zni)n?3wP##%!Z3C-S*R$y3O;9?1 z61s=_BJtxs8I7gQ@w02)jEk#O=-F7|Ipwi4B`r`b5*dk%K*&L%%NLHH8kFDuMyN=m zxZ0-mL@(8w@nOUl)W;0+DQ~x5_gWXyO_sD>EoJhIB1|BMlP;mZhdUp+;&t3&S1;^N z43-jC11rPUMI+oROm#)TS!p$cnYRGCtUoVBxc=_=V5w!E2EiJS9UIeN#+fIn3dL3V z>Gp+GR3PBCdXU&guwkFY3J?(KNSdHL44z@v1VS$pLMNjH!@R^MLN7Ox$=VC<{o|1@ zF>8?0wD)iCV^jRg71OPx0^hKHguJ`F_`s^H-=WgwelRZ6@ldr&cP;dqvP0Tc3R^|2 z4e&$G0Lp|wb+c3GA#J`Y4hZl5YSuto=fE(@5<+dsC^R3h$~9US2K5HN%1lG1T$4Pp z<{E!Ecum|8V~7qG_A1MXI|3JG*2&pt8AD-nZ7^Q~C)V$2#sZr_h<{s%(FSp{;MbJ% z8%DiH4xbjLg88$?%RKY>q<6N;eP&x8P_&8=ST@*8QMOv9GL=8kuTyckz>Q4hoJncn z6al{Cx?$7r(zNWQgD>suYiD;TAb)!-)3y8eutt{(nPBtIYPu*FV!>=?vHJ;TDC1FG ze`N+&ZZE>P<>|&Zir6-6y5|cO6~tzM%2Plmr-;XWHe3h8&pMvsd-@AP69#eQROlh+ zwH#awbNGbIcIcTxjJP~bn6Ub~4F1*>XyL2wb*9a#n@Zv2UDYS27j{io-R47#T@!#! zrPdios9KoXSLX}nn~n%x;CI@9iIV}&PHj<4Q|!NQ<2CjEtJ@Vb>?&ZMJ>+^tUNcw4 za0=6Gbksf_tZSu*4F%X^+tM)0xfx%7|T^h5i5R$+;oNqZZ5i;AVT6b zKFzc^5<^%ih0iN<_@CTqfy^hmxBhAI(W>fC*ecWDA254ks^XKjNI!&Q$6me?DYAmWf+IZbH!D_DrZL#3U#f`j zp1l}ra8LV;Q%g2aN_I9ovQ^iU5YMW1PJ$`2x;_$@pFPR*2jk!d7vOJ88YQ+}!`~2+ zr${VZ@7}sICZ}14FFLto&rLL07XoWEZ1uvEbajNeoVYlp_Pwl_H8*pl%EaWN?QK6p z3DkS#ei!{rv7s}URsO$1cVem^;x-9pudQrQlYKso8O9lq8e2xx+HoAV?Jj21!6ZbS z%*sKqhjAdo718SgJRIHswvQ@s386mq(bURVEO(|)b64wn-atto*cTYzNY{t_Fm_Ql z(p^E_t0Pw$wl)|2xeh*+WNqD0=oX%iS$V3CC!}fEpT>1^eu(9$SG+PAc37~WpZ?3^ z1n8J_Ob8RD2F;l3QEuRijh))E4FMHRuGQ#~ac~ZL zch3XuDcDc)bP|b~?z{}@HktS!O=I&}6q3pcpCmoG%4Y>+v!OmWs z1d_XkSbL<2qG&bR3V*?52CVXu67Da1W?AsI zNQ;1<76R2-<0%b8^;u!J&qEuOZ@Ak&^9IEZ&)Jg8jqYX5>?%!TzHAve##)5Tmy9ss zkKQpMpNGQ1*6}ftQ22q+3vkdZMrq6^9Na_V5CJ!^?_is1cGcpT)_vQ$b;w6jE;6Fx z^gVjnT3CGOOGe7$R4>-nt`(TT;j^u!815+>=b_KUy+h^PD9#@?T(dI-k@i{Mj_mA0 zVt#=S9Sc%CqqJi=?e&haGBfJ?9bsdG?v>>$b|mfC_eAHUKK*xZ5;2gnNhSa2NuV#W zE;-zNFVj~`z=E_Dc4=HRmM(N8w8DpkzbFc+#6-JhkrYC*{$iqM%5OfUtq`lKBCAp^ zwEi3c5?eteIb`s1ZjJT$H@Gr?1Fsq;WS>S=dF3(}5|OSQ-QRw{1yAk560#S(0|cwE zqxk?`qd0CPSz^7=4$y(fAFYya$7Q8sSR~{t3>KE&^q1Zis)ryiO}a@X*LSXH2qLK) zN`Rs*`&VCcn27sP`wWt+?DA57tFa|Gl&!2F2?ookE2hM84J$J_v_ExDYy|QJdtmPAY&rN1qTP4iiz^rH?PF1KMHzOeQCwX;uacH6Y$lNg)-|h>8Aez2wgP z-h7Wo3gQtrN);uGV7w+BWLQ*-f(U(1eMU>U@g*(e(p4!0k!!NPSQj3=m-EOwn?IFg zs?i>rQH09X>OM9h-`H*;r)Gkm1nOs738ScQU$@vSBoqnaL1LPoiAEntyqRkImH_!i zrbZl|8fm{f%$1~`D=3yFHYfZ$k|}XqnhM}}YoMb&7#3p$2=95WR6Cv_<;|H5?C<%J z6eiMyy(;JQwnha!ATt8joc26PmT_6gcp}N31de*q(K6LwiBQ>tqd(vOnr-IE3O?WL z*seS>C?h(OI_Mz}Lo^w9x#vzo8_KVxQEVT!jjs&<%M>3j&@R?+2&EcVKSy3p;?d7t zk|>h^oPF~A#pxEk18tgWcg)aw9hj-_v*cImXWTs@bd3Y<@P$UZ{mm@zd?X21b_O8A ze>l}Po*E?r4s)s~+ zaZ)$6XtSH*hd;b7<#XJ%(|0Lw<~yd`WUOjeIcm-tCfaE>egf@it92357f$!7%yi7= zZ(l!L3mooVcSG2?FG2LJjgeJB$8PPsX!6<3G%p^Gz<+#KDiz*1-!B=;Vf00No!EBe z*<9)UX|F2{eYsd@P93|(y|UP)#78#55idB>u&(~}tXxRo^oL@iNSK281Ox-8FD9z^ z5x|%SM)XA-Ah%8V;SE$b)iTrIx-GfhB5^|fkL0`7pA3rEh7;K3=4^nFMZ!R`?Ek*0 zAvFb|*HC@mj+_#PLV2)@CSs7uQ_ByUV9`sywsJdv59w1Pgc}Tk{qa!ms_8j#d|z&l zsp3dNvOwHYDA#G*I)%{N9IXr-Y^vXM0kn-rsP-vErqn6x{qfF*1&t6vhwE8g1KC^J2hc8H-!#!7+ zgp83;B7d(*z~R#KG+6;gsZ04r<=VRj_#77wqG)|UAAAvN&ARu~8%at3ItSxg?mOfz zgF>YVkwB+D&Z3Q~8j8+t-r(^Yu5iK@X$xwar#XJwgu)a_G2Wm6HrsTw@Wr9J9th{+ z#BP8Cglq4&hiY-lrK0M?i2Y7TO+q|<*J^+lrY~_|_Vj`*WJ#7s4_Vp@gL|U+;WWbe z4>iJ2WeN_p-S4UsuxAd+vUTWVsijAqmLG1mb&XT5PQ8#`1CPQbiEX8c7}aTq+JnIw z7*L3}uRuQzIT+e7T^Z##`E&~x|Jcy=*vR9)miY4Ha4XK}pULT)e=j=!5W22tnEp*B zwk1s-4F=D)9+D7-C-$j6InVPAlm#pw^m}n!Lu|e&T)$$;yU$rGtTWxl^E%H+ag_20 zAEW4_ACNpi{onXRp$mdH+DV;36e*`SSZ2H(*Wy*7)wluDDL+r^nQVgI&Azg}H2~*F z^pi0n$|D)F9&#cC?*&ZZxY2PcRWFBeb24^og?$RQ#V05S-ULAV2$|1f}2VIcvN zo}ghPz@ft5 z-CI6@KmB8nANs}*`p>#ZmoIW8Lf`-Z2ND?gdck$V1rzw+S6OJ=C_tWX@KAoY-!^Aj z2)7z|0*9Ld0)W{19y5M7M<8KE2!DSlu#<0`xPBmKMh6fyScd-m{Bu7|1(d~!pTDUu z{ZKSK&zm5m&D%}R1wR53Ioyj-|108$HMK3FoLbt?pe%yl4|H7+oDZBAdH%!AxGVe+ z<9WH;Kki4*7=B>jtUpc?kU>~L;w+q@eiLBa#L6IO?`20YD0@iQXH9I#m;i`TFYLA% z%Y>TOdvobNjW>eo40?+7uOFM^|6XX;H$KOqqXZOconAy8LbPKV^1BZxn;*%uxj!i` zT6k71E=%d4pul_Ea9bnf^0J>-z+NP~rGGR&hl%9!Re+Jrvvsz;qRi;r|4pl}A~YYD zNqcxo2D}rh2r(PrC-;~>y_*;&GLSIubC0mmPceU8|5pQ)AT;rIN&j<9^1yaRwmTP{ zL>711pJbYHlt_2BJKrUhHNs15d)r+OkC=Ao8%D}=I)>XUyC{5^hY^wrI)&mkzV@L}=$w7a?jrg7`vIJfeTs{n@9|S!^(z^}`!~R0^)U8ZFNNvsV-F zofMYM8w@d;|9M}|Fh#m$CTAw+gVSwmcr83iL-SFQQaPF=%iKuZfV_B#o8*`hh!>1_?=zL?g$3FfE;U0g+Aq4Ed6M#IG5%-VSvuU58ns}pv zZo*~n#>7CoBN@C^S9id8$ktS3MVre^NMil35`;Nxv5)rSY@nT~PXHDD$B*E2C1Dm1 z8^ik*excOOtBZ;D4;_`a5`BM1@!=9I%S&fOgq>*&jg7b9Z?t!dkosd?)B zo=u65RyJ`tyT*gWricVY;?R*w>9e82v`HHNvH!JH2j|7D`W)ea3j;p_k3#>V8a~Is zpjGyX3oD98{wAQg@H|-IW)M3LFosuv`=k8}578IHt%+}}bVaCrxiJ=}ZphX`X%ROn z0JEX2Q2<*`p%5~7?Ja6?i|-X+A*U_#O!bD89Fh@n;bqDOo|>gul)>LwY?s5f-(mr^`kfVfO~GCWW{wO=@aJ7|sJr||7X4Lz zN_#k8ZI>pxgOF;68X2_XhaR`qhfES0=PD#;#VT#6Lmf87z&)d7ARo$+*jsicX@Ojj z6@dR~?<}L@*t$NC69|$7cXy|8cMa|YcXxLuIKiFZ65L&aySqzpcW7if_nABM-uJz; z=B`=u;r;Niif&d{b#dyf{jYs~d+$2u!nK@Fxsbz$l~y)ox7pt?29r+t+3LFs2^gv5 z05cEWh6$R~@MlfbirZqCip9NewfI&U4$eB+v+|inJRe%OA7_5?0?R`p=&iAt=450{ zkZCNxJ;qp5=CT~09O6$uOS z44(*-iPK5KCA@&17wu!NpMoc*@g58s#r#8~XI6M~S5GllkJnB6V@&~WI3 z+w5bMa$-?IunfM$uWC*ct4|Wl^ohOAoz4>PuD)nw+)L-(1Ckzu=eP}Q* zmHWxK*gR#i#IKs!@c7{Bv`y+Y@SIcO`jI&@u6q(886Wi6!ISX3PECVGV*LK?FQNN# z+<|WoBb7y&C#g#7FPyoG+xk@3u%q*K5I^7r> zRJw^gG~&6)XVGxHsIXdKu$TGzRTJl-UbNZNv8vJCi6B7|i}H>Pf`(#hi5S=Y4589+h+=9% z*$VvecH->QR^{Cj5MRq29x?dyQ7N!XEPkzzwfU0&q6~H)IUJvR;MVKMo@*Ffc>W=k z)7R{l=CVh_QnMPL0>lQS?ig5CLZf}<`_9l5uIU)fpX3s4Gqr?3Z|Y~(R?tPdl9q|MI!xKPkH9^)FX~sV)R{T z6^L?J1ta&{1+s1EHNEQ@b5U^JY#-o)(N~&lY41+w)xaTei1J9t@YRD&a&6}~8aWx? zQxT~+Zc(2LbcFDkdvC30dx^U&5kQ4O)6EWgoFfW963`iOW{8|7IWx)9Iu#3+mWI`! zz}eZ7MdA!(g~;Hnl~mzX6G#yg|Y=8#%tRx@vlH=FHGc`z6CA zsqpI54m8n9=(6Z}hISn~ah>aH_^dDP1(8C>O%r&zVn1u0echZZuvAq4UbcV*kpnm| zN2>WzIn>bfd>ue1UGQ8Q^`M$!Gfd4tBwUD^8xM^V`J6am{as^@y9FaoNypHAAt#K3 zg7`pD>rin5mR_`q5{UuQSBKVuT-F^882%8A{N*^c=&a>o!h8QU6gm*s4Slg6JepB~ zdzsJ0sC`pP+IH;c0=o&{(InAuOns8$1FPAQgBFDHJA zod&6$RET-|Pb32k*T`9c8mu8^ zrp?;3!-{gjWS_o%j*G49;Rvk>%4pjNBPi8%x{?$*9m2B9XRuR9r8Siq!p=I>R4 zG+=?Q)~VSv-)fd}%iGGvZ(f%pD;CU7sU|1fRIObGK6dY|O|uSXZ(J-Ei_l*+OjrwZ zzKzj%*UxV_re=QxC#evK^A@~42hO&qL3bfIMQ2r_28J^I1j6bmd9?DosVvzW$D}by z6%G1nk-m{Q{l17C|Z7)uvQE{Yi%2W$ig`VJ5rm(_!|MW0BZLhy_*lO(+Zq{))ayW)J8@V?^ICr&X3J zhY^RlCwHU(+fz0^t|CcJ?r%JCCFfGvzU3`j)yzrL9!}k-m-Jy<8X8xmgI(4>RL|{d z(HbsVjNc7gYiD4#jZGcVT7C}dHo?A_AKK~)dgWF!JRUgp9FDQygCz=rmb0D9b65_0 z9_iA6u4~;QR+Ks4GxtIzA#$7&@cm})M<|xcDPLBEJ)Ayt-uW2$6WiD$9E)BiVeWKEROVHX`4jxLim%$ zI5Y~X)? z-AmVuc?kEt`>-8eSlnN;&h+A}%9l2vQL$7sT9%x7=zTj&xsr;Yx83eHMnN})9MGDd z%Yg<7#b--?d?I}H)dp*9H;e<+497<)`3aAQcH|tj9!AV6_TBUzM!h?1qq|IT(|Yj^h?=_R_sii*7w%rjcsu2s@~>i zY_OgmKlG19w_uMejA4$$%^!Psxj*y;wNs@2eBuGXRNy$=8Jp#Bm#e$i0-h32MDO8w zi8GED1obNEE$-v@&PNP1b4nJ@bZKIinN8NN8dJzn8k6peTy`XN2$uXK*u$ptAw1Af zdH|{RyWhRygXPa{=bv@yhD`Spzal5&1R@x#iC6U?Z=~VJlFK)LlVTt(tY@ePFz4Ed z3?SQ!xH{t`k#p(QpXJMuuuvhkAM#o?1}x&(u_p$o`+`4cmHA+3g;(}k&(SObQytQq zFX*(fuU5?zh@m%(qt2^u#Gf8}`P`N+l~c@$q6v?(&^OaRp%Ig)1Vk(1IKK zvRNxNXq})hkz$Liei8UL#&cCxF-YF0X+jm+a+H~e*=A705nngDAf3fhp?fx)7QY(( znpfY*UgWNvTxt>RqjByE&4^&XS@7hk#hqZlBv;vqF%Ox_T%+E0@nSsBOt6A4izzzn zPE4Ocu5VeTv`mskVXC>iyHO&+t+QO`<2e-VLs1i?!sPbm;wH25wau#^d_Snv-ZPSl zHNrd2uv9y1&6eo%2_v<##3Spu?eg{W*KV-y~h9aF}}lf!bu zZ_F1mSWQ*dXQFmz8ABx4pF_&3PNSH;PESM;XJA}ZClvOtVNgdMd1x8wnmxp5X!{{j z!?^X~2|eC8xMZM}ufwOGxMke%O(Q&#?$WaByKX!>mOJQ#+~660o?CH!!yQ8F>?xI3 zg`%h1=t7wL1)iST7-j;u?!-v*k`fX11eO4OKbVY1?90Ld$6LgETRs8X-glN5V+(dl z6{YGc;*u@n);IO z^n$k(k7x+ZE(3FVJAK*M3yoM-9hwnmaV*TY-OjxELu+kk)+<_0dgiENJLBxM-uAkS zr@^bCIH)7Cl=g|jp#xvwV-fsPpj7)XB(-tsF9DI02MLqS_+s@XB-3Tu5!p-N;P%Y$ z2w1ECJtST5?YFv@79zZPPR1XHG%C>tPS)2}DmdK^F9McQ=-v?wV^SBW^K0$lE*-Qx zs~$HWh2o`We3ZU^+k4e5oz`c59p`i9U-Q)96a<#Lx4d{oQ}A<8H)>#+AjBC(K&w%X zY+J~~YZq7ga2fw3;{D3_*gavs)V5h&t^K{`SUzQQNc3jJ1cJ`%-Bc!OKN~g~XwH(a ziUU-m6czP_8xHPfcpiH3)h@LD=N_z;2AEHFCuURiFH9(vUkVRvZ%8|s(1uG#Jy(B9 z8ThC8Ag|AM_9FE4I{x538`kCF^x||X`9WQUIh+}?lL=Ih^x`qIK;0kbL3$F}M-)W( zD4<+bH$iPE&x~rX9JKF24JBMulY_lXtzI**Bwd$jB!Yq6N$-7rAnpbJMqO)CaDWT> zrO4|%mS-`5apICGrl7QE2GTdJ)=e`Wxe!}@b~`8v7=(h;m-};w75h0bDfne^xrna? z8ClBRr|di>8jDAGZjg0YoYfaL$XA^a8&!X}hOvDzmN??>!q#OXnyTvP#w>+}za+EN z;8l~|hCl%{@r3R~9UtGb%u0z)2WXy@4{JGz@AKyK;y?UqlTKKac!#`PT2c`G!{cLo z?`+-Wwm-5+ss#%0!Rgu$^=EBU^?Hi?&(RZdYu-X9&fJpgN17yuov_0%Kdq_*FQJtH z<3TqHM6CF3uWDPH7=CkYHM~n`Q63PKLx#elB?6_vuh`G3O;mgad+`Kr0 zuj%s(V)HXZ-bW4W+(}9GP^b7>G#H7THpCY8(yYqK`L{o?c82!-{X6#ghmPiO2Z`VH zQTAJ9Ae?^7T_v3E5eg{~Fj->9*NsL~YxrX$zG)^*7)q^@k@~ zg8Rl{^#!eNnTE6w2ksMUK-~-Q_JOR)$`dRqdtd@^r+4PlRv}($!>` z+0Ti2uej*;p|SF)=Jd7-Zx&jpriQx3XSX9Fj~AI%$2Wu9QELuJo-(oYFeaPTde>v_ z^{$`6+I+dx$Mn8&`egRWfeR18h!LL_y^O_kW$MXy9Ul?L_xN&n$twdP-iB5}Z7N~U zYZ<+8ZT_4*#j!*0nnxF^kp3-Q+N{rpUmivJmy%a7wI-A!mL{zsYExf>-;lhLzQuce z8+#Gxh(LE*TG<2|b=*;u&*W6t_Wt_=vwBgcWPCFhq3o5~e^O$abUb3%jYyPH;+B&D({~u=+1w|cg05pva-`CII%gt2>w)KRa9?tO zPmb%-eOf7-g7?~edU#*bGMggviRW;1Uy{K)%jxVo!6Cay`GKckdY>v&>wNU(YK;NU z7DZ?JxK>STdA{T8S+g@TURF~n+XBYpY(~|v_o@=#v#Z`s9PAsIz-X!Z-^hjeAIgP| zz z^GI#0&VEtaJ6kxmF)6*udvT>Xm)ZW1YDDuP91JxCP>BD6<(~eeJQ@D@@ zhSJ=AX#LbRLr>Q$Ph8*%3b z%M*Z08X_%Pe^S`A?v;1}-m&z<5xj#GUVyGS7n_m1lO-EO6sL1I{%8qcFz!Gp1Lbkb0MKUP;`w90Rky3fPkXE-~Tf+7Y+=Fwgk@zFUyM@<}5%xE+@ZF|Tm zHN7cUjB#%FSg;_`Lc>w1Fgk8#Vk%@}N^D|^K04kzI!-z|j%i{_Ydk10<35zlq!bTO zQesr1Ni9(sowYEr5H_(OF|oiHo$Vi;B_ExoPc6}AQnE}bsUMv!9Gx{8o!uLqMIU8J z9A!}%WtkggK}?m#UUS=82+_sxdS$Gz$t!5PY0u{3n6XRhLM_2@#qrc$5yW`4(~$*W zXX%7*^50NIy8n&M|4wk(8d$*d@DMVHnOiv-JAmG;^qq`Fj16s#jQ`Av5wdZz{nbS% z%lx+a_I))sDOBqivV(9q*5wxu;Yb8&Pft zm(qD%lRN6-Pwvl9*VcY%yPI2a^L+WTWWmGBU%k*l)99jizeK)KcYCopnBKsnL(N^| zLyiShX!H-@J9%Au%}kI{de66{d$c3ph=O$G$%~73IN-P^aEE4;a5HeX-(s1a;G&e}iXA{Xo=LLzLlf{Sqod{6tz z8w(~7enCYJTLtzVZjb|P_Cqr)s^8B(MK?lcKam!#4;IW|63HQ8r8$$Jhhdu`7==AP zYd;|TG^jFk`X&j12Zvc=N~&k(G!?;^(XS;Iv=s@#h}?sfkAo88c!V1px`kk2#DkD5 z33kMm(RzF7VS0VpGUD6%dW4|%KHq*YHZG4Q89$rkE)gB(a&*A5cO3!|kv`0z)G;&0 z;SfDIKMi^ddJnyKKg8hNI$HgyBS?CKeV|@qgIyf&5QrWG?65JwDB>eWvKU^Bt>1Od z@ULvc`t+1|$+W7PdY`zxx&yskKM*G8Ogfis@2hrzqr^bQLh1nnv%i${0@$eMiWK-gR`YA@MJbKR+L{eXlJi)Mf&3l zto>i2rw>CQ#dZz4sxJ-}?bs5E|e64&dTJOTb#K)T< z=dBZ+5luM6XMP~D;U(f7H5^qMEaFcS6KSX<_uNKh8Sl_T4y{aF>!r(h9_0Rtli66^ zazEgg+!AK-KBQS$IE8I}%N@>|`b(F=lvDh*qN zgagZemu=tx_8u(FFA`D!@tdarIHeYCFsvf1ME(eL4mqTslli;v*zne9m>D!+fc$~k z;0Z!n7;Z6)RMN?Be&0OAAVS12+TZnH@3BjT z`fk(H{Dq*>m5rdX^||r5a@?+706P?cinGPx@RHL&*IfU@gjbu`3Ekx6W*lW9*TN%Z zvWdM~2(q3nLLVq;&?c z9){D2a&)l>daM)Ob*aXAbqIAlGai)16<@IKU4uKAZWTY(4g|;eQ}lj>aFc2e3J6K? zkc752KjUork#KZ@`|xZ*VK>%}zgmml%|I8Zs|nqCL;Fy$vzaUlk^!QRIo|WM`^CuM zX0irUC$s%^L>8ZLO&%);y>?qW>XdKm zR>0NY*gxw(w10L0=U?srzcK=~Pz?&P{i3x>>6{J`)0#x=_YX*aFhYvWe`EwJ@=^;| zlTRQRw0T-=UwJxJb;y2J5!o0MuRk3H zZBD&1oFTU|?X_+}wVnTeB7~1R;C~WA z&tD1Q@e*QZH3kr=#{T?G$*bb;2w~zkA#j2S!SO#30_Puuu>YG70{$cfYTRrdN>pH)FB7PjS>+CvTjZd!S!hN`DLW$ff zi}~<6VXVS+&*$+hIl2+9^5AxghC$nOL->BSB@{_cYc1v2(#t|l{TJUE7Qq`6qX&I} zZ)ix--wl@7{=aD@Zz=&4ZT2hMc#fnQ&i*?rT zu~O^Lnv$A3Fvub^uaDjRfo0lj%4?!oIwPN5-R(eHIgU}XMgC#3Aa>1( z)7dhlwBhaMjXd?x{KHC({ru!rH6>j=J7%Cg_+5WqUx13s{uAd$CmZZY|3*_Q^EzL2 zk|aNReu)*0Czp-XiglVR&KRd|mAe8h@rv@>7?o!A8lv*AVz2N@b&3cxdc#oTa0u5$ zG)62O>d)Fl^tiIcn|3U6!97yIfSxHWeMMulUT6=qo5|W^dfA2V0y40ozcyrCr^a`% zlI&TM;)=TBj^w)xf5Ny4xxr;jBH?n7odC65?ksbZ;150H!dUuXcW5I`G57T|^xN9D zkTbR&5qY+FzhasaZFXnoLnQSE^KJ3k0l@F@jrKU#14naICRxpJYvh#|x|B4JIoEL} zctg+h;23^-qQE`Bzfy7Ib06k0mBfYn%=g@(IB6~1ncx(~Sw)Pn!E`&j**gn>p(q3} zPsVEz`vD}s#{0$74l%HhLO%*kB%lyrD}%IxcIkMdkUz6gu$ParUm`jfl|;nOh15J1 zAB&S2w0gj@EA}H6r(D>E#aL80ro-+2nP*pWV-IpC-Kr~lEBo50cYz1%kyVZy$(=bq zmLfigCzWM)s5q7afauO#8%vQVoD~V@&a5#QKO~$r%Dg*-N+gGc>^>|qs6;NDRWo!u z{>-rPHhsyqh1SmJ@vHfG)$<@*^KEh~><5mgcT~*j#~;rF{5w7TFk%y;H^}+IMLvJy zSJ?llR#+JSZ+_*!XeE~v_v!xllH@=66^c@;yMOtWr@d7)lepK_`tCLDdDQ**l2G0L zghE_XAjRD@Yu`M=3E!GgdJ8r_t-BJ&fTOwC{5`4l`j2I$D&$sQfG>GpNxIzK{t<`r zZBXEoDx$dbqe;@zr&c{}<*&&2h9#DWlm&63WYVf7YsJMi&F_^KDBR8P0n;9LQVi@FKlHkbWQKOm! zKvM--*st{+VWW{=D=1vLE@=O)UxED7uOw%#X&xj9wPYC)M_+bx-0nd4rxFxlR@y$0 zP`qhDf5#?eLqjz`2o`L2)KQlS%3WY*Zu-Qf0L+N6ll7ahwTU zkX8^Ge!8Q41ZgFao6lVe&s65OR#yL)RoO zL7^G1YxdRQDmaUYf{%q1Ypz@FYj%#D5Z9VEwJeu?mJ}$;bm*8Tl#RoB-K_9!A}ZY5 zMtR#YFJU4ow~X>Y0pmP6`;n()#Y@jC9`Rx3*)gl`A&r8rb5AmqPtIfSI-ew)0uRV@ z*bDM9-dQ(4_a$kvDat|drlae8P{^wN&V9OhLTT7LOL6NuK`Oh*$)z1|KjPZy)F$I5 zS{b8bf5rvGZz-DRb#mJ-UDndwX)vz_MVB0U0Rz7Ztn4W!J)MMZS)F5FjR;RfW#`@|s^9G*I}op*1O56v8dGPSCsw~t%f-hDJvB+aKGQHXLe;JI`$~;YZD3pg6OjD_b_$@I-vozR&jtUUW#JwHTLn`^ z)CE2{3zk@~i3v8_#k>h7&r4jWX@oh;sMQlFUZSX#)0jX-pM=ItJw92iPZXrm2Hi^= zQaigMaZ&YMj|Rp9Y_f+Qtcev2R(8Bv;9$GzU{Y0@4rLSEEt~8nWfg#&M)qB>N@K>) zBWFAfX7(MQCAK_CS#2TsEp{raHKSUdZCYVZN0vo-MbYX@V7=2GG7kYdjO|{|p`H}7%n!SC`%|B&A%0E4)V_L6L zKWnI+%A{b3G^9QboGG;l-e@Y^uvAzROZbr|4~o49AT?}y?J;We@G5~hSapiFHLBt7 zJCugGtDI4(9~^#O*-wk6+lrk*mz@kLcgz99KH`mcv?7f+Teq70*{a!A`ZDc`X4te` zYIK{v0|HiD(;f1{s&FN8lj7#1}FJ>ze_p&<4K{MK(-e!zR zdjN4@Q|WCFi=hN*Lq754-1)APed(=Z^z~lluCsCJZQb|{$OYsdJbC+G^AKCl$7hNi=5Iu)a3$P_?wi%I;s1@8|KWOvgulzo`S{=+og9qyt>N7=td+ZM@<1WAYqZ}{rcP*t24Z@9; zR-LW{Y?_W8`o}e^BJ*=^nPfyeb{WN~MOS2P28mX=p!G3EP$530px$mBufCq#$vu5W&UJ|{GS zomvuuiIZv$8~vUGkTA074{o+2z7OG{K!2=6!p;QJPUX)&CD4xrpRS|}c9Vw(845sK zU*vs9`%s;*pN8gpg7%-I9_~=halfkkk>5LV=>@Lfni9zotU5=w2>3k z6A?Je@*M?u&5}KuaXgwqJ(`g|ni*X6(c1WI5rp`nK5tdU*o@@0+_Z1dG}YN@cjcO8 zw4c^joD#k#(E2(96H=MX{Pez3CTQTl8an4ce7xensiE6*a%-i{EH+`mo_PYYc=lTj z_Y6;@BlU+FR*+?m|G*)jz?Q{KmVO9Pnyz!zWB$ovQ%h&KK5Q&H+|W@WcBSq^#rP{T zq5C~&~6P{nhci zRC-w3^4SC6mR%8k@4F-qy1z zP+kZW%lp8~Pmh9~g0deuKG{vic#|C@zlUr7^dxn*;&$%V)ine`aBlsGtb1w4&zSdV zH#u%MIedtrp0HC{$fqRXSrO~80QIrJX)+cP2>|0G%U2rUrA+o%%=uUh{a6h8!w_WK zgW{R7F&SHE=ppVpc^Hg{9=6CbhcJs!E#I<8%T1W{HDF~tn38F{|WIlJK^o=n* z_gusT@Z&a2S-UDHcidY-tD#rCS4WMiZ7iR!$1~arJhs#9xVTjm^96@r2z>e*L;t6F z^#7iBbbHo+8~VQu{jY{j@*Mc~H-`RCGvMq@e+>qEgR+5t3|;fZ)tQaWj_-Sdv z`+RM6SKFCu*~O!-q2bou+3UlEu-fSfsZFhQhjsel__s#uTl><})LT}n`g0l20zCqI zpoK3`i4`|7VY)K<)$QnXQ!ej{%t0spu*beL53Z5CLkmTDI~lLP(2^ji#T5#Ja+&Km z`oQ`Iy_T<}re1O@iwBf5>{Be54O2ituqUw6j-nY)+QhNvE=-AXYxX`wb`bR~B zVQ1w@mF-4(W0C{Oym9lT)t9%%hV974p3jH^hz9p@)B3j7LZM^R?RB&7NcBj=A+|n& zM+pc~A+-u@*|ls7Y(Y>R6^z;~LNi0bBN^o%ml1}KhnMmL_2=o0gUSoGBR_ELKEYsK z<&Qh+EvuQ*=$(;J`74c+`Sd@daumrbZ&yu6=4gms&8UF68bHuxxG`K*3Tu~fxE;@5cyBVuaJP2xNH%E=-+wV!IQCG?WuKc2RlhPTVvOU5~H|$NA%+=9RO$i>p)0JMaUow8o4`}+uDeL^5uk-B3#Uj z%m79fCN?I}+T{RN%|DO$ee`F2Wn*l3>C&#$u41L#>mt&(@J zHF7rm{ZIaN@;}c3+NI=dU}0?N^hbM@&7G`3mks(<*+JjV&e#Z4IiPRlX#5*$jBSj5 zR~2yn$Ly*y=(-6R)D?|Q{#R820KoWvC_DI9`GLH?gS8{!@7e@mTPtU48%ILc-_0{N zGBB7|Rf0EVo_?D}kM9BhmR#-JP) zn-LomBPW2-kOg4C!EDUL#{)28)i-8mV+1gP?rLo890n}LY^+8m90o?lpzkoT^J)Ku z(oW;#Xhak+`!^gXjLuSzncovf85Q&+j4381d6 zUb#h)q+1-$PIrl~%u0Alm6x-tjk*Es^Xvx%5Upa}cVy&;M8R3qXQh}fE2Lkv*k;~# zDkQS~ZbNVMq^B9TYM^Uxv;s?H7bvVCxLYL8CTW`x!jz8O8wp-Ut&806z;P&5zt@tv z3_2u1G$Wh1Y+~&;05S|BulFK0yI9uQuIbmLJ7R~8Cpia1vbdz2-y)`5Pio&r=YG92 zMMVP?<}E(~5t!a+I>G$d`Tm9{2><=_?;iMf5B$3a{@nxr4?O^iBkDUixq-$N@XSnX M@ML77a$@lR0~B@FivR!s literal 0 HcmV?d00001 From 2b84a6b74c74e76fe7b58965c3b1c4a05cdcf28e Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sun, 16 Apr 2023 20:43:48 +0800 Subject: [PATCH 279/280] Update CPython_Tier_2_LBBV_Report_For_Repo.pdf --- .../CPython_Tier_2_LBBV_Report_For_Repo.pdf | Bin 2634616 -> 2634465 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/report/CPython_Tier_2_LBBV_Report_For_Repo.pdf b/report/CPython_Tier_2_LBBV_Report_For_Repo.pdf index 2a0ee715f55a68105ba13957cec83001c22c1ced..af92d63ed34b15b49161d5f8f18c5713bc994f41 100644 GIT binary patch delta 25757 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 u&nS{v&-2F5iG>3MOB`Iz(xTOuR}_v<=3a Date: Sat, 20 May 2023 16:27:45 +0800 Subject: [PATCH 280/280] Add reference to Mark's tiers of execution, and whatsnew on PEP 659 --- .../CPython_Tier_2_LBBV_Report_For_Repo.pdf | Bin 2634465 -> 2635172 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/report/CPython_Tier_2_LBBV_Report_For_Repo.pdf b/report/CPython_Tier_2_LBBV_Report_For_Repo.pdf index af92d63ed34b15b49161d5f8f18c5713bc994f41..9b018fc84fec2dd68bb5218c88cd19851fa9fcd4 100644 GIT binary patch delta 29565 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 Q&4K`GCCIc`c51Bu0sLrqX8-^I

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ⓈIGfl&qPmZ&x9(r?BW!JKo6BtxM<)3^ETm~J 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 z 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.Ou}?=g@BVU($g3JVn&O4K!G1 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 z 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�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