From a4e456f30fda1d168bc4f03a798a67fbdb6b9e62 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 22 Jun 2023 13:41:50 -0700 Subject: [PATCH 01/13] "Un-materialize" __dict__s if possible --- Include/internal/pycore_dict.h | 2 + Objects/typeobject.c | 3 - Python/bytecodes.c | 30 ++- Python/generated_cases.c.h | 473 +++++++++++++++++---------------- 4 files changed, 276 insertions(+), 232 deletions(-) diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h index 6253e0841ad349..90be253f12edab 100644 --- a/Include/internal/pycore_dict.h +++ b/Include/internal/pycore_dict.h @@ -42,6 +42,8 @@ extern uint32_t _PyDictKeys_GetVersionForCurrentState( extern size_t _PyDict_KeysSize(PyDictKeysObject *keys); +extern void _PyDictKeys_DecRef(PyDictKeysObject *keys); + /* _Py_dict_lookup() returns index of entry which can be used like DK_ENTRIES(dk)[index]. * -1 when no entry found, -3 when compare raises error. */ diff --git a/Objects/typeobject.c b/Objects/typeobject.c index d427ecd50a76fc..b1766d03cbb639 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4962,9 +4962,6 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) return res; } -extern void -_PyDictKeys_DecRef(PyDictKeysObject *keys); - static void type_dealloc_common(PyTypeObject *type) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 3ef8ed0ccaafdc..9566f734be382b 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1831,9 +1831,9 @@ dummy_func( 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); + 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(FRAME_CO_NAMES, oparg>>1); @@ -1849,7 +1849,29 @@ dummy_func( DEOPT_IF(ep->me_key != name, LOAD_ATTR); res = ep->me_value; } - DEOPT_IF(res == NULL, LOAD_ATTR); + if (res == NULL) { + // This is almost never an AttributeError... it's way more + // likely that this __dict__ still shares its keys (for example, + // if it was materialized on request and not heavily modified). + // If that's the case, we probably have an opportunity to do + // something *really* cool: un-materialize it! + PyDictKeysObject *keys = dict->ma_keys; + PyDictValues *values = dict->ma_values; + if (Py_REFCNT(dict) == 1 + && _PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) + && keys == ((PyHeapTypeObject *)tp)->ht_cached_keys) + { + assert(values); + // Don't try this at home, kids: + dict->ma_keys = NULL; + dict->ma_values = NULL; + Py_DECREF(dict); + _PyDictKeys_DecRef(keys); + _PyDictOrValues_SetValues(dorv, values); + GO_TO_INSTRUCTION(LOAD_ATTR_INSTANCE_VALUE); + } + DEOPT_IF(true, LOAD_ATTR); + } STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 11ca535adfb19b..d9d6d2605047e3 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2514,6 +2514,7 @@ } TARGET(LOAD_ATTR_INSTANCE_VALUE) { + PREDICTED(LOAD_ATTR_INSTANCE_VALUE); PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; @@ -2532,7 +2533,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2536 "Python/generated_cases.c.h" + #line 2537 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2560,7 +2561,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2564 "Python/generated_cases.c.h" + #line 2565 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2580,9 +2581,9 @@ 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); + 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(FRAME_CO_NAMES, oparg>>1); @@ -2598,11 +2599,33 @@ DEOPT_IF(ep->me_key != name, LOAD_ATTR); res = ep->me_value; } - DEOPT_IF(res == NULL, LOAD_ATTR); + if (res == NULL) { + // This is almost never an AttributeError... it's way more + // likely that this __dict__ still shares its keys (for example, + // if it was materialized on request and not heavily modified). + // If that's the case, we probably have an opportunity to do + // something *really* cool: un-materialize it! + PyDictKeysObject *keys = dict->ma_keys; + PyDictValues *values = dict->ma_values; + if (Py_REFCNT(dict) == 1 + && _PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) + && keys == ((PyHeapTypeObject *)tp)->ht_cached_keys) + { + assert(values); + // Don't try this at home, kids: + dict->ma_keys = NULL; + dict->ma_values = NULL; + Py_DECREF(dict); + _PyDictKeys_DecRef(keys); + _PyDictOrValues_SetValues(dorv, values); + GO_TO_INSTRUCTION(LOAD_ATTR_INSTANCE_VALUE); + } + DEOPT_IF(true, LOAD_ATTR); + } STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2606 "Python/generated_cases.c.h" + #line 2629 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2617,7 +2640,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1860 "Python/bytecodes.c" + #line 1882 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2627,7 +2650,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2631 "Python/generated_cases.c.h" + #line 2654 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2642,7 +2665,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1873 "Python/bytecodes.c" + #line 1895 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2654,7 +2677,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2658 "Python/generated_cases.c.h" + #line 2681 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2668,7 +2691,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1888 "Python/bytecodes.c" + #line 1910 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2692,7 +2715,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2696 "Python/generated_cases.c.h" + #line 2719 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2700,7 +2723,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1914 "Python/bytecodes.c" + #line 1936 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2726,7 +2749,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2730 "Python/generated_cases.c.h" + #line 2753 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2734,7 +2757,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1942 "Python/bytecodes.c" + #line 1964 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2752,7 +2775,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2756 "Python/generated_cases.c.h" + #line 2779 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2763,7 +2786,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1962 "Python/bytecodes.c" + #line 1984 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2802,7 +2825,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2806 "Python/generated_cases.c.h" + #line 2829 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2813,7 +2836,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 2003 "Python/bytecodes.c" + #line 2025 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2823,7 +2846,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2827 "Python/generated_cases.c.h" + #line 2850 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2835,7 +2858,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2022 "Python/bytecodes.c" + #line 2044 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2848,12 +2871,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2852 "Python/generated_cases.c.h" + #line 2875 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2035 "Python/bytecodes.c" + #line 2057 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2857 "Python/generated_cases.c.h" + #line 2880 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2864,7 +2887,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2039 "Python/bytecodes.c" + #line 2061 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2875,7 +2898,7 @@ _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2879 "Python/generated_cases.c.h" + #line 2902 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2886,7 +2909,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2053 "Python/bytecodes.c" + #line 2075 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -2901,7 +2924,7 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2905 "Python/generated_cases.c.h" + #line 2928 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2912,7 +2935,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2071 "Python/bytecodes.c" + #line 2093 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2924,7 +2947,7 @@ assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; - #line 2928 "Python/generated_cases.c.h" + #line 2951 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2935,14 +2958,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2085 "Python/bytecodes.c" + #line 2107 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2941 "Python/generated_cases.c.h" + #line 2964 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2087 "Python/bytecodes.c" + #line 2109 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 2946 "Python/generated_cases.c.h" + #line 2969 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2952,15 +2975,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2091 "Python/bytecodes.c" + #line 2113 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2958 "Python/generated_cases.c.h" + #line 2981 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2093 "Python/bytecodes.c" + #line 2115 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 2964 "Python/generated_cases.c.h" + #line 2987 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2971,12 +2994,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2098 "Python/bytecodes.c" + #line 2120 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 2977 "Python/generated_cases.c.h" + #line 3000 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2100 "Python/bytecodes.c" + #line 2122 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -2984,10 +3007,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 2988 "Python/generated_cases.c.h" + #line 3011 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2108 "Python/bytecodes.c" + #line 2130 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -2996,7 +3019,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 3000 "Python/generated_cases.c.h" + #line 3023 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -3006,21 +3029,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2119 "Python/bytecodes.c" + #line 2141 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 3013 "Python/generated_cases.c.h" + #line 3036 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2122 "Python/bytecodes.c" + #line 2144 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 3020 "Python/generated_cases.c.h" + #line 3043 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2127 "Python/bytecodes.c" + #line 2149 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 3024 "Python/generated_cases.c.h" + #line 3047 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -3029,15 +3052,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2131 "Python/bytecodes.c" + #line 2153 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 3036 "Python/generated_cases.c.h" + #line 3059 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2134 "Python/bytecodes.c" + #line 2156 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 3041 "Python/generated_cases.c.h" + #line 3064 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -3046,25 +3069,25 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2138 "Python/bytecodes.c" + #line 2160 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 3054 "Python/generated_cases.c.h" + #line 3077 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2144 "Python/bytecodes.c" + #line 2166 "Python/bytecodes.c" JUMPBY(oparg); - #line 3063 "Python/generated_cases.c.h" + #line 3086 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { - #line 2148 "Python/bytecodes.c" + #line 2170 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr - 1; assert(oparg <= INSTR_OFFSET()); JUMPBY(1-oparg); @@ -3082,13 +3105,13 @@ goto resume_frame; } #endif /* ENABLE_SPECIALIZATION */ - #line 3086 "Python/generated_cases.c.h" + #line 3109 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(ENTER_EXECUTOR) { - #line 2179 "Python/bytecodes.c" + #line 2201 "Python/bytecodes.c" PyCodeObject *code = _PyFrame_GetCode(frame); _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255]; Py_INCREF(executor); @@ -3098,20 +3121,20 @@ goto error; } goto resume_frame; - #line 3102 "Python/generated_cases.c.h" + #line 3125 "Python/generated_cases.c.h" } TARGET(POP_JUMP_IF_FALSE) { PyObject *cond = stack_pointer[-1]; - #line 2191 "Python/bytecodes.c" + #line 2213 "Python/bytecodes.c" if (Py_IsFalse(cond)) { JUMPBY(oparg); } else if (!Py_IsTrue(cond)) { int err = PyObject_IsTrue(cond); - #line 3113 "Python/generated_cases.c.h" + #line 3136 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2197 "Python/bytecodes.c" + #line 2219 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -3119,22 +3142,22 @@ if (err < 0) goto pop_1_error; } } - #line 3123 "Python/generated_cases.c.h" + #line 3146 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2207 "Python/bytecodes.c" + #line 2229 "Python/bytecodes.c" if (Py_IsTrue(cond)) { JUMPBY(oparg); } else if (!Py_IsFalse(cond)) { int err = PyObject_IsTrue(cond); - #line 3136 "Python/generated_cases.c.h" + #line 3159 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2213 "Python/bytecodes.c" + #line 2235 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -3142,63 +3165,63 @@ if (err < 0) goto pop_1_error; } } - #line 3146 "Python/generated_cases.c.h" + #line 3169 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2223 "Python/bytecodes.c" + #line 2245 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 3155 "Python/generated_cases.c.h" + #line 3178 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2225 "Python/bytecodes.c" + #line 2247 "Python/bytecodes.c" JUMPBY(oparg); } - #line 3160 "Python/generated_cases.c.h" + #line 3183 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2230 "Python/bytecodes.c" + #line 2252 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { - #line 3172 "Python/generated_cases.c.h" + #line 3195 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2235 "Python/bytecodes.c" + #line 2257 "Python/bytecodes.c" } - #line 3176 "Python/generated_cases.c.h" + #line 3199 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2239 "Python/bytecodes.c" + #line 2261 "Python/bytecodes.c" /* 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); - #line 3189 "Python/generated_cases.c.h" + #line 3212 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2248 "Python/bytecodes.c" + #line 2270 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3202 "Python/generated_cases.c.h" + #line 3225 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3209,16 +3232,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2256 "Python/bytecodes.c" + #line 2278 "Python/bytecodes.c" // 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); - #line 3218 "Python/generated_cases.c.h" + #line 3241 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2261 "Python/bytecodes.c" + #line 2283 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3226,7 +3249,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 3230 "Python/generated_cases.c.h" + #line 3253 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3235,10 +3258,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2271 "Python/bytecodes.c" + #line 2293 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 3242 "Python/generated_cases.c.h" + #line 3265 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3247,10 +3270,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2276 "Python/bytecodes.c" + #line 2298 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 3254 "Python/generated_cases.c.h" + #line 3277 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3260,11 +3283,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2281 "Python/bytecodes.c" + #line 2303 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3268 "Python/generated_cases.c.h" + #line 3291 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3273,14 +3296,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2287 "Python/bytecodes.c" + #line 2309 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3280 "Python/generated_cases.c.h" + #line 3303 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2290 "Python/bytecodes.c" + #line 2312 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3284 "Python/generated_cases.c.h" + #line 3307 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3288,7 +3311,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2294 "Python/bytecodes.c" + #line 2316 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3311,11 +3334,11 @@ if (iter == NULL) { goto error; } - #line 3315 "Python/generated_cases.c.h" + #line 3338 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2317 "Python/bytecodes.c" + #line 2339 "Python/bytecodes.c" } - #line 3319 "Python/generated_cases.c.h" + #line 3342 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3325,7 +3348,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2335 "Python/bytecodes.c" + #line 2357 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3357,7 +3380,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3361 "Python/generated_cases.c.h" + #line 3384 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3365,7 +3388,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2369 "Python/bytecodes.c" + #line 2391 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3391,14 +3414,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3395 "Python/generated_cases.c.h" + #line 3418 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2397 "Python/bytecodes.c" + #line 2419 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3419,7 +3442,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3423 "Python/generated_cases.c.h" + #line 3446 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3429,7 +3452,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2420 "Python/bytecodes.c" + #line 2442 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3450,7 +3473,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3454 "Python/generated_cases.c.h" + #line 3477 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3460,7 +3483,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2443 "Python/bytecodes.c" + #line 2465 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3479,7 +3502,7 @@ if (next == NULL) { goto error; } - #line 3483 "Python/generated_cases.c.h" + #line 3506 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3488,7 +3511,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2464 "Python/bytecodes.c" + #line 2486 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3504,14 +3527,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3508 "Python/generated_cases.c.h" + #line 3531 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2482 "Python/bytecodes.c" + #line 2504 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3534,16 +3557,16 @@ Py_DECREF(enter); goto error; } - #line 3538 "Python/generated_cases.c.h" + #line 3561 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2505 "Python/bytecodes.c" + #line 2527 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3547 "Python/generated_cases.c.h" + #line 3570 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3554,7 +3577,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2514 "Python/bytecodes.c" + #line 2536 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3580,16 +3603,16 @@ Py_DECREF(enter); goto error; } - #line 3584 "Python/generated_cases.c.h" + #line 3607 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2540 "Python/bytecodes.c" + #line 2562 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3593 "Python/generated_cases.c.h" + #line 3616 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3601,7 +3624,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2549 "Python/bytecodes.c" + #line 2571 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3622,7 +3645,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3626 "Python/generated_cases.c.h" + #line 3649 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3631,7 +3654,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2588 "Python/bytecodes.c" + #line 2610 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3641,7 +3664,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3645 "Python/generated_cases.c.h" + #line 3668 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3655,7 +3678,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2600 "Python/bytecodes.c" + #line 2622 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3672,7 +3695,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3676 "Python/generated_cases.c.h" + #line 3699 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3686,7 +3709,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2619 "Python/bytecodes.c" + #line 2641 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3696,7 +3719,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3700 "Python/generated_cases.c.h" + #line 3723 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3710,7 +3733,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2631 "Python/bytecodes.c" + #line 2653 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3724,7 +3747,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3728 "Python/generated_cases.c.h" + #line 3751 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3733,16 +3756,16 @@ } TARGET(KW_NAMES) { - #line 2647 "Python/bytecodes.c" + #line 2669 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); - #line 3741 "Python/generated_cases.c.h" + #line 3764 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2653 "Python/bytecodes.c" + #line 2675 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3755,7 +3778,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3759 "Python/generated_cases.c.h" + #line 3782 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3765,7 +3788,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2699 "Python/bytecodes.c" + #line 2721 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3847,7 +3870,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3851 "Python/generated_cases.c.h" + #line 3874 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3859,7 +3882,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2787 "Python/bytecodes.c" + #line 2809 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3869,7 +3892,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3873 "Python/generated_cases.c.h" + #line 3896 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3878,7 +3901,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2799 "Python/bytecodes.c" + #line 2821 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3904,7 +3927,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3908 "Python/generated_cases.c.h" + #line 3931 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3912,7 +3935,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2827 "Python/bytecodes.c" + #line 2849 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3948,7 +3971,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3952 "Python/generated_cases.c.h" + #line 3975 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3956,7 +3979,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2865 "Python/bytecodes.c" + #line 2887 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3966,7 +3989,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3970 "Python/generated_cases.c.h" + #line 3993 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3979,7 +4002,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2877 "Python/bytecodes.c" + #line 2899 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3990,7 +4013,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3994 "Python/generated_cases.c.h" + #line 4017 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4004,7 +4027,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2891 "Python/bytecodes.c" + #line 2913 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4015,7 +4038,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4019 "Python/generated_cases.c.h" + #line 4042 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4028,7 +4051,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; - #line 2905 "Python/bytecodes.c" + #line 2927 "Python/bytecodes.c" /* This instruction does the following: * 1. Creates the object (by calling ``object.__new__``) * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) @@ -4078,12 +4101,12 @@ frame = cframe.current_frame = init_frame; CALL_STAT_INC(inlined_py_calls); goto start_frame; - #line 4082 "Python/generated_cases.c.h" + #line 4105 "Python/generated_cases.c.h" } TARGET(EXIT_INIT_CHECK) { PyObject *should_be_none = stack_pointer[-1]; - #line 2957 "Python/bytecodes.c" + #line 2979 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -4091,7 +4114,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 4095 "Python/generated_cases.c.h" + #line 4118 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -4101,7 +4124,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2967 "Python/bytecodes.c" + #line 2989 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4123,7 +4146,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4127 "Python/generated_cases.c.h" + #line 4150 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4137,7 +4160,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2992 "Python/bytecodes.c" + #line 3014 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4165,7 +4188,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4169 "Python/generated_cases.c.h" + #line 4192 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4179,7 +4202,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3023 "Python/bytecodes.c" + #line 3045 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4211,7 +4234,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4215 "Python/generated_cases.c.h" + #line 4238 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4225,7 +4248,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3058 "Python/bytecodes.c" + #line 3080 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4257,7 +4280,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4261 "Python/generated_cases.c.h" + #line 4284 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4271,7 +4294,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3093 "Python/bytecodes.c" + #line 3115 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4296,7 +4319,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4300 "Python/generated_cases.c.h" + #line 4323 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4309,7 +4332,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3120 "Python/bytecodes.c" + #line 3142 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4336,7 +4359,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4340 "Python/generated_cases.c.h" + #line 4363 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4348,7 +4371,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3150 "Python/bytecodes.c" + #line 3172 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4366,14 +4389,14 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4370 "Python/generated_cases.c.h" + #line 4393 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3170 "Python/bytecodes.c" + #line 3192 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4404,7 +4427,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4408 "Python/generated_cases.c.h" + #line 4431 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4417,7 +4440,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3204 "Python/bytecodes.c" + #line 3226 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4446,7 +4469,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4450 "Python/generated_cases.c.h" + #line 4473 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4459,7 +4482,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3236 "Python/bytecodes.c" + #line 3258 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4488,7 +4511,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4492 "Python/generated_cases.c.h" + #line 4515 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4501,7 +4524,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3268 "Python/bytecodes.c" + #line 3290 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4529,7 +4552,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4533 "Python/generated_cases.c.h" + #line 4556 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4539,9 +4562,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3299 "Python/bytecodes.c" + #line 3321 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4545 "Python/generated_cases.c.h" + #line 4568 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4550,7 +4573,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3303 "Python/bytecodes.c" + #line 3325 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4612,14 +4635,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4616 "Python/generated_cases.c.h" + #line 4639 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3365 "Python/bytecodes.c" + #line 3387 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4623 "Python/generated_cases.c.h" + #line 4646 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4630,7 +4653,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3371 "Python/bytecodes.c" + #line 3393 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4642,7 +4665,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4646 "Python/generated_cases.c.h" + #line 4669 "Python/generated_cases.c.h" stack_pointer[-1] = func; DISPATCH(); } @@ -4650,7 +4673,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3385 "Python/bytecodes.c" + #line 3407 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4675,14 +4698,14 @@ default: Py_UNREACHABLE(); } - #line 4679 "Python/generated_cases.c.h" + #line 4702 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3412 "Python/bytecodes.c" + #line 3434 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4703,7 +4726,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4707 "Python/generated_cases.c.h" + #line 4730 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4711,15 +4734,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3435 "Python/bytecodes.c" + #line 3457 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4717 "Python/generated_cases.c.h" + #line 4740 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3437 "Python/bytecodes.c" + #line 3459 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4723 "Python/generated_cases.c.h" + #line 4746 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4729,14 +4752,14 @@ TARGET(CONVERT_VALUE) { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3441 "Python/bytecodes.c" + #line 3463 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 4740 "Python/generated_cases.c.h" + #line 4763 "Python/generated_cases.c.h" stack_pointer[-1] = result; DISPATCH(); } @@ -4744,7 +4767,7 @@ TARGET(FORMAT_SIMPLE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3450 "Python/bytecodes.c" + #line 3472 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -4755,7 +4778,7 @@ else { res = value; } - #line 4759 "Python/generated_cases.c.h" + #line 4782 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -4764,12 +4787,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3463 "Python/bytecodes.c" + #line 3485 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 4773 "Python/generated_cases.c.h" + #line 4796 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -4778,10 +4801,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3470 "Python/bytecodes.c" + #line 3492 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4785 "Python/generated_cases.c.h" + #line 4808 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4793,7 +4816,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3475 "Python/bytecodes.c" + #line 3497 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4808,12 +4831,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4812 "Python/generated_cases.c.h" + #line 4835 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3490 "Python/bytecodes.c" + #line 3512 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4817 "Python/generated_cases.c.h" + #line 4840 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4823,16 +4846,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3495 "Python/bytecodes.c" + #line 3517 "Python/bytecodes.c" assert(oparg >= 2); - #line 4829 "Python/generated_cases.c.h" + #line 4852 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3499 "Python/bytecodes.c" + #line 3521 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4844,26 +4867,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4848 "Python/generated_cases.c.h" + #line 4871 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3513 "Python/bytecodes.c" + #line 3535 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4854 "Python/generated_cases.c.h" + #line 4877 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3517 "Python/bytecodes.c" + #line 3539 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 4861 "Python/generated_cases.c.h" + #line 4884 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3522 "Python/bytecodes.c" + #line 3544 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4872,12 +4895,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4876 "Python/generated_cases.c.h" + #line 4899 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3533 "Python/bytecodes.c" + #line 3555 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4886,12 +4909,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4890 "Python/generated_cases.c.h" + #line 4913 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3544 "Python/bytecodes.c" + #line 3566 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4903,12 +4926,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4907 "Python/generated_cases.c.h" + #line 4930 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3558 "Python/bytecodes.c" + #line 3580 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4920,30 +4943,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4924 "Python/generated_cases.c.h" + #line 4947 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3572 "Python/bytecodes.c" + #line 3594 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4935 "Python/generated_cases.c.h" + #line 4958 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3580 "Python/bytecodes.c" + #line 3602 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4942 "Python/generated_cases.c.h" + #line 4965 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3585 "Python/bytecodes.c" + #line 3607 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4949 "Python/generated_cases.c.h" + #line 4972 "Python/generated_cases.c.h" } From 716cc5a5a8b4e4f919bc42f37df03d5657c3fa0f Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 29 Jun 2023 12:26:07 -0700 Subject: [PATCH 02/13] Add stats --- Include/pystats.h | 1 + Python/bytecodes.c | 40 ++-- Python/generated_cases.c.h | 478 ++++++++++++++++++------------------- Python/specialize.c | 1 + 4 files changed, 259 insertions(+), 261 deletions(-) diff --git a/Include/pystats.h b/Include/pystats.h index 034bf05bfe290f..e212a42c73ca70 100644 --- a/Include/pystats.h +++ b/Include/pystats.h @@ -65,6 +65,7 @@ typedef struct _object_stats { uint64_t dict_materialized_new_key; uint64_t dict_materialized_too_big; uint64_t dict_materialized_str_subclass; + uint64_t dict_unmaterialized; uint64_t type_cache_hits; uint64_t type_cache_misses; uint64_t type_cache_dunder_hits; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 9566f734be382b..02d2aadc44c5a6 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1850,27 +1850,25 @@ dummy_func( res = ep->me_value; } if (res == NULL) { - // This is almost never an AttributeError... it's way more - // likely that this __dict__ still shares its keys (for example, - // if it was materialized on request and not heavily modified). - // If that's the case, we probably have an opportunity to do - // something *really* cool: un-materialize it! - PyDictKeysObject *keys = dict->ma_keys; - PyDictValues *values = dict->ma_values; - if (Py_REFCNT(dict) == 1 - && _PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) - && keys == ((PyHeapTypeObject *)tp)->ht_cached_keys) - { - assert(values); - // Don't try this at home, kids: - dict->ma_keys = NULL; - dict->ma_values = NULL; - Py_DECREF(dict); - _PyDictKeys_DecRef(keys); - _PyDictOrValues_SetValues(dorv, values); - GO_TO_INSTRUCTION(LOAD_ATTR_INSTANCE_VALUE); - } - DEOPT_IF(true, LOAD_ATTR); + // This is almost never an AttributeError. It's way more likely + // that this __dict__ still shares its keys (for example, if it + // was materialized on request and not heavily modified): + DEOPT_IF(!_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), LOAD_ATTR); + PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; + DEOPT_IF(dict->ma_keys != ht->ht_cached_keys, LOAD_ATTR); + assert(dict->ma_values); + DEOPT_IF(Py_REFCNT(dict) != 1, LOAD_ATTR); + // We have an opportunity to do something *really* cool: + // un-materialize it! + _PyDictKeys_DecRef(dict->ma_keys); + _PyDictOrValues_SetValues(dorv, dict->ma_values); + OBJECT_STAT_INC(dict_unmaterialized); + // Don't try this at home, kids: + dict->ma_keys = NULL; + dict->ma_values = NULL; + Py_DECREF(dict); + // Guess what... our caches are still valid! + GO_TO_INSTRUCTION(LOAD_ATTR_INSTANCE_VALUE); } STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index d9d6d2605047e3..f5e369815246e4 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2600,32 +2600,30 @@ res = ep->me_value; } if (res == NULL) { - // This is almost never an AttributeError... it's way more - // likely that this __dict__ still shares its keys (for example, - // if it was materialized on request and not heavily modified). - // If that's the case, we probably have an opportunity to do - // something *really* cool: un-materialize it! - PyDictKeysObject *keys = dict->ma_keys; - PyDictValues *values = dict->ma_values; - if (Py_REFCNT(dict) == 1 - && _PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) - && keys == ((PyHeapTypeObject *)tp)->ht_cached_keys) - { - assert(values); - // Don't try this at home, kids: - dict->ma_keys = NULL; - dict->ma_values = NULL; - Py_DECREF(dict); - _PyDictKeys_DecRef(keys); - _PyDictOrValues_SetValues(dorv, values); - GO_TO_INSTRUCTION(LOAD_ATTR_INSTANCE_VALUE); - } - DEOPT_IF(true, LOAD_ATTR); + // This is almost never an AttributeError. It's way more likely + // that this __dict__ still shares its keys (for example, if it + // was materialized on request and not heavily modified): + DEOPT_IF(!_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), LOAD_ATTR); + PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; + DEOPT_IF(dict->ma_keys != ht->ht_cached_keys, LOAD_ATTR); + assert(dict->ma_values); + DEOPT_IF(Py_REFCNT(dict) != 1, LOAD_ATTR); + // We have an opportunity to do something *really* cool: + // un-materialize it! + _PyDictKeys_DecRef(dict->ma_keys); + _PyDictOrValues_SetValues(dorv, dict->ma_values); + OBJECT_STAT_INC(dict_unmaterialized); + // Don't try this at home, kids: + dict->ma_keys = NULL; + dict->ma_values = NULL; + Py_DECREF(dict); + // Guess what... our caches are still valid! + GO_TO_INSTRUCTION(LOAD_ATTR_INSTANCE_VALUE); } STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2629 "Python/generated_cases.c.h" + #line 2627 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2640,7 +2638,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1882 "Python/bytecodes.c" + #line 1880 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2650,7 +2648,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2654 "Python/generated_cases.c.h" + #line 2652 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2665,7 +2663,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 1895 "Python/bytecodes.c" + #line 1893 "Python/bytecodes.c" DEOPT_IF(!PyType_Check(cls), LOAD_ATTR); DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version, @@ -2677,7 +2675,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2681 "Python/generated_cases.c.h" + #line 2679 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2691,7 +2689,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *fget = read_obj(&next_instr[5].cache); - #line 1910 "Python/bytecodes.c" + #line 1908 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); @@ -2715,7 +2713,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2719 "Python/generated_cases.c.h" + #line 2717 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2723,7 +2721,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t func_version = read_u32(&next_instr[3].cache); PyObject *getattribute = read_obj(&next_instr[5].cache); - #line 1936 "Python/bytecodes.c" + #line 1934 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR); PyTypeObject *cls = Py_TYPE(owner); DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR); @@ -2749,7 +2747,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2753 "Python/generated_cases.c.h" + #line 2751 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2757,7 +2755,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1964 "Python/bytecodes.c" + #line 1962 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2775,7 +2773,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2779 "Python/generated_cases.c.h" + #line 2777 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2786,7 +2784,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t hint = read_u16(&next_instr[3].cache); - #line 1984 "Python/bytecodes.c" + #line 1982 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2825,7 +2823,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2829 "Python/generated_cases.c.h" + #line 2827 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2836,7 +2834,7 @@ PyObject *value = stack_pointer[-2]; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 2025 "Python/bytecodes.c" + #line 2023 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR); @@ -2846,7 +2844,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2850 "Python/generated_cases.c.h" + #line 2848 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2858,7 +2856,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2044 "Python/bytecodes.c" + #line 2042 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2871,12 +2869,12 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 4) <= Py_GE); res = PyObject_RichCompare(left, right, oparg>>4); - #line 2875 "Python/generated_cases.c.h" + #line 2873 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2057 "Python/bytecodes.c" + #line 2055 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2880 "Python/generated_cases.c.h" + #line 2878 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2887,7 +2885,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2061 "Python/bytecodes.c" + #line 2059 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2898,7 +2896,7 @@ _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2902 "Python/generated_cases.c.h" + #line 2900 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2909,7 +2907,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2075 "Python/bytecodes.c" + #line 2073 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP); DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP); @@ -2924,7 +2922,7 @@ _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; - #line 2928 "Python/generated_cases.c.h" + #line 2926 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2935,7 +2933,7 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *res; - #line 2093 "Python/bytecodes.c" + #line 2091 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP); DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP); STAT_INC(COMPARE_OP, hit); @@ -2947,7 +2945,7 @@ assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS); assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; - #line 2951 "Python/generated_cases.c.h" + #line 2949 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -2958,14 +2956,14 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2107 "Python/bytecodes.c" + #line 2105 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 2964 "Python/generated_cases.c.h" + #line 2962 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2109 "Python/bytecodes.c" + #line 2107 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 2969 "Python/generated_cases.c.h" + #line 2967 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2975,15 +2973,15 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2113 "Python/bytecodes.c" + #line 2111 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 2981 "Python/generated_cases.c.h" + #line 2979 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); - #line 2115 "Python/bytecodes.c" + #line 2113 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 2987 "Python/generated_cases.c.h" + #line 2985 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -2994,12 +2992,12 @@ PyObject *exc_value = stack_pointer[-2]; PyObject *rest; PyObject *match; - #line 2120 "Python/bytecodes.c" + #line 2118 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 3000 "Python/generated_cases.c.h" + #line 2998 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2122 "Python/bytecodes.c" + #line 2120 "Python/bytecodes.c" if (true) goto pop_2_error; } @@ -3007,10 +3005,10 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 3011 "Python/generated_cases.c.h" + #line 3009 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); - #line 2130 "Python/bytecodes.c" + #line 2128 "Python/bytecodes.c" if (res < 0) goto pop_2_error; assert((match == NULL) == (rest == NULL)); @@ -3019,7 +3017,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 3023 "Python/generated_cases.c.h" + #line 3021 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -3029,21 +3027,21 @@ PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; PyObject *b; - #line 2141 "Python/bytecodes.c" + #line 2139 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 3036 "Python/generated_cases.c.h" + #line 3034 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2144 "Python/bytecodes.c" + #line 2142 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 3043 "Python/generated_cases.c.h" + #line 3041 "Python/generated_cases.c.h" Py_DECREF(right); - #line 2149 "Python/bytecodes.c" + #line 2147 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 3047 "Python/generated_cases.c.h" + #line 3045 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -3052,15 +3050,15 @@ PyObject *fromlist = stack_pointer[-1]; PyObject *level = stack_pointer[-2]; PyObject *res; - #line 2153 "Python/bytecodes.c" + #line 2151 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 3059 "Python/generated_cases.c.h" + #line 3057 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); - #line 2156 "Python/bytecodes.c" + #line 2154 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 3064 "Python/generated_cases.c.h" + #line 3062 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -3069,25 +3067,25 @@ TARGET(IMPORT_FROM) { PyObject *from = stack_pointer[-1]; PyObject *res; - #line 2160 "Python/bytecodes.c" + #line 2158 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 3077 "Python/generated_cases.c.h" + #line 3075 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); } TARGET(JUMP_FORWARD) { - #line 2166 "Python/bytecodes.c" + #line 2164 "Python/bytecodes.c" JUMPBY(oparg); - #line 3086 "Python/generated_cases.c.h" + #line 3084 "Python/generated_cases.c.h" DISPATCH(); } TARGET(JUMP_BACKWARD) { - #line 2170 "Python/bytecodes.c" + #line 2168 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr - 1; assert(oparg <= INSTR_OFFSET()); JUMPBY(1-oparg); @@ -3105,13 +3103,13 @@ goto resume_frame; } #endif /* ENABLE_SPECIALIZATION */ - #line 3109 "Python/generated_cases.c.h" + #line 3107 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(ENTER_EXECUTOR) { - #line 2201 "Python/bytecodes.c" + #line 2199 "Python/bytecodes.c" PyCodeObject *code = _PyFrame_GetCode(frame); _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255]; Py_INCREF(executor); @@ -3121,20 +3119,20 @@ goto error; } goto resume_frame; - #line 3125 "Python/generated_cases.c.h" + #line 3123 "Python/generated_cases.c.h" } TARGET(POP_JUMP_IF_FALSE) { PyObject *cond = stack_pointer[-1]; - #line 2213 "Python/bytecodes.c" + #line 2211 "Python/bytecodes.c" if (Py_IsFalse(cond)) { JUMPBY(oparg); } else if (!Py_IsTrue(cond)) { int err = PyObject_IsTrue(cond); - #line 3136 "Python/generated_cases.c.h" + #line 3134 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2219 "Python/bytecodes.c" + #line 2217 "Python/bytecodes.c" if (err == 0) { JUMPBY(oparg); } @@ -3142,22 +3140,22 @@ if (err < 0) goto pop_1_error; } } - #line 3146 "Python/generated_cases.c.h" + #line 3144 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_TRUE) { PyObject *cond = stack_pointer[-1]; - #line 2229 "Python/bytecodes.c" + #line 2227 "Python/bytecodes.c" if (Py_IsTrue(cond)) { JUMPBY(oparg); } else if (!Py_IsFalse(cond)) { int err = PyObject_IsTrue(cond); - #line 3159 "Python/generated_cases.c.h" + #line 3157 "Python/generated_cases.c.h" Py_DECREF(cond); - #line 2235 "Python/bytecodes.c" + #line 2233 "Python/bytecodes.c" if (err > 0) { JUMPBY(oparg); } @@ -3165,63 +3163,63 @@ if (err < 0) goto pop_1_error; } } - #line 3169 "Python/generated_cases.c.h" + #line 3167 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NOT_NONE) { PyObject *value = stack_pointer[-1]; - #line 2245 "Python/bytecodes.c" + #line 2243 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 3178 "Python/generated_cases.c.h" + #line 3176 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2247 "Python/bytecodes.c" + #line 2245 "Python/bytecodes.c" JUMPBY(oparg); } - #line 3183 "Python/generated_cases.c.h" + #line 3181 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(POP_JUMP_IF_NONE) { PyObject *value = stack_pointer[-1]; - #line 2252 "Python/bytecodes.c" + #line 2250 "Python/bytecodes.c" if (Py_IsNone(value)) { JUMPBY(oparg); } else { - #line 3195 "Python/generated_cases.c.h" + #line 3193 "Python/generated_cases.c.h" Py_DECREF(value); - #line 2257 "Python/bytecodes.c" + #line 2255 "Python/bytecodes.c" } - #line 3199 "Python/generated_cases.c.h" + #line 3197 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } TARGET(JUMP_BACKWARD_NO_INTERRUPT) { - #line 2261 "Python/bytecodes.c" + #line 2259 "Python/bytecodes.c" /* 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); - #line 3212 "Python/generated_cases.c.h" + #line 3210 "Python/generated_cases.c.h" DISPATCH(); } TARGET(GET_LEN) { PyObject *obj = stack_pointer[-1]; PyObject *len_o; - #line 2270 "Python/bytecodes.c" + #line 2268 "Python/bytecodes.c" // PUSH(len(TOS)) Py_ssize_t len_i = PyObject_Length(obj); if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3225 "Python/generated_cases.c.h" + #line 3223 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3232,16 +3230,16 @@ PyObject *type = stack_pointer[-2]; PyObject *subject = stack_pointer[-3]; PyObject *attrs; - #line 2278 "Python/bytecodes.c" + #line 2276 "Python/bytecodes.c" // 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); - #line 3241 "Python/generated_cases.c.h" + #line 3239 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); - #line 2283 "Python/bytecodes.c" + #line 2281 "Python/bytecodes.c" if (attrs) { assert(PyTuple_CheckExact(attrs)); // Success! } @@ -3249,7 +3247,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 3253 "Python/generated_cases.c.h" + #line 3251 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3258,10 +3256,10 @@ TARGET(MATCH_MAPPING) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2293 "Python/bytecodes.c" + #line 2291 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 3265 "Python/generated_cases.c.h" + #line 3263 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3270,10 +3268,10 @@ TARGET(MATCH_SEQUENCE) { PyObject *subject = stack_pointer[-1]; PyObject *res; - #line 2298 "Python/bytecodes.c" + #line 2296 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 3277 "Python/generated_cases.c.h" + #line 3275 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3283,11 +3281,11 @@ PyObject *keys = stack_pointer[-1]; PyObject *subject = stack_pointer[-2]; PyObject *values_or_none; - #line 2303 "Python/bytecodes.c" + #line 2301 "Python/bytecodes.c" // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3291 "Python/generated_cases.c.h" + #line 3289 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3296,14 +3294,14 @@ TARGET(GET_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2309 "Python/bytecodes.c" + #line 2307 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3303 "Python/generated_cases.c.h" + #line 3301 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2312 "Python/bytecodes.c" + #line 2310 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3307 "Python/generated_cases.c.h" + #line 3305 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3311,7 +3309,7 @@ TARGET(GET_YIELD_FROM_ITER) { PyObject *iterable = stack_pointer[-1]; PyObject *iter; - #line 2316 "Python/bytecodes.c" + #line 2314 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ if (PyCoro_CheckExact(iterable)) { /* `iterable` is a coroutine */ @@ -3334,11 +3332,11 @@ if (iter == NULL) { goto error; } - #line 3338 "Python/generated_cases.c.h" + #line 3336 "Python/generated_cases.c.h" Py_DECREF(iterable); - #line 2339 "Python/bytecodes.c" + #line 2337 "Python/bytecodes.c" } - #line 3342 "Python/generated_cases.c.h" + #line 3340 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3348,7 +3346,7 @@ static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2357 "Python/bytecodes.c" + #line 2355 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -3380,7 +3378,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3384 "Python/generated_cases.c.h" + #line 3382 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3388,7 +3386,7 @@ } TARGET(INSTRUMENTED_FOR_ITER) { - #line 2391 "Python/bytecodes.c" + #line 2389 "Python/bytecodes.c" _Py_CODEUNIT *here = next_instr-1; _Py_CODEUNIT *target; PyObject *iter = TOP(); @@ -3414,14 +3412,14 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3418 "Python/generated_cases.c.h" + #line 3416 "Python/generated_cases.c.h" DISPATCH(); } TARGET(FOR_ITER_LIST) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2419 "Python/bytecodes.c" + #line 2417 "Python/bytecodes.c" DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); @@ -3442,7 +3440,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3446 "Python/generated_cases.c.h" + #line 3444 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3452,7 +3450,7 @@ TARGET(FOR_ITER_TUPLE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2442 "Python/bytecodes.c" + #line 2440 "Python/bytecodes.c" _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3473,7 +3471,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3477 "Python/generated_cases.c.h" + #line 3475 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3483,7 +3481,7 @@ TARGET(FOR_ITER_RANGE) { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2465 "Python/bytecodes.c" + #line 2463 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3502,7 +3500,7 @@ if (next == NULL) { goto error; } - #line 3506 "Python/generated_cases.c.h" + #line 3504 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3511,7 +3509,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2486 "Python/bytecodes.c" + #line 2484 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3527,14 +3525,14 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3531 "Python/generated_cases.c.h" + #line 3529 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2504 "Python/bytecodes.c" + #line 2502 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3557,16 +3555,16 @@ Py_DECREF(enter); goto error; } - #line 3561 "Python/generated_cases.c.h" + #line 3559 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2527 "Python/bytecodes.c" + #line 2525 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3570 "Python/generated_cases.c.h" + #line 3568 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3577,7 +3575,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2536 "Python/bytecodes.c" + #line 2534 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3603,16 +3601,16 @@ Py_DECREF(enter); goto error; } - #line 3607 "Python/generated_cases.c.h" + #line 3605 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2562 "Python/bytecodes.c" + #line 2560 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3616 "Python/generated_cases.c.h" + #line 3614 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3624,7 +3622,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2571 "Python/bytecodes.c" + #line 2569 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3645,7 +3643,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3649 "Python/generated_cases.c.h" + #line 3647 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3654,7 +3652,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2610 "Python/bytecodes.c" + #line 2608 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3664,7 +3662,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3668 "Python/generated_cases.c.h" + #line 3666 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3678,7 +3676,7 @@ uint32_t type_version = read_u32(&next_instr[1].cache); uint32_t keys_version = read_u32(&next_instr[3].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2622 "Python/bytecodes.c" + #line 2620 "Python/bytecodes.c" /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3695,7 +3693,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3699 "Python/generated_cases.c.h" + #line 3697 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3709,7 +3707,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2641 "Python/bytecodes.c" + #line 2639 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); assert(self_cls->tp_dictoffset == 0); @@ -3719,7 +3717,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3723 "Python/generated_cases.c.h" + #line 3721 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3733,7 +3731,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2653 "Python/bytecodes.c" + #line 2651 "Python/bytecodes.c" PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); Py_ssize_t dictoffset = self_cls->tp_dictoffset; @@ -3747,7 +3745,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3751 "Python/generated_cases.c.h" + #line 3749 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3756,16 +3754,16 @@ } TARGET(KW_NAMES) { - #line 2669 "Python/bytecodes.c" + #line 2667 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); - #line 3764 "Python/generated_cases.c.h" + #line 3762 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_CALL) { - #line 2675 "Python/bytecodes.c" + #line 2673 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3778,7 +3776,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3782 "Python/generated_cases.c.h" + #line 3780 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3788,7 +3786,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2721 "Python/bytecodes.c" + #line 2719 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3870,7 +3868,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3874 "Python/generated_cases.c.h" + #line 3872 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3882,7 +3880,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2809 "Python/bytecodes.c" + #line 2807 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3892,7 +3890,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3896 "Python/generated_cases.c.h" + #line 3894 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -3901,7 +3899,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2821 "Python/bytecodes.c" + #line 2819 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3927,7 +3925,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3931 "Python/generated_cases.c.h" + #line 3929 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -3935,7 +3933,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2849 "Python/bytecodes.c" + #line 2847 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -3971,7 +3969,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 3975 "Python/generated_cases.c.h" + #line 3973 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -3979,7 +3977,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2887 "Python/bytecodes.c" + #line 2885 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -3989,7 +3987,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 3993 "Python/generated_cases.c.h" + #line 3991 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4002,7 +4000,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2899 "Python/bytecodes.c" + #line 2897 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4013,7 +4011,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4017 "Python/generated_cases.c.h" + #line 4015 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4027,7 +4025,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2913 "Python/bytecodes.c" + #line 2911 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4038,7 +4036,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4042 "Python/generated_cases.c.h" + #line 4040 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4051,7 +4049,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; - #line 2927 "Python/bytecodes.c" + #line 2925 "Python/bytecodes.c" /* This instruction does the following: * 1. Creates the object (by calling ``object.__new__``) * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) @@ -4101,12 +4099,12 @@ frame = cframe.current_frame = init_frame; CALL_STAT_INC(inlined_py_calls); goto start_frame; - #line 4105 "Python/generated_cases.c.h" + #line 4103 "Python/generated_cases.c.h" } TARGET(EXIT_INIT_CHECK) { PyObject *should_be_none = stack_pointer[-1]; - #line 2979 "Python/bytecodes.c" + #line 2977 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -4114,7 +4112,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 4118 "Python/generated_cases.c.h" + #line 4116 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -4124,7 +4122,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2989 "Python/bytecodes.c" + #line 2987 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4146,7 +4144,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4150 "Python/generated_cases.c.h" + #line 4148 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4160,7 +4158,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3014 "Python/bytecodes.c" + #line 3012 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4188,7 +4186,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4192 "Python/generated_cases.c.h" + #line 4190 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4202,7 +4200,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3045 "Python/bytecodes.c" + #line 3043 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4234,7 +4232,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4238 "Python/generated_cases.c.h" + #line 4236 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4248,7 +4246,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3080 "Python/bytecodes.c" + #line 3078 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4280,7 +4278,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4284 "Python/generated_cases.c.h" + #line 4282 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4294,7 +4292,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3115 "Python/bytecodes.c" + #line 3113 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4319,7 +4317,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4323 "Python/generated_cases.c.h" + #line 4321 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4332,7 +4330,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3142 "Python/bytecodes.c" + #line 3140 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4359,7 +4357,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4363 "Python/generated_cases.c.h" + #line 4361 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4371,7 +4369,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3172 "Python/bytecodes.c" + #line 3170 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4389,14 +4387,14 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4393 "Python/generated_cases.c.h" + #line 4391 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3192 "Python/bytecodes.c" + #line 3190 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4427,7 +4425,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4431 "Python/generated_cases.c.h" + #line 4429 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4440,7 +4438,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3226 "Python/bytecodes.c" + #line 3224 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4469,7 +4467,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4473 "Python/generated_cases.c.h" + #line 4471 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4482,7 +4480,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3258 "Python/bytecodes.c" + #line 3256 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4511,7 +4509,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4515 "Python/generated_cases.c.h" + #line 4513 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4524,7 +4522,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3290 "Python/bytecodes.c" + #line 3288 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4552,7 +4550,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4556 "Python/generated_cases.c.h" + #line 4554 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4562,9 +4560,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3321 "Python/bytecodes.c" + #line 3319 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4568 "Python/generated_cases.c.h" + #line 4566 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4573,7 +4571,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3325 "Python/bytecodes.c" + #line 3323 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4635,14 +4633,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4639 "Python/generated_cases.c.h" + #line 4637 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3387 "Python/bytecodes.c" + #line 3385 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4646 "Python/generated_cases.c.h" + #line 4644 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4653,7 +4651,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3393 "Python/bytecodes.c" + #line 3391 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4665,7 +4663,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4669 "Python/generated_cases.c.h" + #line 4667 "Python/generated_cases.c.h" stack_pointer[-1] = func; DISPATCH(); } @@ -4673,7 +4671,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3407 "Python/bytecodes.c" + #line 3405 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4698,14 +4696,14 @@ default: Py_UNREACHABLE(); } - #line 4702 "Python/generated_cases.c.h" + #line 4700 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3434 "Python/bytecodes.c" + #line 3432 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4726,7 +4724,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4730 "Python/generated_cases.c.h" + #line 4728 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4734,15 +4732,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3457 "Python/bytecodes.c" + #line 3455 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4740 "Python/generated_cases.c.h" + #line 4738 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3459 "Python/bytecodes.c" + #line 3457 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4746 "Python/generated_cases.c.h" + #line 4744 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4752,14 +4750,14 @@ TARGET(CONVERT_VALUE) { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3463 "Python/bytecodes.c" + #line 3461 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 4763 "Python/generated_cases.c.h" + #line 4761 "Python/generated_cases.c.h" stack_pointer[-1] = result; DISPATCH(); } @@ -4767,7 +4765,7 @@ TARGET(FORMAT_SIMPLE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3472 "Python/bytecodes.c" + #line 3470 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -4778,7 +4776,7 @@ else { res = value; } - #line 4782 "Python/generated_cases.c.h" + #line 4780 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -4787,12 +4785,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3485 "Python/bytecodes.c" + #line 3483 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 4796 "Python/generated_cases.c.h" + #line 4794 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -4801,10 +4799,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3492 "Python/bytecodes.c" + #line 3490 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4808 "Python/generated_cases.c.h" + #line 4806 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4816,7 +4814,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3497 "Python/bytecodes.c" + #line 3495 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4831,12 +4829,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4835 "Python/generated_cases.c.h" + #line 4833 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3512 "Python/bytecodes.c" + #line 3510 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4840 "Python/generated_cases.c.h" + #line 4838 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4846,16 +4844,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3517 "Python/bytecodes.c" + #line 3515 "Python/bytecodes.c" assert(oparg >= 2); - #line 4852 "Python/generated_cases.c.h" + #line 4850 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3521 "Python/bytecodes.c" + #line 3519 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4867,26 +4865,26 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4871 "Python/generated_cases.c.h" + #line 4869 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3535 "Python/bytecodes.c" + #line 3533 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4877 "Python/generated_cases.c.h" + #line 4875 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3539 "Python/bytecodes.c" + #line 3537 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 4884 "Python/generated_cases.c.h" + #line 4882 "Python/generated_cases.c.h" CHECK_EVAL_BREAKER(); DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3544 "Python/bytecodes.c" + #line 3542 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4895,12 +4893,12 @@ assert(err == 0 || err == 1); int offset = err*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4899 "Python/generated_cases.c.h" + #line 4897 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3555 "Python/bytecodes.c" + #line 3553 "Python/bytecodes.c" PyObject *cond = POP(); int err = PyObject_IsTrue(cond); Py_DECREF(cond); @@ -4909,12 +4907,12 @@ assert(err == 0 || err == 1); int offset = (1-err)*oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4913 "Python/generated_cases.c.h" + #line 4911 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3566 "Python/bytecodes.c" + #line 3564 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4926,12 +4924,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4930 "Python/generated_cases.c.h" + #line 4928 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3580 "Python/bytecodes.c" + #line 3578 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -4943,30 +4941,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4947 "Python/generated_cases.c.h" + #line 4945 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3594 "Python/bytecodes.c" + #line 3592 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 4958 "Python/generated_cases.c.h" + #line 4956 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3602 "Python/bytecodes.c" + #line 3600 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 4965 "Python/generated_cases.c.h" + #line 4963 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3607 "Python/bytecodes.c" + #line 3605 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 4972 "Python/generated_cases.c.h" + #line 4970 "Python/generated_cases.c.h" } diff --git a/Python/specialize.c b/Python/specialize.c index 0006aa733bd6cb..1a118a9a46c562 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -190,6 +190,7 @@ print_object_stats(FILE *out, ObjectStats *stats) fprintf(out, "Object materialize dict (new key): %" PRIu64 "\n", stats->dict_materialized_new_key); fprintf(out, "Object materialize dict (too big): %" PRIu64 "\n", stats->dict_materialized_too_big); fprintf(out, "Object materialize dict (str subclass): %" PRIu64 "\n", stats->dict_materialized_str_subclass); + fprintf(out, "Object un-materialize dict: %" PRIu64 "\n", stats->dict_unmaterialized); fprintf(out, "Object method cache hits: %" PRIu64 "\n", stats->type_cache_hits); fprintf(out, "Object method cache misses: %" PRIu64 "\n", stats->type_cache_misses); fprintf(out, "Object method cache collisions: %" PRIu64 "\n", stats->type_cache_collisions); From c5f2067bd622c490288b21e2f8bb1dfae2c384c2 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 29 Jun 2023 12:53:31 -0700 Subject: [PATCH 03/13] Add comment --- Lib/test/test_opcache.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py index 187fc3eea58149..7d95abb5a65fd5 100644 --- a/Lib/test/test_opcache.py +++ b/Lib/test/test_opcache.py @@ -866,6 +866,7 @@ class C: for _ in range(self.ITEMS): o = C() o.a = None + # Need to keep a __dict__ reference so it isn't un-materialized: item = o, o.__dict__ items.append(item) return items From c3d076bbd69154e8a2fcc55a05c65711da830638 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 7 Jul 2023 12:46:27 -0700 Subject: [PATCH 04/13] Catch up with main --- Lib/asyncio/selector_events.py | 1 + Lib/multiprocessing/spawn.py | 6 +- Lib/test/_test_multiprocessing.py | 82 ++- Lib/test/test_capi/test_misc.py | 136 ++++- Lib/test/test_class.py | 15 + Misc/ACKS | 1 + ...3-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst | 3 + ...-07-07-03-05-58.gh-issue-106503.ltfeiH.rst | 2 + Python/bytecodes.c | 7 +- Python/ceval.c | 5 - Python/executor_cases.c.h | 576 +++++++++++++----- Python/generated_cases.c.h | 157 ++--- Python/opcode_metadata.h | 17 + Python/optimizer.c | 83 +-- Tools/cases_generator/generate_cases.py | 87 ++- Tools/clinic/clinic.py | 143 ++--- 16 files changed, 940 insertions(+), 381 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst create mode 100644 Misc/NEWS.d/next/Library/2023-07-07-03-05-58.gh-issue-106503.ltfeiH.rst diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py index fa2422b7fba4a7..f895750e3cf959 100644 --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -1202,6 +1202,7 @@ def _reset_empty_waiter(self): def close(self): self._read_ready_cb = None + self._write_ready = None super().close() diff --git a/Lib/multiprocessing/spawn.py b/Lib/multiprocessing/spawn.py index 09f8a229d7cccb..f1af7709104714 100644 --- a/Lib/multiprocessing/spawn.py +++ b/Lib/multiprocessing/spawn.py @@ -31,11 +31,13 @@ WINSERVICE = False else: WINEXE = getattr(sys, 'frozen', False) - WINSERVICE = sys.executable.lower().endswith("pythonservice.exe") + WINSERVICE = sys.executable and sys.executable.lower().endswith("pythonservice.exe") def set_executable(exe): global _python_exe - if sys.platform == 'win32': + if exe is None: + _python_exe = exe + elif sys.platform == 'win32': _python_exe = os.fsdecode(exe) else: _python_exe = os.fsencode(exe) diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index c101fe980ceed5..c1f9487ae80511 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -13,6 +13,7 @@ import os import gc import errno +import functools import signal import array import socket @@ -31,6 +32,7 @@ from test.support import hashlib_helper from test.support import import_helper from test.support import os_helper +from test.support import script_helper from test.support import socket_helper from test.support import threading_helper from test.support import warnings_helper @@ -171,6 +173,59 @@ def check_enough_semaphores(): "to run the test (required: %d)." % nsems_min) +def only_run_in_spawn_testsuite(reason): + """Returns a decorator: raises SkipTest when SM != spawn at test time. + + This can be useful to save overall Python test suite execution time. + "spawn" is the universal mode available on all platforms so this limits the + decorated test to only execute within test_multiprocessing_spawn. + + This would not be necessary if we refactored our test suite to split things + into other test files when they are not start method specific to be rerun + under all start methods. + """ + + def decorator(test_item): + + @functools.wraps(test_item) + def spawn_check_wrapper(*args, **kwargs): + if (start_method := multiprocessing.get_start_method()) != "spawn": + raise unittest.SkipTest(f"{start_method=}, not 'spawn'; {reason}") + return test_item(*args, **kwargs) + + return spawn_check_wrapper + + return decorator + + +class TestInternalDecorators(unittest.TestCase): + """Logic within a test suite that could errantly skip tests? Test it!""" + + @unittest.skipIf(sys.platform == "win32", "test requires that fork exists.") + def test_only_run_in_spawn_testsuite(self): + if multiprocessing.get_start_method() != "spawn": + raise unittest.SkipTest("only run in test_multiprocessing_spawn.") + + try: + @only_run_in_spawn_testsuite("testing this decorator") + def return_four_if_spawn(): + return 4 + except Exception as err: + self.fail(f"expected decorated `def` not to raise; caught {err}") + + orig_start_method = multiprocessing.get_start_method(allow_none=True) + try: + multiprocessing.set_start_method("spawn", force=True) + self.assertEqual(return_four_if_spawn(), 4) + multiprocessing.set_start_method("fork", force=True) + with self.assertRaises(unittest.SkipTest) as ctx: + return_four_if_spawn() + self.assertIn("testing this decorator", str(ctx.exception)) + self.assertIn("start_method=", str(ctx.exception)) + finally: + multiprocessing.set_start_method(orig_start_method, force=True) + + # # Creates a wrapper for a function which records the time it takes to finish # @@ -5815,6 +5870,7 @@ def test_namespace(self): class TestNamedResource(unittest.TestCase): + @only_run_in_spawn_testsuite("spawn specific test.") def test_global_named_resource_spawn(self): # # gh-90549: Check that global named resources in main module @@ -5825,22 +5881,18 @@ def test_global_named_resource_spawn(self): with open(testfn, 'w', encoding='utf-8') as f: f.write(textwrap.dedent('''\ import multiprocessing as mp - ctx = mp.get_context('spawn') - global_resource = ctx.Semaphore() - def submain(): pass - if __name__ == '__main__': p = ctx.Process(target=submain) p.start() p.join() ''')) - rc, out, err = test.support.script_helper.assert_python_ok(testfn) + rc, out, err = script_helper.assert_python_ok(testfn) # on error, err = 'UserWarning: resource_tracker: There appear to # be 1 leaked semaphore objects to clean up at shutdown' - self.assertEqual(err, b'') + self.assertFalse(err, msg=err.decode('utf-8')) class MiscTestCase(unittest.TestCase): @@ -5849,6 +5901,24 @@ def test__all__(self): support.check__all__(self, multiprocessing, extra=multiprocessing.__all__, not_exported=['SUBDEBUG', 'SUBWARNING']) + @only_run_in_spawn_testsuite("avoids redundant testing.") + def test_spawn_sys_executable_none_allows_import(self): + # Regression test for a bug introduced in + # https://github.com/python/cpython/issues/90876 that caused an + # ImportError in multiprocessing when sys.executable was None. + # This can be true in embedded environments. + rc, out, err = script_helper.assert_python_ok( + "-c", + """if 1: + import sys + sys.executable = None + assert "multiprocessing" not in sys.modules, "already imported!" + import multiprocessing + import multiprocessing.spawn # This should not fail\n""", + ) + self.assertEqual(rc, 0) + self.assertFalse(err, msg=err.decode('utf-8')) + # # Mixins diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index de9f00a9e5fb48..5f39f23401c3f2 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -7,6 +7,7 @@ import importlib.machinery import importlib.util import json +import opcode import os import pickle import queue @@ -2343,23 +2344,27 @@ def func(): names = ["func", "outer", "outer", "inner", "inner", "outer", "inner"] self.do_test(func, names) -class TestOptimizerAPI(unittest.TestCase): - @contextlib.contextmanager - def temporary_optimizer(self, opt): - _testinternalcapi.set_optimizer(opt) - try: - yield - finally: - _testinternalcapi.set_optimizer(None) +@contextlib.contextmanager +def temporary_optimizer(opt): + _testinternalcapi.set_optimizer(opt) + try: + yield + finally: + _testinternalcapi.set_optimizer(None) - @contextlib.contextmanager - def clear_executors(self, func): - try: - yield - finally: - #Clear executors - func.__code__ = func.__code__.replace() + +@contextlib.contextmanager +def clear_executors(func): + # Clear executors in func before and after running a block + func.__code__ = func.__code__.replace() + try: + yield + finally: + func.__code__ = func.__code__.replace() + + +class TestOptimizerAPI(unittest.TestCase): def test_get_set_optimizer(self): self.assertEqual(_testinternalcapi.get_optimizer(), None) @@ -2381,9 +2386,9 @@ def loop(): for repeat in range(5): opt = _testinternalcapi.get_counter_optimizer() - with self.temporary_optimizer(opt): + with temporary_optimizer(opt): self.assertEqual(opt.get_count(), 0) - with self.clear_executors(loop): + with clear_executors(loop): loop() self.assertEqual(opt.get_count(), 1000) @@ -2409,33 +2414,118 @@ def long_loop(): long_loop = ns['long_loop'] opt = _testinternalcapi.get_counter_optimizer() - with self.temporary_optimizer(opt): + with temporary_optimizer(opt): self.assertEqual(opt.get_count(), 0) long_loop() self.assertEqual(opt.get_count(), 10) + +def get_first_executor(code): + co_code = code.co_code + JUMP_BACKWARD = opcode.opmap["JUMP_BACKWARD"] + for i in range(0, len(co_code), 2): + if co_code[i] == JUMP_BACKWARD or 1: + try: + return _testinternalcapi.get_executor(code, i) + except ValueError: + pass + return None + + class TestUops(unittest.TestCase): def test_basic_loop(self): + def testfunc(x): + i = 0 + while i < x: + i += 1 + opt = _testinternalcapi.get_uop_optimizer() + + with temporary_optimizer(opt): + testfunc(1000) + + ex = None + for offset in range(0, len(testfunc.__code__.co_code), 2): + try: + ex = _testinternalcapi.get_executor(testfunc.__code__, offset) + break + except ValueError: + pass + self.assertIsNotNone(ex) + uops = {opname for opname, _ in ex} + self.assertIn("SAVE_IP", uops) + self.assertIn("LOAD_FAST", uops) + + def test_extended_arg(self): + "Check EXTENDED_ARG handling in superblock creation" + def many_vars(): + # 260 vars, so z9 should have index 259 + a0 = a1 = a2 = a3 = a4 = a5 = a6 = a7 = a8 = a9 = 42 + b0 = b1 = b2 = b3 = b4 = b5 = b6 = b7 = b8 = b9 = 42 + c0 = c1 = c2 = c3 = c4 = c5 = c6 = c7 = c8 = c9 = 42 + d0 = d1 = d2 = d3 = d4 = d5 = d6 = d7 = d8 = d9 = 42 + e0 = e1 = e2 = e3 = e4 = e5 = e6 = e7 = e8 = e9 = 42 + f0 = f1 = f2 = f3 = f4 = f5 = f6 = f7 = f8 = f9 = 42 + g0 = g1 = g2 = g3 = g4 = g5 = g6 = g7 = g8 = g9 = 42 + h0 = h1 = h2 = h3 = h4 = h5 = h6 = h7 = h8 = h9 = 42 + i0 = i1 = i2 = i3 = i4 = i5 = i6 = i7 = i8 = i9 = 42 + j0 = j1 = j2 = j3 = j4 = j5 = j6 = j7 = j8 = j9 = 42 + k0 = k1 = k2 = k3 = k4 = k5 = k6 = k7 = k8 = k9 = 42 + l0 = l1 = l2 = l3 = l4 = l5 = l6 = l7 = l8 = l9 = 42 + m0 = m1 = m2 = m3 = m4 = m5 = m6 = m7 = m8 = m9 = 42 + n0 = n1 = n2 = n3 = n4 = n5 = n6 = n7 = n8 = n9 = 42 + o0 = o1 = o2 = o3 = o4 = o5 = o6 = o7 = o8 = o9 = 42 + p0 = p1 = p2 = p3 = p4 = p5 = p6 = p7 = p8 = p9 = 42 + q0 = q1 = q2 = q3 = q4 = q5 = q6 = q7 = q8 = q9 = 42 + r0 = r1 = r2 = r3 = r4 = r5 = r6 = r7 = r8 = r9 = 42 + s0 = s1 = s2 = s3 = s4 = s5 = s6 = s7 = s8 = s9 = 42 + t0 = t1 = t2 = t3 = t4 = t5 = t6 = t7 = t8 = t9 = 42 + u0 = u1 = u2 = u3 = u4 = u5 = u6 = u7 = u8 = u9 = 42 + v0 = v1 = v2 = v3 = v4 = v5 = v6 = v7 = v8 = v9 = 42 + w0 = w1 = w2 = w3 = w4 = w5 = w6 = w7 = w8 = w9 = 42 + x0 = x1 = x2 = x3 = x4 = x5 = x6 = x7 = x8 = x9 = 42 + y0 = y1 = y2 = y3 = y4 = y5 = y6 = y7 = y8 = y9 = 42 + z0 = z1 = z2 = z3 = z4 = z5 = z6 = z7 = z8 = z9 = 42 + while z9 > 0: + z9 = z9 - 1 + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + ex = get_first_executor(many_vars.__code__) + self.assertIsNone(ex) + many_vars() + ex = get_first_executor(many_vars.__code__) + self.assertIn(("LOAD_FAST", 259), list(ex)) + + def test_unspecialized_unpack(self): + # An example of an unspecialized opcode def testfunc(x): i = 0 while i < x: i += 1 + a, b = {1: 2, 3: 3} + assert a == 1 and b == 3 + i = 0 + while i < x: + i += 1 + + opt = _testinternalcapi.get_uop_optimizer() - testfunc(1000) + with temporary_optimizer(opt): + testfunc(10) ex = None - for offset in range(0, 100, 2): + for offset in range(0, len(testfunc.__code__.co_code), 2): try: ex = _testinternalcapi.get_executor(testfunc.__code__, offset) break except ValueError: pass - if ex is None: - return - self.assertIn("SAVE_IP", str(ex)) + self.assertIsNotNone(ex) + uops = {opname for opname, _ in ex} + self.assertIn("UNPACK_SEQUENCE", uops) if __name__ == "__main__": diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index d7a48e55b10180..894e0ca67deabc 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -740,6 +740,21 @@ class A(0, 1, 2, 3, 4, 5, 6, 7, **d): pass class A(0, *range(1, 8), **d, foo='bar'): pass self.assertEqual(A, (tuple(range(8)), {'foo': 'bar'})) + def testClassCallRecursionLimit(self): + class C: + def __init__(self): + self.c = C() + + with self.assertRaises(RecursionError): + C() + + def add_one_level(): + #Each call to C() consumes 2 levels, so offset by 1. + C() + + with self.assertRaises(RecursionError): + add_one_level() + if __name__ == '__main__': unittest.main() diff --git a/Misc/ACKS b/Misc/ACKS index 454b63155f013c..ef0029a7e4119d 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -615,6 +615,7 @@ Marius Gedminas Jan-Philip Gehrcke Thomas Gellekum Gabriel Genellina +Andrew Geng Philip Georgi Christos Georgiou Elazar (אלעזר) Gershuni diff --git a/Misc/NEWS.d/next/Library/2023-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst b/Misc/NEWS.d/next/Library/2023-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst new file mode 100644 index 00000000000000..3e062b5add6d89 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-05-13-08-23.gh-issue-90876.Qvlkfl.rst @@ -0,0 +1,3 @@ +Prevent :mod:`multiprocessing.spawn` from failing to *import* in environments +where ``sys.executable`` is ``None``. This regressed in 3.11 with the addition +of support for path-like objects in multiprocessing. diff --git a/Misc/NEWS.d/next/Library/2023-07-07-03-05-58.gh-issue-106503.ltfeiH.rst b/Misc/NEWS.d/next/Library/2023-07-07-03-05-58.gh-issue-106503.ltfeiH.rst new file mode 100644 index 00000000000000..b8dd850386e86c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-07-07-03-05-58.gh-issue-106503.ltfeiH.rst @@ -0,0 +1,2 @@ +Fix ref cycle in :class:`!asyncio._SelectorSocketTransport` by removing +``_write_ready`` in ``close``. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index e4364615ab9b30..3aa4422835f0b5 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3005,9 +3005,6 @@ dummy_func( goto error; } Py_DECREF(tp); - if (_Py_EnterRecursivePy(tstate)) { - goto exit_unwind; - } _PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked( tstate, (PyCodeObject *)&_Py_InitCleanup, 1, 0); assert(_PyCode_CODE((PyCodeObject *)shim->f_executable)[1].op.code == EXIT_INIT_CHECK); @@ -3031,6 +3028,10 @@ dummy_func( shim->previous = frame; frame = cframe.current_frame = init_frame; CALL_STAT_INC(inlined_py_calls); + /* Account for pushing the extra frame. + * We don't check recursion depth here, + * as it will be checked after start_frame */ + tstate->py_recursion_remaining--; goto start_frame; } diff --git a/Python/ceval.c b/Python/ceval.c index 0ee95bc3a3a4bb..1b8650a650412d 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -763,11 +763,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); - if (_Py_HandlePending(tstate) != 0) { - goto error; - } - DISPATCH(); - { /* Start instructions */ #if !USE_COMPUTED_GOTOS diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index c081a6db7853ee..cac1c660f5212c 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -118,12 +118,38 @@ break; } + case TO_BOOL: { + static_assert(INLINE_CACHE_ENTRIES_TO_BOOL == 3, "incorrect cache size"); + PyObject *value = stack_pointer[-1]; + PyObject *res; + #line 296 "Python/bytecodes.c" + #if ENABLE_SPECIALIZATION + _PyToBoolCache *cache = (_PyToBoolCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + next_instr--; + _Py_Specialize_ToBool(value, next_instr); + DISPATCH_SAME_OPARG(); + } + STAT_INC(TO_BOOL, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ + int err = PyObject_IsTrue(value); + #line 138 "Python/executor_cases.c.h" + Py_DECREF(value); + #line 308 "Python/bytecodes.c" + if (err < 0) goto pop_1_error; + res = err ? Py_True : Py_False; + #line 143 "Python/executor_cases.c.h" + stack_pointer[-1] = res; + break; + } + case TO_BOOL_BOOL: { PyObject *value = stack_pointer[-1]; #line 313 "Python/bytecodes.c" DEOPT_IF(!PyBool_Check(value), TO_BOOL); STAT_INC(TO_BOOL, hit); - #line 127 "Python/executor_cases.c.h" + #line 153 "Python/executor_cases.c.h" break; } @@ -138,12 +164,12 @@ res = Py_False; } else { - #line 142 "Python/executor_cases.c.h" + #line 168 "Python/executor_cases.c.h" Py_DECREF(value); #line 326 "Python/bytecodes.c" res = Py_True; } - #line 147 "Python/executor_cases.c.h" + #line 173 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -155,7 +181,7 @@ DEOPT_IF(!PyList_CheckExact(value), TO_BOOL); STAT_INC(TO_BOOL, hit); res = Py_SIZE(value) ? Py_True : Py_False; - #line 159 "Python/executor_cases.c.h" + #line 185 "Python/executor_cases.c.h" Py_DECREF(value); stack_pointer[-1] = res; break; @@ -169,7 +195,7 @@ DEOPT_IF(!Py_IsNone(value), TO_BOOL); STAT_INC(TO_BOOL, hit); res = Py_False; - #line 173 "Python/executor_cases.c.h" + #line 199 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -186,12 +212,12 @@ } else { assert(Py_SIZE(value)); - #line 190 "Python/executor_cases.c.h" + #line 216 "Python/executor_cases.c.h" Py_DECREF(value); #line 354 "Python/bytecodes.c" res = Py_True; } - #line 195 "Python/executor_cases.c.h" + #line 221 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -205,11 +231,11 @@ assert(version); DEOPT_IF(Py_TYPE(value)->tp_version_tag != version, TO_BOOL); STAT_INC(TO_BOOL, hit); - #line 209 "Python/executor_cases.c.h" + #line 235 "Python/executor_cases.c.h" Py_DECREF(value); #line 364 "Python/bytecodes.c" res = Py_True; - #line 213 "Python/executor_cases.c.h" + #line 239 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -219,11 +245,11 @@ PyObject *res; #line 368 "Python/bytecodes.c" res = PyNumber_Invert(value); - #line 223 "Python/executor_cases.c.h" + #line 249 "Python/executor_cases.c.h" Py_DECREF(value); #line 370 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 227 "Python/executor_cases.c.h" + #line 253 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -234,7 +260,7 @@ #line 386 "Python/bytecodes.c" DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP); DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP); - #line 238 "Python/executor_cases.c.h" + #line 264 "Python/executor_cases.c.h" break; } @@ -248,7 +274,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 252 "Python/executor_cases.c.h" + #line 278 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -264,7 +290,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 268 "Python/executor_cases.c.h" + #line 294 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -280,7 +306,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free); if (res == NULL) goto pop_2_error; - #line 284 "Python/executor_cases.c.h" + #line 310 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -292,7 +318,7 @@ #line 422 "Python/bytecodes.c" DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP); DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP); - #line 296 "Python/executor_cases.c.h" + #line 322 "Python/executor_cases.c.h" break; } @@ -306,7 +332,7 @@ ((PyFloatObject *)left)->ob_fval * ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 310 "Python/executor_cases.c.h" + #line 336 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -322,7 +348,7 @@ ((PyFloatObject *)left)->ob_fval + ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 326 "Python/executor_cases.c.h" + #line 352 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -338,7 +364,7 @@ ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval; DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dres, res); - #line 342 "Python/executor_cases.c.h" + #line 368 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -350,7 +376,7 @@ #line 458 "Python/bytecodes.c" DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP); DEOPT_IF(!PyUnicode_CheckExact(right), BINARY_OP); - #line 354 "Python/executor_cases.c.h" + #line 380 "Python/executor_cases.c.h" break; } @@ -364,7 +390,35 @@ _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc); _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc); if (res == NULL) goto pop_2_error; - #line 368 "Python/executor_cases.c.h" + #line 394 "Python/executor_cases.c.h" + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + + case BINARY_SUBSCR: { + static_assert(INLINE_CACHE_ENTRIES_BINARY_SUBSCR == 1, "incorrect cache size"); + PyObject *sub = stack_pointer[-1]; + PyObject *container = stack_pointer[-2]; + PyObject *res; + #line 517 "Python/bytecodes.c" + #if ENABLE_SPECIALIZATION + _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + 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); + #line 417 "Python/executor_cases.c.h" + Py_DECREF(container); + Py_DECREF(sub); + #line 529 "Python/bytecodes.c" + if (res == NULL) goto pop_2_error; + #line 422 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -388,7 +442,7 @@ } Py_DECREF(container); if (res == NULL) goto pop_3_error; - #line 392 "Python/executor_cases.c.h" + #line 446 "Python/executor_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = res; break; @@ -412,7 +466,7 @@ Py_DECREF(v); Py_DECREF(container); if (err) goto pop_4_error; - #line 416 "Python/executor_cases.c.h" + #line 470 "Python/executor_cases.c.h" STACK_SHRINK(4); break; } @@ -435,7 +489,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 439 "Python/executor_cases.c.h" + #line 493 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -459,7 +513,7 @@ Py_INCREF(res); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(tuple); - #line 463 "Python/executor_cases.c.h" + #line 517 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -477,14 +531,14 @@ if (!_PyErr_Occurred(tstate)) { _PyErr_SetKeyError(sub); } - #line 481 "Python/executor_cases.c.h" + #line 535 "Python/executor_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); #line 603 "Python/bytecodes.c" if (true) goto pop_2_error; } Py_INCREF(res); // Do this before DECREF'ing dict, sub - #line 488 "Python/executor_cases.c.h" + #line 542 "Python/executor_cases.c.h" Py_DECREF(dict); Py_DECREF(sub); STACK_SHRINK(1); @@ -497,7 +551,7 @@ PyObject *list = stack_pointer[-(2 + (oparg-1))]; #line 635 "Python/bytecodes.c" if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error; - #line 501 "Python/executor_cases.c.h" + #line 555 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -507,15 +561,47 @@ PyObject *set = stack_pointer[-(2 + (oparg-1))]; #line 639 "Python/bytecodes.c" int err = PySet_Add(set, v); - #line 511 "Python/executor_cases.c.h" + #line 565 "Python/executor_cases.c.h" Py_DECREF(v); #line 641 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 515 "Python/executor_cases.c.h" + #line 569 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } + case STORE_SUBSCR: { + static_assert(INLINE_CACHE_ENTRIES_STORE_SUBSCR == 1, "incorrect cache size"); + PyObject *sub = stack_pointer[-1]; + PyObject *container = stack_pointer[-2]; + PyObject *v = stack_pointer[-3]; + uint16_t counter = (uint16_t)operand; + #line 651 "Python/bytecodes.c" + #if ENABLE_SPECIALIZATION + if (ADAPTIVE_COUNTER_IS_ZERO(counter)) { + 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); + #line 595 "Python/executor_cases.c.h" + Py_DECREF(v); + Py_DECREF(container); + Py_DECREF(sub); + #line 666 "Python/bytecodes.c" + if (err) goto pop_3_error; + #line 601 "Python/executor_cases.c.h" + STACK_SHRINK(3); + break; + } + case STORE_SUBSCR_LIST_INT: { PyObject *sub = stack_pointer[-1]; PyObject *list = stack_pointer[-2]; @@ -537,7 +623,7 @@ Py_DECREF(old_value); _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free); Py_DECREF(list); - #line 541 "Python/executor_cases.c.h" + #line 627 "Python/executor_cases.c.h" STACK_SHRINK(3); break; } @@ -552,7 +638,7 @@ int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value); Py_DECREF(dict); if (err) goto pop_3_error; - #line 556 "Python/executor_cases.c.h" + #line 642 "Python/executor_cases.c.h" STACK_SHRINK(3); break; } @@ -563,12 +649,12 @@ #line 697 "Python/bytecodes.c" /* del container[sub] */ int err = PyObject_DelItem(container, sub); - #line 567 "Python/executor_cases.c.h" + #line 653 "Python/executor_cases.c.h" Py_DECREF(container); Py_DECREF(sub); #line 700 "Python/bytecodes.c" if (err) goto pop_2_error; - #line 572 "Python/executor_cases.c.h" + #line 658 "Python/executor_cases.c.h" STACK_SHRINK(2); break; } @@ -579,11 +665,11 @@ #line 704 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_1); res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value); - #line 583 "Python/executor_cases.c.h" + #line 669 "Python/executor_cases.c.h" Py_DECREF(value); #line 707 "Python/bytecodes.c" if (res == NULL) goto pop_1_error; - #line 587 "Python/executor_cases.c.h" + #line 673 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -595,12 +681,12 @@ #line 711 "Python/bytecodes.c" assert(oparg <= MAX_INTRINSIC_2); res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1); - #line 599 "Python/executor_cases.c.h" + #line 685 "Python/executor_cases.c.h" Py_DECREF(value2); Py_DECREF(value1); #line 714 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 604 "Python/executor_cases.c.h" + #line 690 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -622,14 +708,14 @@ "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); - #line 626 "Python/executor_cases.c.h" + #line 712 "Python/executor_cases.c.h" Py_DECREF(obj); #line 832 "Python/bytecodes.c" if (true) goto pop_1_error; } iter = (*getter)(obj); - #line 633 "Python/executor_cases.c.h" + #line 719 "Python/executor_cases.c.h" Py_DECREF(obj); #line 837 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; @@ -644,7 +730,7 @@ Py_DECREF(iter); if (true) goto pop_1_error; } - #line 648 "Python/executor_cases.c.h" + #line 734 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -695,7 +781,7 @@ Py_DECREF(next_iter); } } - #line 699 "Python/executor_cases.c.h" + #line 785 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = awaitable; break; @@ -711,7 +797,7 @@ format_awaitable_error(tstate, Py_TYPE(iterable), oparg); } - #line 715 "Python/executor_cases.c.h" + #line 801 "Python/executor_cases.c.h" Py_DECREF(iterable); #line 904 "Python/bytecodes.c" @@ -730,7 +816,7 @@ } if (iter == NULL) goto pop_1_error; - #line 734 "Python/executor_cases.c.h" + #line 820 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -740,7 +826,7 @@ #line 1034 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; Py_XSETREF(exc_info->exc_value, exc_value); - #line 744 "Python/executor_cases.c.h" + #line 830 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -749,7 +835,7 @@ PyObject *value; #line 1085 "Python/bytecodes.c" value = Py_NewRef(PyExc_AssertionError); - #line 753 "Python/executor_cases.c.h" + #line 839 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -779,7 +865,7 @@ if (true) goto error; } } - #line 783 "Python/executor_cases.c.h" + #line 869 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = bc; break; @@ -794,7 +880,7 @@ if (ns == NULL) { _PyErr_Format(tstate, PyExc_SystemError, "no locals found when storing %R", name); - #line 798 "Python/executor_cases.c.h" + #line 884 "Python/executor_cases.c.h" Py_DECREF(v); #line 1121 "Python/bytecodes.c" if (true) goto pop_1_error; @@ -803,11 +889,11 @@ err = PyDict_SetItem(ns, name, v); else err = PyObject_SetItem(ns, name, v); - #line 807 "Python/executor_cases.c.h" + #line 893 "Python/executor_cases.c.h" Py_DECREF(v); #line 1128 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 811 "Python/executor_cases.c.h" + #line 897 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -830,7 +916,33 @@ name); goto error; } - #line 834 "Python/executor_cases.c.h" + #line 920 "Python/executor_cases.c.h" + break; + } + + case UNPACK_SEQUENCE: { + static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size"); + PyObject *seq = stack_pointer[-1]; + #line 1158 "Python/bytecodes.c" + #if ENABLE_SPECIALIZATION + _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + 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 **top = stack_pointer + oparg - 1; + int res = unpack_iterable(tstate, seq, oparg, -1, top); + #line 940 "Python/executor_cases.c.h" + Py_DECREF(seq); + #line 1171 "Python/bytecodes.c" + if (res == 0) goto pop_1_error; + #line 944 "Python/executor_cases.c.h" + STACK_SHRINK(1); + STACK_GROW(oparg); break; } @@ -844,7 +956,7 @@ STAT_INC(UNPACK_SEQUENCE, hit); values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); - #line 848 "Python/executor_cases.c.h" + #line 960 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -862,7 +974,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 866 "Python/executor_cases.c.h" + #line 978 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -880,7 +992,7 @@ for (int i = oparg; --i >= 0; ) { *values++ = Py_NewRef(items[i]); } - #line 884 "Python/executor_cases.c.h" + #line 996 "Python/executor_cases.c.h" Py_DECREF(seq); STACK_SHRINK(1); STACK_GROW(oparg); @@ -893,11 +1005,11 @@ int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject **top = stack_pointer + totalargs - 1; int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); - #line 897 "Python/executor_cases.c.h" + #line 1009 "Python/executor_cases.c.h" Py_DECREF(seq); #line 1211 "Python/bytecodes.c" if (res == 0) goto pop_1_error; - #line 901 "Python/executor_cases.c.h" + #line 1013 "Python/executor_cases.c.h" STACK_GROW((oparg & 0xFF) + (oparg >> 8)); break; } @@ -907,11 +1019,11 @@ #line 1242 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyObject_SetAttr(owner, name, (PyObject *)NULL); - #line 911 "Python/executor_cases.c.h" + #line 1023 "Python/executor_cases.c.h" Py_DECREF(owner); #line 1245 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 915 "Python/executor_cases.c.h" + #line 1027 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -921,11 +1033,11 @@ #line 1249 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); int err = PyDict_SetItem(GLOBALS(), name, v); - #line 925 "Python/executor_cases.c.h" + #line 1037 "Python/executor_cases.c.h" Py_DECREF(v); #line 1252 "Python/bytecodes.c" if (err) goto pop_1_error; - #line 929 "Python/executor_cases.c.h" + #line 1041 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -943,7 +1055,7 @@ } goto error; } - #line 947 "Python/executor_cases.c.h" + #line 1059 "Python/executor_cases.c.h" break; } @@ -957,7 +1069,7 @@ if (true) goto error; } Py_INCREF(locals); - #line 961 "Python/executor_cases.c.h" + #line 1073 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = locals; break; @@ -1023,17 +1135,81 @@ } } } - #line 1027 "Python/executor_cases.c.h" + #line 1139 "Python/executor_cases.c.h" stack_pointer[-1] = v; break; } + case LOAD_GLOBAL: { + static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size"); + PyObject *null = NULL; + PyObject *v; + #line 1351 "Python/bytecodes.c" + #if ENABLE_SPECIALIZATION + _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + PyObject *name = GETITEM(FRAME_CO_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 */ + PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); + 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); + } + if (true) 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); + } + if (true) goto error; + } + } + } + null = NULL; + #line 1200 "Python/executor_cases.c.h" + STACK_GROW(1); + STACK_GROW(((oparg & 1) ? 1 : 0)); + stack_pointer[-1] = v; + if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = null; } + break; + } + case DELETE_FAST: { #line 1435 "Python/bytecodes.c" PyObject *v = GETLOCAL(oparg); if (v == NULL) goto unbound_local_error; SETLOCAL(oparg, NULL); - #line 1037 "Python/executor_cases.c.h" + #line 1213 "Python/executor_cases.c.h" break; } @@ -1049,7 +1225,7 @@ } PyCell_SET(cell, NULL); Py_DECREF(oldobj); - #line 1053 "Python/executor_cases.c.h" + #line 1229 "Python/executor_cases.c.h" break; } @@ -1091,7 +1267,7 @@ } Py_INCREF(value); } - #line 1095 "Python/executor_cases.c.h" + #line 1271 "Python/executor_cases.c.h" stack_pointer[-1] = value; break; } @@ -1106,7 +1282,7 @@ if (true) goto error; } Py_INCREF(value); - #line 1110 "Python/executor_cases.c.h" + #line 1286 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = value; break; @@ -1119,7 +1295,7 @@ PyObject *oldobj = PyCell_GET(cell); PyCell_SET(cell, v); Py_XDECREF(oldobj); - #line 1123 "Python/executor_cases.c.h" + #line 1299 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -1136,7 +1312,7 @@ PyObject *o = PyTuple_GET_ITEM(closure, i); frame->localsplus[offset + i] = Py_NewRef(o); } - #line 1140 "Python/executor_cases.c.h" + #line 1316 "Python/executor_cases.c.h" break; } @@ -1145,13 +1321,13 @@ PyObject *str; #line 1532 "Python/bytecodes.c" str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg); - #line 1149 "Python/executor_cases.c.h" + #line 1325 "Python/executor_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(pieces[_i]); } #line 1534 "Python/bytecodes.c" if (str == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1155 "Python/executor_cases.c.h" + #line 1331 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = str; @@ -1164,7 +1340,7 @@ #line 1538 "Python/bytecodes.c" tup = _PyTuple_FromArraySteal(values, oparg); if (tup == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1168 "Python/executor_cases.c.h" + #line 1344 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = tup; @@ -1177,7 +1353,7 @@ #line 1543 "Python/bytecodes.c" list = _PyList_FromArraySteal(values, oparg); if (list == NULL) { STACK_SHRINK(oparg); goto error; } - #line 1181 "Python/executor_cases.c.h" + #line 1357 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = list; @@ -1198,13 +1374,13 @@ "Value after * must be an iterable, not %.200s", Py_TYPE(iterable)->tp_name); } - #line 1202 "Python/executor_cases.c.h" + #line 1378 "Python/executor_cases.c.h" Py_DECREF(iterable); #line 1559 "Python/bytecodes.c" if (true) goto pop_1_error; } assert(Py_IsNone(none_val)); - #line 1208 "Python/executor_cases.c.h" + #line 1384 "Python/executor_cases.c.h" Py_DECREF(iterable); STACK_SHRINK(1); break; @@ -1215,11 +1391,11 @@ PyObject *set = stack_pointer[-(2 + (oparg-1))]; #line 1566 "Python/bytecodes.c" int err = _PySet_Update(set, iterable); - #line 1219 "Python/executor_cases.c.h" + #line 1395 "Python/executor_cases.c.h" Py_DECREF(iterable); #line 1568 "Python/bytecodes.c" if (err < 0) goto pop_1_error; - #line 1223 "Python/executor_cases.c.h" + #line 1399 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -1242,7 +1418,7 @@ Py_DECREF(set); if (true) { STACK_SHRINK(oparg); goto error; } } - #line 1246 "Python/executor_cases.c.h" + #line 1422 "Python/executor_cases.c.h" STACK_SHRINK(oparg); STACK_GROW(1); stack_pointer[-1] = set; @@ -1260,13 +1436,13 @@ if (map == NULL) goto error; - #line 1264 "Python/executor_cases.c.h" + #line 1440 "Python/executor_cases.c.h" for (int _i = oparg*2; --_i >= 0;) { Py_DECREF(values[_i]); } #line 1597 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg*2); goto error; } - #line 1270 "Python/executor_cases.c.h" + #line 1446 "Python/executor_cases.c.h" STACK_SHRINK(oparg*2); STACK_GROW(1); stack_pointer[-1] = map; @@ -1314,7 +1490,7 @@ Py_DECREF(ann_dict); } } - #line 1318 "Python/executor_cases.c.h" + #line 1494 "Python/executor_cases.c.h" break; } @@ -1332,14 +1508,14 @@ map = _PyDict_FromItems( &PyTuple_GET_ITEM(keys, 0), 1, values, 1, oparg); - #line 1336 "Python/executor_cases.c.h" + #line 1512 "Python/executor_cases.c.h" for (int _i = oparg; --_i >= 0;) { Py_DECREF(values[_i]); } Py_DECREF(keys); #line 1653 "Python/bytecodes.c" if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; } - #line 1343 "Python/executor_cases.c.h" + #line 1519 "Python/executor_cases.c.h" STACK_SHRINK(oparg); stack_pointer[-1] = map; break; @@ -1355,12 +1531,12 @@ "'%.200s' object is not a mapping", Py_TYPE(update)->tp_name); } - #line 1359 "Python/executor_cases.c.h" + #line 1535 "Python/executor_cases.c.h" Py_DECREF(update); #line 1665 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 1364 "Python/executor_cases.c.h" + #line 1540 "Python/executor_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); break; @@ -1373,12 +1549,12 @@ if (_PyDict_MergeEx(dict, update, 2) < 0) { format_kwargs_error(tstate, PEEK(3 + oparg), update); - #line 1377 "Python/executor_cases.c.h" + #line 1553 "Python/executor_cases.c.h" Py_DECREF(update); #line 1676 "Python/bytecodes.c" if (true) goto pop_1_error; } - #line 1382 "Python/executor_cases.c.h" + #line 1558 "Python/executor_cases.c.h" Py_DECREF(update); STACK_SHRINK(1); break; @@ -1393,7 +1569,7 @@ /* 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; - #line 1397 "Python/executor_cases.c.h" + #line 1573 "Python/executor_cases.c.h" STACK_SHRINK(2); break; } @@ -1411,13 +1587,13 @@ STAT_INC(LOAD_SUPER_ATTR, hit); PyObject *name = GETITEM(FRAME_CO_NAMES, oparg >> 2); res = _PySuper_Lookup((PyTypeObject *)class, self, name, NULL); - #line 1415 "Python/executor_cases.c.h" + #line 1591 "Python/executor_cases.c.h" Py_DECREF(global_super); Py_DECREF(class); Py_DECREF(self); #line 1772 "Python/bytecodes.c" if (res == NULL) goto pop_3_error; - #line 1421 "Python/executor_cases.c.h" + #line 1597 "Python/executor_cases.c.h" STACK_SHRINK(2); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -1454,13 +1630,110 @@ res = res2; res2 = NULL; } - #line 1458 "Python/executor_cases.c.h" + #line 1634 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; stack_pointer[-2] = res2; break; } + case LOAD_ATTR: { + static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); + PyObject *owner = stack_pointer[-1]; + PyObject *res2 = NULL; + PyObject *res; + #line 1815 "Python/bytecodes.c" + #if ENABLE_SPECIALIZATION + _PyAttrCache *cache = (_PyAttrCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + PyObject *name = GETITEM(FRAME_CO_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(FRAME_CO_NAMES, oparg >> 1); + if (oparg & 1) { + /* Designed to work in tandem with CALL, pushes two values. */ + PyObject* meth = NULL; + if (_PyObject_GetMethod(owner, name, &meth)) { + /* We can bypass temporary bound method object. + meth is unbound method and obj is self. + + meth | self | arg1 | ... | argN + */ + assert(meth != NULL); // No errors on this branch + res2 = meth; + res = owner; // Transfer ownership + } + 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 + */ + #line 1680 "Python/executor_cases.c.h" + Py_DECREF(owner); + #line 1849 "Python/bytecodes.c" + if (meth == NULL) goto pop_1_error; + res2 = NULL; + res = meth; + } + } + else { + /* Classic, pushes one value. */ + res = PyObject_GetAttr(owner, name); + #line 1691 "Python/executor_cases.c.h" + Py_DECREF(owner); + #line 1858 "Python/bytecodes.c" + if (res == NULL) goto pop_1_error; + } + #line 1696 "Python/executor_cases.c.h" + STACK_GROW(((oparg & 1) ? 1 : 0)); + stack_pointer[-1] = res; + if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } + break; + } + + case 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; + #line 2111 "Python/bytecodes.c" + #if ENABLE_SPECIALIZATION + _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + next_instr--; + _Py_Specialize_CompareOp(left, right, next_instr, oparg); + DISPATCH_SAME_OPARG(); + } + STAT_INC(COMPARE_OP, deferred); + DECREMENT_ADAPTIVE_COUNTER(cache->counter); + #endif /* ENABLE_SPECIALIZATION */ + assert((oparg >> 5) <= Py_GE); + res = PyObject_RichCompare(left, right, oparg >> 5); + #line 1721 "Python/executor_cases.c.h" + Py_DECREF(left); + Py_DECREF(right); + #line 2124 "Python/bytecodes.c" + if (res == NULL) goto pop_2_error; + if (oparg & 16) { + int res_bool = PyObject_IsTrue(res); + Py_DECREF(res); + if (res_bool < 0) goto pop_2_error; + res = res_bool ? Py_True : Py_False; + } + #line 1732 "Python/executor_cases.c.h" + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + case COMPARE_OP_FLOAT: { PyObject *right = stack_pointer[-1]; PyObject *left = stack_pointer[-2]; @@ -1477,7 +1750,7 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 1481 "Python/executor_cases.c.h" + #line 1754 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1503,7 +1776,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 1507 "Python/executor_cases.c.h" + #line 1780 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1526,7 +1799,7 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 1530 "Python/executor_cases.c.h" + #line 1803 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1538,12 +1811,12 @@ PyObject *b; #line 2183 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 1542 "Python/executor_cases.c.h" + #line 1815 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); #line 2185 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 1547 "Python/executor_cases.c.h" + #line 1820 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; break; @@ -1555,13 +1828,13 @@ PyObject *b; #line 2189 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 1559 "Python/executor_cases.c.h" + #line 1832 "Python/executor_cases.c.h" Py_DECREF(left); Py_DECREF(right); #line 2191 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 1565 "Python/executor_cases.c.h" + #line 1838 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; break; @@ -1574,7 +1847,7 @@ PyObject *match; #line 2196 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 1578 "Python/executor_cases.c.h" + #line 1851 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); #line 2198 "Python/bytecodes.c" @@ -1585,7 +1858,7 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 1589 "Python/executor_cases.c.h" + #line 1862 "Python/executor_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); #line 2206 "Python/bytecodes.c" @@ -1597,7 +1870,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 1601 "Python/executor_cases.c.h" + #line 1874 "Python/executor_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; break; @@ -1610,18 +1883,18 @@ #line 2217 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 1614 "Python/executor_cases.c.h" + #line 1887 "Python/executor_cases.c.h" Py_DECREF(right); #line 2220 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 1621 "Python/executor_cases.c.h" + #line 1894 "Python/executor_cases.c.h" Py_DECREF(right); #line 2225 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 1625 "Python/executor_cases.c.h" + #line 1898 "Python/executor_cases.c.h" stack_pointer[-1] = b; break; } @@ -1635,7 +1908,7 @@ if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 1639 "Python/executor_cases.c.h" + #line 1912 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; break; @@ -1651,7 +1924,7 @@ // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 1655 "Python/executor_cases.c.h" + #line 1928 "Python/executor_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); @@ -1663,7 +1936,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 1667 "Python/executor_cases.c.h" + #line 1940 "Python/executor_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; break; @@ -1675,7 +1948,7 @@ #line 2352 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 1679 "Python/executor_cases.c.h" + #line 1952 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1687,7 +1960,7 @@ #line 2357 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 1691 "Python/executor_cases.c.h" + #line 1964 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1701,7 +1974,7 @@ // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 1705 "Python/executor_cases.c.h" + #line 1978 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; break; @@ -1713,11 +1986,11 @@ #line 2368 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 1717 "Python/executor_cases.c.h" + #line 1990 "Python/executor_cases.c.h" Py_DECREF(iterable); #line 2371 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 1721 "Python/executor_cases.c.h" + #line 1994 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -1748,11 +2021,11 @@ if (iter == NULL) { goto error; } - #line 1752 "Python/executor_cases.c.h" + #line 2025 "Python/executor_cases.c.h" Py_DECREF(iterable); #line 2398 "Python/bytecodes.c" } - #line 1756 "Python/executor_cases.c.h" + #line 2029 "Python/executor_cases.c.h" stack_pointer[-1] = iter; break; } @@ -1783,7 +2056,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 1787 "Python/executor_cases.c.h" + #line 2060 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -1802,7 +2075,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 1806 "Python/executor_cases.c.h" + #line 2079 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -1811,7 +2084,7 @@ case EXIT_INIT_CHECK: { PyObject *should_be_none = stack_pointer[-1]; - #line 3038 "Python/bytecodes.c" + #line 3039 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -1819,7 +2092,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 1823 "Python/executor_cases.c.h" + #line 2096 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -1827,7 +2100,7 @@ case MAKE_FUNCTION: { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3452 "Python/bytecodes.c" + #line 3453 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -1839,7 +2112,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 1843 "Python/executor_cases.c.h" + #line 2116 "Python/executor_cases.c.h" stack_pointer[-1] = func; break; } @@ -1847,7 +2120,7 @@ case SET_FUNCTION_ATTRIBUTE: { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3466 "Python/bytecodes.c" + #line 3467 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -1872,7 +2145,7 @@ default: Py_UNREACHABLE(); } - #line 1876 "Python/executor_cases.c.h" + #line 2149 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; break; @@ -1883,15 +2156,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3516 "Python/bytecodes.c" + #line 3517 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 1889 "Python/executor_cases.c.h" + #line 2162 "Python/executor_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3518 "Python/bytecodes.c" + #line 3519 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 1895 "Python/executor_cases.c.h" + #line 2168 "Python/executor_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -1901,14 +2174,14 @@ case CONVERT_VALUE: { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3522 "Python/bytecodes.c" + #line 3523 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 1912 "Python/executor_cases.c.h" + #line 2185 "Python/executor_cases.c.h" stack_pointer[-1] = result; break; } @@ -1916,7 +2189,7 @@ case FORMAT_SIMPLE: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3531 "Python/bytecodes.c" + #line 3532 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -1927,7 +2200,7 @@ else { res = value; } - #line 1931 "Python/executor_cases.c.h" + #line 2204 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -1936,12 +2209,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3544 "Python/bytecodes.c" + #line 3545 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 1945 "Python/executor_cases.c.h" + #line 2218 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -1950,21 +2223,52 @@ case COPY: { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3551 "Python/bytecodes.c" + #line 3552 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 1957 "Python/executor_cases.c.h" + #line 2230 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; break; } + case BINARY_OP: { + static_assert(INLINE_CACHE_ENTRIES_BINARY_OP == 1, "incorrect cache size"); + PyObject *rhs = stack_pointer[-1]; + PyObject *lhs = stack_pointer[-2]; + PyObject *res; + #line 3557 "Python/bytecodes.c" + #if ENABLE_SPECIALIZATION + _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; + if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { + 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); + #line 2256 "Python/executor_cases.c.h" + Py_DECREF(lhs); + Py_DECREF(rhs); + #line 3572 "Python/bytecodes.c" + if (res == NULL) goto pop_2_error; + #line 2261 "Python/executor_cases.c.h" + STACK_SHRINK(1); + stack_pointer[-1] = res; + break; + } + case SWAP: { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3576 "Python/bytecodes.c" + #line 3577 "Python/bytecodes.c" assert(oparg >= 2); - #line 1968 "Python/executor_cases.c.h" + #line 2272 "Python/executor_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; break; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 63c05a2cb2eade..a6354910053427 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -4168,9 +4168,6 @@ goto error; } Py_DECREF(tp); - if (_Py_EnterRecursivePy(tstate)) { - goto exit_unwind; - } _PyInterpreterFrame *shim = _PyFrame_PushTrampolineUnchecked( tstate, (PyCodeObject *)&_Py_InitCleanup, 1, 0); assert(_PyCode_CODE((PyCodeObject *)shim->f_executable)[1].op.code == EXIT_INIT_CHECK); @@ -4194,13 +4191,17 @@ shim->previous = frame; frame = cframe.current_frame = init_frame; CALL_STAT_INC(inlined_py_calls); + /* Account for pushing the extra frame. + * We don't check recursion depth here, + * as it will be checked after start_frame */ + tstate->py_recursion_remaining--; goto start_frame; - #line 4199 "Python/generated_cases.c.h" + #line 4200 "Python/generated_cases.c.h" } TARGET(EXIT_INIT_CHECK) { PyObject *should_be_none = stack_pointer[-1]; - #line 3038 "Python/bytecodes.c" + #line 3039 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -4208,7 +4209,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 4212 "Python/generated_cases.c.h" + #line 4213 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -4218,7 +4219,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3048 "Python/bytecodes.c" + #line 3049 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4240,7 +4241,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4244 "Python/generated_cases.c.h" + #line 4245 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4254,7 +4255,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3073 "Python/bytecodes.c" + #line 3074 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4282,7 +4283,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4286 "Python/generated_cases.c.h" + #line 4287 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4296,7 +4297,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3104 "Python/bytecodes.c" + #line 3105 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4328,7 +4329,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4332 "Python/generated_cases.c.h" + #line 4333 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4342,7 +4343,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3139 "Python/bytecodes.c" + #line 3140 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4374,7 +4375,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4378 "Python/generated_cases.c.h" + #line 4379 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4388,7 +4389,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3174 "Python/bytecodes.c" + #line 3175 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4413,7 +4414,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4417 "Python/generated_cases.c.h" + #line 4418 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4426,7 +4427,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3201 "Python/bytecodes.c" + #line 3202 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4453,7 +4454,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4457 "Python/generated_cases.c.h" + #line 4458 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4465,7 +4466,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3231 "Python/bytecodes.c" + #line 3232 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4483,14 +4484,14 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4487 "Python/generated_cases.c.h" + #line 4488 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3251 "Python/bytecodes.c" + #line 3252 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4521,7 +4522,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4525 "Python/generated_cases.c.h" + #line 4526 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4534,7 +4535,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3285 "Python/bytecodes.c" + #line 3286 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4563,7 +4564,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4567 "Python/generated_cases.c.h" + #line 4568 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4576,7 +4577,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3317 "Python/bytecodes.c" + #line 3318 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4605,7 +4606,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4609 "Python/generated_cases.c.h" + #line 4610 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4618,7 +4619,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3349 "Python/bytecodes.c" + #line 3350 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4646,7 +4647,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4650 "Python/generated_cases.c.h" + #line 4651 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4656,9 +4657,9 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3380 "Python/bytecodes.c" + #line 3381 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4662 "Python/generated_cases.c.h" + #line 4663 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4667,7 +4668,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3384 "Python/bytecodes.c" + #line 3385 "Python/bytecodes.c" // DICT_MERGE is called before this opcode if there are kwargs. // It converts all dict subtypes in kwargs into regular dicts. assert(kwargs == NULL || PyDict_CheckExact(kwargs)); @@ -4729,14 +4730,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4733 "Python/generated_cases.c.h" + #line 4734 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3446 "Python/bytecodes.c" + #line 3447 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4740 "Python/generated_cases.c.h" + #line 4741 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4747,7 +4748,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3452 "Python/bytecodes.c" + #line 3453 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4759,7 +4760,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4763 "Python/generated_cases.c.h" + #line 4764 "Python/generated_cases.c.h" stack_pointer[-1] = func; DISPATCH(); } @@ -4767,7 +4768,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3466 "Python/bytecodes.c" + #line 3467 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4792,14 +4793,14 @@ default: Py_UNREACHABLE(); } - #line 4796 "Python/generated_cases.c.h" + #line 4797 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; DISPATCH(); } TARGET(RETURN_GENERATOR) { - #line 3493 "Python/bytecodes.c" + #line 3494 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4820,7 +4821,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4824 "Python/generated_cases.c.h" + #line 4825 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4828,15 +4829,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3516 "Python/bytecodes.c" + #line 3517 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4834 "Python/generated_cases.c.h" + #line 4835 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3518 "Python/bytecodes.c" + #line 3519 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4840 "Python/generated_cases.c.h" + #line 4841 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4846,14 +4847,14 @@ TARGET(CONVERT_VALUE) { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3522 "Python/bytecodes.c" + #line 3523 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 4857 "Python/generated_cases.c.h" + #line 4858 "Python/generated_cases.c.h" stack_pointer[-1] = result; DISPATCH(); } @@ -4861,7 +4862,7 @@ TARGET(FORMAT_SIMPLE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3531 "Python/bytecodes.c" + #line 3532 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -4872,7 +4873,7 @@ else { res = value; } - #line 4876 "Python/generated_cases.c.h" + #line 4877 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -4881,12 +4882,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3544 "Python/bytecodes.c" + #line 3545 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 4890 "Python/generated_cases.c.h" + #line 4891 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -4895,10 +4896,10 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3551 "Python/bytecodes.c" + #line 3552 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4902 "Python/generated_cases.c.h" + #line 4903 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4910,7 +4911,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3556 "Python/bytecodes.c" + #line 3557 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4925,12 +4926,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4929 "Python/generated_cases.c.h" + #line 4930 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3571 "Python/bytecodes.c" + #line 3572 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4934 "Python/generated_cases.c.h" + #line 4935 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4940,16 +4941,16 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3576 "Python/bytecodes.c" + #line 3577 "Python/bytecodes.c" assert(oparg >= 2); - #line 4946 "Python/generated_cases.c.h" + #line 4947 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3580 "Python/bytecodes.c" + #line 3581 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4961,48 +4962,48 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4965 "Python/generated_cases.c.h" + #line 4966 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3594 "Python/bytecodes.c" + #line 3595 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4971 "Python/generated_cases.c.h" + #line 4972 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3598 "Python/bytecodes.c" + #line 3599 "Python/bytecodes.c" CHECK_EVAL_BREAKER(); INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 4979 "Python/generated_cases.c.h" + #line 4980 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3603 "Python/bytecodes.c" + #line 3604 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; int offset = Py_IsTrue(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4990 "Python/generated_cases.c.h" + #line 4991 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3611 "Python/bytecodes.c" + #line 3612 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; int offset = Py_IsFalse(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5001 "Python/generated_cases.c.h" + #line 5002 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3619 "Python/bytecodes.c" + #line 3620 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -5014,12 +5015,12 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5018 "Python/generated_cases.c.h" + #line 5019 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3633 "Python/bytecodes.c" + #line 3634 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -5031,30 +5032,30 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5035 "Python/generated_cases.c.h" + #line 5036 "Python/generated_cases.c.h" DISPATCH(); } TARGET(EXTENDED_ARG) { - #line 3647 "Python/bytecodes.c" + #line 3648 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 5046 "Python/generated_cases.c.h" + #line 5047 "Python/generated_cases.c.h" } TARGET(CACHE) { - #line 3655 "Python/bytecodes.c" + #line 3656 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 5053 "Python/generated_cases.c.h" + #line 5054 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3660 "Python/bytecodes.c" + #line 3661 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 5060 "Python/generated_cases.c.h" + #line 5061 "Python/generated_cases.c.h" } diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index ac86a4abd9c1b3..70e1ca44ce7663 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -934,6 +934,12 @@ struct opcode_macro_expansion { struct { int16_t uop; int8_t size; int8_t offset; } uops[8]; }; +#define OPARG_FULL 0 +#define OPARG_CACHE_1 1 +#define OPARG_CACHE_2 2 +#define OPARG_CACHE_4 4 +#define OPARG_TOP 5 +#define OPARG_BOTTOM 6 #define OPCODE_METADATA_FMT(OP) (_PyOpcode_opcode_metadata[(OP)].instr_format) #define SAME_OPCODE_METADATA(OP1, OP2) \ @@ -1165,14 +1171,18 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [LOAD_FAST_CHECK] = { .nuops = 1, .uops = { { LOAD_FAST_CHECK, 0, 0 } } }, [LOAD_FAST] = { .nuops = 1, .uops = { { LOAD_FAST, 0, 0 } } }, [LOAD_FAST_AND_CLEAR] = { .nuops = 1, .uops = { { LOAD_FAST_AND_CLEAR, 0, 0 } } }, + [LOAD_FAST_LOAD_FAST] = { .nuops = 2, .uops = { { LOAD_FAST, 5, 0 }, { LOAD_FAST, 6, 0 } } }, [LOAD_CONST] = { .nuops = 1, .uops = { { LOAD_CONST, 0, 0 } } }, [STORE_FAST] = { .nuops = 1, .uops = { { STORE_FAST, 0, 0 } } }, + [STORE_FAST_LOAD_FAST] = { .nuops = 2, .uops = { { STORE_FAST, 5, 0 }, { LOAD_FAST, 6, 0 } } }, + [STORE_FAST_STORE_FAST] = { .nuops = 2, .uops = { { STORE_FAST, 5, 0 }, { STORE_FAST, 6, 0 } } }, [POP_TOP] = { .nuops = 1, .uops = { { POP_TOP, 0, 0 } } }, [PUSH_NULL] = { .nuops = 1, .uops = { { PUSH_NULL, 0, 0 } } }, [END_FOR] = { .nuops = 2, .uops = { { POP_TOP, 0, 0 }, { POP_TOP, 0, 0 } } }, [END_SEND] = { .nuops = 1, .uops = { { END_SEND, 0, 0 } } }, [UNARY_NEGATIVE] = { .nuops = 1, .uops = { { UNARY_NEGATIVE, 0, 0 } } }, [UNARY_NOT] = { .nuops = 1, .uops = { { UNARY_NOT, 0, 0 } } }, + [TO_BOOL] = { .nuops = 1, .uops = { { TO_BOOL, 0, 0 } } }, [TO_BOOL_BOOL] = { .nuops = 1, .uops = { { TO_BOOL_BOOL, 0, 0 } } }, [TO_BOOL_INT] = { .nuops = 1, .uops = { { TO_BOOL_INT, 0, 0 } } }, [TO_BOOL_LIST] = { .nuops = 1, .uops = { { TO_BOOL_LIST, 0, 0 } } }, @@ -1187,6 +1197,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [BINARY_OP_ADD_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_ADD_FLOAT, 0, 0 } } }, [BINARY_OP_SUBTRACT_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_SUBTRACT_FLOAT, 0, 0 } } }, [BINARY_OP_ADD_UNICODE] = { .nuops = 2, .uops = { { _GUARD_BOTH_UNICODE, 0, 0 }, { _BINARY_OP_ADD_UNICODE, 0, 0 } } }, + [BINARY_SUBSCR] = { .nuops = 1, .uops = { { BINARY_SUBSCR, 0, 0 } } }, [BINARY_SLICE] = { .nuops = 1, .uops = { { BINARY_SLICE, 0, 0 } } }, [STORE_SLICE] = { .nuops = 1, .uops = { { STORE_SLICE, 0, 0 } } }, [BINARY_SUBSCR_LIST_INT] = { .nuops = 1, .uops = { { BINARY_SUBSCR_LIST_INT, 0, 0 } } }, @@ -1194,6 +1205,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [BINARY_SUBSCR_DICT] = { .nuops = 1, .uops = { { BINARY_SUBSCR_DICT, 0, 0 } } }, [LIST_APPEND] = { .nuops = 1, .uops = { { LIST_APPEND, 0, 0 } } }, [SET_ADD] = { .nuops = 1, .uops = { { SET_ADD, 0, 0 } } }, + [STORE_SUBSCR] = { .nuops = 1, .uops = { { STORE_SUBSCR, 1, 0 } } }, [STORE_SUBSCR_LIST_INT] = { .nuops = 1, .uops = { { STORE_SUBSCR_LIST_INT, 0, 0 } } }, [STORE_SUBSCR_DICT] = { .nuops = 1, .uops = { { STORE_SUBSCR_DICT, 0, 0 } } }, [DELETE_SUBSCR] = { .nuops = 1, .uops = { { DELETE_SUBSCR, 0, 0 } } }, @@ -1207,6 +1219,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [LOAD_BUILD_CLASS] = { .nuops = 1, .uops = { { LOAD_BUILD_CLASS, 0, 0 } } }, [STORE_NAME] = { .nuops = 1, .uops = { { STORE_NAME, 0, 0 } } }, [DELETE_NAME] = { .nuops = 1, .uops = { { DELETE_NAME, 0, 0 } } }, + [UNPACK_SEQUENCE] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE, 0, 0 } } }, [UNPACK_SEQUENCE_TWO_TUPLE] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_TWO_TUPLE, 0, 0 } } }, [UNPACK_SEQUENCE_TUPLE] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_TUPLE, 0, 0 } } }, [UNPACK_SEQUENCE_LIST] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_LIST, 0, 0 } } }, @@ -1217,6 +1230,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [LOAD_LOCALS] = { .nuops = 1, .uops = { { _LOAD_LOCALS, 0, 0 } } }, [LOAD_NAME] = { .nuops = 2, .uops = { { _LOAD_LOCALS, 0, 0 }, { _LOAD_FROM_DICT_OR_GLOBALS, 0, 0 } } }, [LOAD_FROM_DICT_OR_GLOBALS] = { .nuops = 1, .uops = { { _LOAD_FROM_DICT_OR_GLOBALS, 0, 0 } } }, + [LOAD_GLOBAL] = { .nuops = 1, .uops = { { LOAD_GLOBAL, 0, 0 } } }, [DELETE_FAST] = { .nuops = 1, .uops = { { DELETE_FAST, 0, 0 } } }, [DELETE_DEREF] = { .nuops = 1, .uops = { { DELETE_DEREF, 0, 0 } } }, [LOAD_FROM_DICT_OR_DEREF] = { .nuops = 1, .uops = { { LOAD_FROM_DICT_OR_DEREF, 0, 0 } } }, @@ -1237,6 +1251,8 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [MAP_ADD] = { .nuops = 1, .uops = { { MAP_ADD, 0, 0 } } }, [LOAD_SUPER_ATTR_ATTR] = { .nuops = 1, .uops = { { LOAD_SUPER_ATTR_ATTR, 0, 0 } } }, [LOAD_SUPER_ATTR_METHOD] = { .nuops = 1, .uops = { { LOAD_SUPER_ATTR_METHOD, 0, 0 } } }, + [LOAD_ATTR] = { .nuops = 1, .uops = { { LOAD_ATTR, 0, 0 } } }, + [COMPARE_OP] = { .nuops = 1, .uops = { { COMPARE_OP, 0, 0 } } }, [COMPARE_OP_FLOAT] = { .nuops = 1, .uops = { { COMPARE_OP_FLOAT, 0, 0 } } }, [COMPARE_OP_INT] = { .nuops = 1, .uops = { { COMPARE_OP_INT, 0, 0 } } }, [COMPARE_OP_STR] = { .nuops = 1, .uops = { { COMPARE_OP_STR, 0, 0 } } }, @@ -1261,6 +1277,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { [FORMAT_SIMPLE] = { .nuops = 1, .uops = { { FORMAT_SIMPLE, 0, 0 } } }, [FORMAT_WITH_SPEC] = { .nuops = 1, .uops = { { FORMAT_WITH_SPEC, 0, 0 } } }, [COPY] = { .nuops = 1, .uops = { { COPY, 0, 0 } } }, + [BINARY_OP] = { .nuops = 1, .uops = { { BINARY_OP, 0, 0 } } }, [SWAP] = { .nuops = 1, .uops = { { SWAP, 0, 0 } } }, }; #ifdef NEED_OPCODE_METADATA diff --git a/Python/optimizer.c b/Python/optimizer.c index 2c1be61f8d614e..1d731ed2309c3c 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -411,37 +411,21 @@ translate_bytecode_to_trace( for (;;) { ADD_TO_TRACE(SAVE_IP, (int)(instr - (_Py_CODEUNIT *)code->co_code_adaptive)); int opcode = instr->op.code; - uint64_t operand = instr->op.arg; + int oparg = instr->op.arg; + int extras = 0; + while (opcode == EXTENDED_ARG) { + instr++; + extras += 1; + opcode = instr->op.code; + oparg = (oparg << 8) | instr->op.arg; + } + if (opcode == ENTER_EXECUTOR) { + _PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255]; + opcode = executor->vm_data.opcode; + DPRINTF(2, " * ENTER_EXECUTOR -> %s\n", _PyOpcode_OpName[opcode]); + oparg = (oparg & 0xffffff00) | executor->vm_data.oparg; + } switch (opcode) { - case LOAD_FAST_LOAD_FAST: - case STORE_FAST_LOAD_FAST: - case STORE_FAST_STORE_FAST: - { - // Reserve space for two uops (+ SAVE_IP + EXIT_TRACE) - if (trace_length + 4 > max_length) { - DPRINTF(1, "Ran out of space for LOAD_FAST_LOAD_FAST\n"); - goto done; - } - uint64_t oparg1 = operand >> 4; - uint64_t oparg2 = operand & 15; - switch (opcode) { - case LOAD_FAST_LOAD_FAST: - ADD_TO_TRACE(LOAD_FAST, oparg1); - ADD_TO_TRACE(LOAD_FAST, oparg2); - break; - case STORE_FAST_LOAD_FAST: - ADD_TO_TRACE(STORE_FAST, oparg1); - ADD_TO_TRACE(LOAD_FAST, oparg2); - break; - case STORE_FAST_STORE_FAST: - ADD_TO_TRACE(STORE_FAST, oparg1); - ADD_TO_TRACE(STORE_FAST, oparg2); - break; - default: - Py_FatalError("Missing case"); - } - break; - } default: { const struct opcode_macro_expansion *expansion = &_PyOpcode_macro_expansion[opcode]; @@ -455,23 +439,40 @@ translate_bytecode_to_trace( goto done; } for (int i = 0; i < nuops; i++) { + uint64_t operand; int offset = expansion->uops[i].offset; switch (expansion->uops[i].size) { - case 0: + case OPARG_FULL: + operand = oparg; + if (extras && OPCODE_HAS_JUMP(opcode)) { + if (opcode == JUMP_BACKWARD_NO_INTERRUPT) { + operand -= extras; + } + else { + assert(opcode != JUMP_BACKWARD); + operand += extras; + } + } break; - case 1: + case OPARG_CACHE_1: operand = read_u16(&instr[offset].cache); break; - case 2: + case OPARG_CACHE_2: operand = read_u32(&instr[offset].cache); break; - case 4: + case OPARG_CACHE_4: operand = read_u64(&instr[offset].cache); break; + case OPARG_TOP: // First half of super-instr + operand = oparg >> 4; + break; + case OPARG_BOTTOM: // Second half of super-instr + operand = oparg & 0xF; + break; default: fprintf(stderr, - "opcode=%d, operand=%" PRIu64 "; nuops=%d, i=%d; size=%d, offset=%d\n", - opcode, operand, nuops, i, + "opcode=%d, oparg=%d; nuops=%d, i=%d; size=%d, offset=%d\n", + opcode, oparg, nuops, i, expansion->uops[i].size, expansion->uops[i].offset); Py_FatalError("garbled expansion"); @@ -532,7 +533,7 @@ uop_optimize( return trace_length; } OBJECT_STAT_INC(optimization_traces_created); - _PyUOpExecutorObject *executor = (_PyUOpExecutorObject *)_PyObject_New(&UOpExecutor_Type); + _PyUOpExecutorObject *executor = PyObject_New(_PyUOpExecutorObject, &UOpExecutor_Type); if (executor == NULL) { return -1; } @@ -542,18 +543,24 @@ uop_optimize( return 1; } +static void +uop_opt_dealloc(PyObject *self) { + PyObject_Free(self); +} + static PyTypeObject UOpOptimizer_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) .tp_name = "uop_optimizer", .tp_basicsize = sizeof(_PyOptimizerObject), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, + .tp_dealloc = uop_opt_dealloc, }; PyObject * PyUnstable_Optimizer_NewUOpOptimizer(void) { - _PyOptimizerObject *opt = (_PyOptimizerObject *)_PyObject_New(&UOpOptimizer_Type); + _PyOptimizerObject *opt = PyObject_New(_PyOptimizerObject, &UOpOptimizer_Type); if (opt == NULL) { return NULL; } diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py index a90abfe20c1739..14269ca8cbe750 100644 --- a/Tools/cases_generator/generate_cases.py +++ b/Tools/cases_generator/generate_cases.py @@ -40,6 +40,17 @@ UNUSED = "unused" BITS_PER_CODE_UNIT = 16 +# Constants used instead of size for macro expansions. +# Note: 1, 2, 4 must match actual cache entry sizes. +OPARG_SIZES = { + "OPARG_FULL": 0, + "OPARG_CACHE_1": 1, + "OPARG_CACHE_2": 2, + "OPARG_CACHE_4": 4, + "OPARG_TOP": 5, + "OPARG_BOTTOM": 6, +} + RESERVED_WORDS = { "co_consts" : "Use FRAME_CO_CONSTS.", "co_names": "Use FRAME_CO_NAMES.", @@ -414,8 +425,9 @@ def is_viable_uop(self) -> bool: return False res = True for forbidden in FORBIDDEN_NAMES_IN_UOPS: - # TODO: Don't check in '#ifdef ENABLE_SPECIALIZATION' regions - if variable_used(self.inst, forbidden): + # NOTE: To disallow unspecialized uops, use + # if variable_used(self.inst, forbidden): + if variable_used_unspecialized(self.inst, forbidden): # print(f"Skipping {self.name} because it uses {forbidden}") res = False return res @@ -1213,7 +1225,10 @@ def write_metadata(self) -> None: self.out.emit("struct { int16_t uop; int8_t size; int8_t offset; } uops[8];") self.out.emit("") + for key, value in OPARG_SIZES.items(): + self.out.emit(f"#define {key} {value}") self.out.emit("") + self.out.emit("#define OPCODE_METADATA_FMT(OP) " "(_PyOpcode_opcode_metadata[(OP)].instr_format)") self.out.emit("#define SAME_OPCODE_METADATA(OP1, OP2) \\") @@ -1263,6 +1278,9 @@ def write_metadata(self) -> None: # Construct a dummy Component -- input/output mappings are not used part = Component(instr, [], [], instr.active_caches) self.write_macro_expansions(instr.name, [part]) + elif instr.kind == "inst" and variable_used(instr.inst, "oparg1"): + assert variable_used(instr.inst, "oparg2"), "Half super-instr?" + self.write_super_expansions(instr.name) case parser.Macro(): mac = self.macro_instrs[thing.name] self.write_macro_expansions(mac.name, mac.parts) @@ -1342,7 +1360,7 @@ def write_macro_expansions(self, name: str, parts: MacroParts) -> None: print(f"NOTE: Part {part.instr.name} of {name} is not a viable uop") return if part.instr.instr_flags.HAS_ARG_FLAG or not part.active_caches: - size, offset = 0, 0 + size, offset = OPARG_SIZES["OPARG_FULL"], 0 else: # If this assert triggers, is_viable_uops() lied assert len(part.active_caches) == 1, (name, part.instr.name) @@ -1350,10 +1368,50 @@ def write_macro_expansions(self, name: str, parts: MacroParts) -> None: size, offset = cache.effect.size, cache.offset expansions.append((part.instr.name, size, offset)) assert len(expansions) > 0, f"Macro {name} has empty expansion?!" + self.write_expansions(name, expansions) + + def write_super_expansions(self, name: str) -> None: + """Write special macro expansions for super-instructions. + + If you get an assertion failure here, you probably have accidentally + violated one of the assumptions here. + + - A super-instruction's name is of the form FIRST_SECOND where + FIRST and SECOND are regular instructions whose name has the + form FOO_BAR. Thus, there must be exactly 3 underscores. + Example: LOAD_CONST_STORE_FAST. + + - A super-instruction's body uses `oparg1 and `oparg2`, and no + other instruction's body uses those variable names. + + - A super-instruction has no active (used) cache entries. + + In the expansion, the first instruction's operand is all but the + bottom 4 bits of the super-instruction's oparg, and the second + instruction's operand is the bottom 4 bits. We use the special + size codes OPARG_TOP and OPARG_BOTTOM for these. + """ + pieces = name.split("_") + assert len(pieces) == 4, f"{name} doesn't look like a super-instr" + name1 = "_".join(pieces[:2]) + name2 = "_".join(pieces[2:]) + assert name1 in self.instrs, f"{name1} doesn't match any instr" + assert name2 in self.instrs, f"{name2} doesn't match any instr" + instr1 = self.instrs[name1] + instr2 = self.instrs[name2] + assert not instr1.active_caches, f"{name1} has active caches" + assert not instr2.active_caches, f"{name2} has active caches" + expansions = [ + (name1, OPARG_SIZES["OPARG_TOP"], 0), + (name2, OPARG_SIZES["OPARG_BOTTOM"], 0), + ] + self.write_expansions(name, expansions) + + def write_expansions(self, name: str, expansions: list[tuple[str, int, int]]) -> None: pieces = [f"{{ {name}, {size}, {offset} }}" for name, size, offset in expansions] self.out.emit( f"[{name}] = " - f"{{ .nuops = {len(expansions)}, .uops = {{ {', '.join(pieces)} }} }}," + f"{{ .nuops = {len(pieces)}, .uops = {{ {', '.join(pieces)} }} }}," ) def emit_metadata_entry( @@ -1587,6 +1645,27 @@ def variable_used(node: parser.Node, name: str) -> bool: ) +def variable_used_unspecialized(node: parser.Node, name: str) -> bool: + """Like variable_used(), but skips #if ENABLE_SPECIALIZATION blocks.""" + tokens: list[lx.Token] = [] + skipping = False + for i, token in enumerate(node.tokens): + if token.kind == "MACRO": + text = "".join(token.text.split()) + # TODO: Handle nested #if + if text == "#if": + if ( + i + 1 < len(node.tokens) + and node.tokens[i + 1].text == "ENABLE_SPECIALIZATION" + ): + skipping = True + elif text in ("#else", "#endif"): + skipping = False + if not skipping: + tokens.append(token) + return any(token.kind == "IDENTIFIER" and token.text == name for token in tokens) + + def main(): """Parse command line, parse input, analyze, write output.""" args = arg_parser.parse_args() # Prints message and sys.exit(2) on error diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py index 24d6255f262da4..19c5f573920cb9 100755 --- a/Tools/clinic/clinic.py +++ b/Tools/clinic/clinic.py @@ -2439,6 +2439,8 @@ def __repr__(self) -> str: ParamDict = dict[str, "Parameter"] ReturnConverterType = Callable[..., "CReturnConverter"] + +@dc.dataclass(repr=False) class Function: """ Mutable duck type for inspect.Function. @@ -2450,49 +2452,34 @@ class Function: It will always be true that (not docstring) or ((not docstring[0].isspace()) and (docstring.rstrip() == docstring)) """ + parameters: ParamDict = dc.field(default_factory=dict) + _: dc.KW_ONLY + name: str + module: Module + cls: Class | None = None + c_basename: str | None = None + full_name: str | None = None + return_converter: CReturnConverter + return_annotation: object = inspect.Signature.empty + docstring: str = '' + kind: str = CALLABLE + coexist: bool = False + # docstring_only means "don't generate a machine-readable + # signature, just a normal docstring". it's True for + # functions with optional groups because we can't represent + # those accurately with inspect.Signature in 3.4. + docstring_only: bool = False - def __init__( - self, - parameters: ParamDict | None = None, - *, - name: str, - module: Module, - cls: Class | None = None, - c_basename: str | None = None, - full_name: str | None = None, - return_converter: CReturnConverter, - return_annotation = inspect.Signature.empty, - docstring: str | None = None, - kind: str = CALLABLE, - coexist: bool = False, - docstring_only: bool = False - ) -> None: - self.parameters = parameters or {} - self.return_annotation = return_annotation - self.name = name - self.full_name = full_name - self.module = module - self.cls = cls - self.parent = cls or module - self.c_basename = c_basename - self.return_converter = return_converter - self.docstring = docstring or '' - self.kind = kind - self.coexist = coexist + def __post_init__(self) -> None: + self.parent: Class | Module = self.cls or self.module self.self_converter: self_converter | None = None - # docstring_only means "don't generate a machine-readable - # signature, just a normal docstring". it's True for - # functions with optional groups because we can't represent - # those accurately with inspect.Signature in 3.4. - self.docstring_only = docstring_only - - self.rendered_parameters = None + self.__render_parameters__: list[Parameter] | None = None - __render_parameters__ = None @property - def render_parameters(self): + def render_parameters(self) -> list[Parameter]: if not self.__render_parameters__: - self.__render_parameters__ = l = [] + l: list[Parameter] = [] + self.__render_parameters__ = l for p in self.parameters.values(): p = p.copy() p.converter.pre_render() @@ -2517,17 +2504,8 @@ def methoddef_flags(self) -> str | None: def __repr__(self) -> str: return '' - def copy(self, **overrides) -> "Function": - kwargs = { - 'name': self.name, 'module': self.module, 'parameters': self.parameters, - 'cls': self.cls, 'c_basename': self.c_basename, - 'full_name': self.full_name, - 'return_converter': self.return_converter, 'return_annotation': self.return_annotation, - 'docstring': self.docstring, 'kind': self.kind, 'coexist': self.coexist, - 'docstring_only': self.docstring_only, - } - kwargs.update(overrides) - f = Function(**kwargs) + def copy(self, **overrides: Any) -> Function: + f = dc.replace(self, **overrides) f.parameters = { name: value.copy(function=f) for name, value in f.parameters.items() @@ -2535,31 +2513,21 @@ def copy(self, **overrides) -> "Function": return f +@dc.dataclass(repr=False, slots=True) class Parameter: """ Mutable duck type of inspect.Parameter. """ - - def __init__( - self, - name: str, - kind: inspect._ParameterKind, - *, - default = inspect.Parameter.empty, - function: Function, - converter: "CConverter", - annotation = inspect.Parameter.empty, - docstring: str | None = None, - group: int = 0 - ) -> None: - self.name = name - self.kind = kind - self.default = default - self.function = function - self.converter = converter - self.annotation = annotation - self.docstring = docstring or '' - self.group = group + name: str + kind: inspect._ParameterKind + _: dc.KW_ONLY + default: object = inspect.Parameter.empty + function: Function + converter: CConverter + annotation: object = inspect.Parameter.empty + docstring: str = '' + group: int = 0 + right_bracket_count: int = dc.field(init=False, default=0) def __repr__(self) -> str: return '' @@ -2576,18 +2544,19 @@ def is_vararg(self) -> bool: def is_optional(self) -> bool: return not self.is_vararg() and (self.default is not unspecified) - def copy(self, **overrides) -> "Parameter": - kwargs = { - 'name': self.name, 'kind': self.kind, 'default':self.default, - 'function': self.function, 'converter': self.converter, 'annotation': self.annotation, - 'docstring': self.docstring, 'group': self.group, - } - kwargs.update(overrides) - if 'converter' not in overrides: + def copy( + self, + /, + *, + converter: CConverter | None = None, + function: Function | None = None, + **overrides: Any + ) -> Parameter: + function = function or self.function + if not converter: converter = copy.copy(self.converter) - converter.function = kwargs['function'] - kwargs['converter'] = converter - return Parameter(**kwargs) + converter.function = function + return dc.replace(self, **overrides, function=function, converter=converter) def get_displayname(self, i: int) -> str: if i == 0: @@ -2761,7 +2730,7 @@ def __init__(self, # Positional args: name: str, py_name: str, - function, + function: Function, default: object = unspecified, *, # Keyword only args: c_default: str | None = None, @@ -2800,7 +2769,9 @@ def __init__(self, # about the function in the init. # (that breaks if we get cloned.) # so after this change we will noisily fail. - self.function = LandMine("Don't access members of self.function inside converter_init!") + self.function: Function | LandMine = LandMine( + "Don't access members of self.function inside converter_init!" + ) self.converter_init(**kwargs) self.function = function @@ -2810,7 +2781,7 @@ def converter_init(self): def is_optional(self) -> bool: return (self.default is not unspecified) - def _render_self(self, parameter: str, data: CRenderData) -> None: + def _render_self(self, parameter: Parameter, data: CRenderData) -> None: self.parameter = parameter name = self.parser_name @@ -2870,7 +2841,7 @@ def _render_non_self(self, parameter, data): if cleanup: data.cleanup.append('/* Cleanup for ' + name + ' */\n' + cleanup.rstrip() + "\n") - def render(self, parameter: str, data: CRenderData) -> None: + def render(self, parameter: Parameter, data: CRenderData) -> None: """ parameter is a clinic.Parameter instance. data is a CRenderData instance. @@ -5246,7 +5217,7 @@ def format_docstring(self): assert isinstance(parameters[0].converter, self_converter) # self is always positional-only. assert parameters[0].is_positional_only() - parameters[0].right_bracket_count = 0 + assert parameters[0].right_bracket_count == 0 positional_only = True for p in parameters[1:]: if not p.is_positional_only(): From 2b20a5ba597f06717b18bc7a8b37b06a1263bd88 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 7 Jul 2023 14:26:09 -0700 Subject: [PATCH 05/13] Un-materialize in LOAD_ATTR_INSTANCE_VALUE --- Python/bytecodes.c | 48 +++---- Python/generated_cases.c.h | 273 ++++++++++++++++++------------------- Python/specialize.c | 12 ++ 3 files changed, 172 insertions(+), 161 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 3aa4422835f0b5..4325228eb1459d 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1869,9 +1869,29 @@ dummy_func( 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[index]; + PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner); + if (!_PyDictOrValues_IsValues(*dorv)) { + PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(*dorv); + // It's likely that this __dict__ still shares its keys (if it + // was materialized on request and not heavily modified): + assert(dict); + assert(PyDict_CheckExact(dict)); + assert(_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)); + PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; + DEOPT_IF(dict->ma_keys != ht->ht_cached_keys, LOAD_ATTR); + assert(dict->ma_values); + DEOPT_IF(Py_REFCNT(dict) != 1, LOAD_ATTR); + // We have an opportunity to do something *really* cool: + // un-materialize it! + _PyDictKeys_DecRef(dict->ma_keys); + _PyDictOrValues_SetValues(dorv, dict->ma_values); + OBJECT_STAT_INC(dict_unmaterialized); + // Don't try this at home, kids: + dict->ma_keys = NULL; + dict->ma_values = NULL; + Py_DECREF(dict); + } + res = _PyDictOrValues_GetValues(*dorv)->values[index]; DEOPT_IF(res == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); @@ -1918,27 +1938,7 @@ dummy_func( DEOPT_IF(ep->me_key != name, LOAD_ATTR); res = ep->me_value; } - if (res == NULL) { - // This is almost never an AttributeError. It's way more likely - // that this __dict__ still shares its keys (for example, if it - // was materialized on request and not heavily modified): - DEOPT_IF(!_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), LOAD_ATTR); - PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; - DEOPT_IF(dict->ma_keys != ht->ht_cached_keys, LOAD_ATTR); - assert(dict->ma_values); - DEOPT_IF(Py_REFCNT(dict) != 1, LOAD_ATTR); - // We have an opportunity to do something *really* cool: - // un-materialize it! - _PyDictKeys_DecRef(dict->ma_keys); - _PyDictOrValues_SetValues(dorv, dict->ma_values); - OBJECT_STAT_INC(dict_unmaterialized); - // Don't try this at home, kids: - dict->ma_keys = NULL; - dict->ma_values = NULL; - Py_DECREF(dict); - // Guess what... our caches are still valid! - GO_TO_INSTRUCTION(LOAD_ATTR_INSTANCE_VALUE); - } + DEOPT_IF(res == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index a6354910053427..f00f89f67c4e52 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2622,7 +2622,6 @@ } TARGET(LOAD_ATTR_INSTANCE_VALUE) { - PREDICTED(LOAD_ATTR_INSTANCE_VALUE); PyObject *owner = stack_pointer[-1]; PyObject *res2 = NULL; PyObject *res; @@ -2634,14 +2633,34 @@ 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[index]; + PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner); + if (!_PyDictOrValues_IsValues(*dorv)) { + PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(*dorv); + // It's likely that this __dict__ still shares its keys (if it + // was materialized on request and not heavily modified): + assert(dict); + assert(PyDict_CheckExact(dict)); + assert(_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)); + PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; + DEOPT_IF(dict->ma_keys != ht->ht_cached_keys, LOAD_ATTR); + assert(dict->ma_values); + DEOPT_IF(Py_REFCNT(dict) != 1, LOAD_ATTR); + // We have an opportunity to do something *really* cool: + // un-materialize it! + _PyDictKeys_DecRef(dict->ma_keys); + _PyDictOrValues_SetValues(dorv, dict->ma_values); + OBJECT_STAT_INC(dict_unmaterialized); + // Don't try this at home, kids: + dict->ma_keys = NULL; + dict->ma_values = NULL; + Py_DECREF(dict); + } + res = _PyDictOrValues_GetValues(*dorv)->values[index]; DEOPT_IF(res == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2645 "Python/generated_cases.c.h" + #line 2664 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2656,7 +2675,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1883 "Python/bytecodes.c" + #line 1903 "Python/bytecodes.c" DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; assert(dict != NULL); @@ -2669,7 +2688,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2673 "Python/generated_cases.c.h" + #line 2692 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2684,7 +2703,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); uint16_t index = read_u16(&next_instr[3].cache); - #line 1899 "Python/bytecodes.c" + #line 1919 "Python/bytecodes.c" PyTypeObject *tp = Py_TYPE(owner); assert(type_version != 0); DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR); @@ -2707,31 +2726,11 @@ DEOPT_IF(ep->me_key != name, LOAD_ATTR); res = ep->me_value; } - if (res == NULL) { - // This is almost never an AttributeError. It's way more likely - // that this __dict__ still shares its keys (for example, if it - // was materialized on request and not heavily modified): - DEOPT_IF(!_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), LOAD_ATTR); - PyHeapTypeObject *ht = (PyHeapTypeObject *)tp; - DEOPT_IF(dict->ma_keys != ht->ht_cached_keys, LOAD_ATTR); - assert(dict->ma_values); - DEOPT_IF(Py_REFCNT(dict) != 1, LOAD_ATTR); - // We have an opportunity to do something *really* cool: - // un-materialize it! - _PyDictKeys_DecRef(dict->ma_keys); - _PyDictOrValues_SetValues(dorv, dict->ma_values); - OBJECT_STAT_INC(dict_unmaterialized); - // Don't try this at home, kids: - dict->ma_keys = NULL; - dict->ma_values = NULL; - Py_DECREF(dict); - // Guess what... our caches are still valid! - GO_TO_INSTRUCTION(LOAD_ATTR_INSTANCE_VALUE); - } + DEOPT_IF(res == NULL, LOAD_ATTR); STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2735 "Python/generated_cases.c.h" + #line 2734 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2756,7 +2755,7 @@ STAT_INC(LOAD_ATTR, hit); Py_INCREF(res); res2 = NULL; - #line 2760 "Python/generated_cases.c.h" + #line 2759 "Python/generated_cases.c.h" Py_DECREF(owner); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2783,7 +2782,7 @@ res = descr; assert(res != NULL); Py_INCREF(res); - #line 2787 "Python/generated_cases.c.h" + #line 2786 "Python/generated_cases.c.h" Py_DECREF(cls); STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; @@ -2821,7 +2820,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2825 "Python/generated_cases.c.h" + #line 2824 "Python/generated_cases.c.h" } TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) { @@ -2855,7 +2854,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_LOAD_ATTR); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 2859 "Python/generated_cases.c.h" + #line 2858 "Python/generated_cases.c.h" } TARGET(STORE_ATTR_INSTANCE_VALUE) { @@ -2881,7 +2880,7 @@ Py_DECREF(old_value); } Py_DECREF(owner); - #line 2885 "Python/generated_cases.c.h" + #line 2884 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2931,7 +2930,7 @@ /* PEP 509 */ dict->ma_version_tag = new_version; Py_DECREF(owner); - #line 2935 "Python/generated_cases.c.h" + #line 2934 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2952,7 +2951,7 @@ *(PyObject **)addr = value; Py_XDECREF(old_value); Py_DECREF(owner); - #line 2956 "Python/generated_cases.c.h" + #line 2955 "Python/generated_cases.c.h" STACK_SHRINK(2); next_instr += 4; DISPATCH(); @@ -2977,7 +2976,7 @@ #endif /* ENABLE_SPECIALIZATION */ assert((oparg >> 5) <= Py_GE); res = PyObject_RichCompare(left, right, oparg >> 5); - #line 2981 "Python/generated_cases.c.h" + #line 2980 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); #line 2124 "Python/bytecodes.c" @@ -2988,7 +2987,7 @@ if (res_bool < 0) goto pop_2_error; res = res_bool ? Py_True : Py_False; } - #line 2992 "Python/generated_cases.c.h" + #line 2991 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -3011,7 +3010,7 @@ _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 3015 "Python/generated_cases.c.h" + #line 3014 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -3038,7 +3037,7 @@ _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free); res = (sign_ish & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 3042 "Python/generated_cases.c.h" + #line 3041 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -3062,7 +3061,7 @@ assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS); res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False; // It's always a bool, so we don't care about oparg & 16. - #line 3066 "Python/generated_cases.c.h" + #line 3065 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -3075,12 +3074,12 @@ PyObject *b; #line 2183 "Python/bytecodes.c" int res = Py_Is(left, right) ^ oparg; - #line 3079 "Python/generated_cases.c.h" + #line 3078 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); #line 2185 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 3084 "Python/generated_cases.c.h" + #line 3083 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -3092,13 +3091,13 @@ PyObject *b; #line 2189 "Python/bytecodes.c" int res = PySequence_Contains(right, left); - #line 3096 "Python/generated_cases.c.h" + #line 3095 "Python/generated_cases.c.h" Py_DECREF(left); Py_DECREF(right); #line 2191 "Python/bytecodes.c" if (res < 0) goto pop_2_error; b = (res ^ oparg) ? Py_True : Py_False; - #line 3102 "Python/generated_cases.c.h" + #line 3101 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = b; DISPATCH(); @@ -3111,7 +3110,7 @@ PyObject *match; #line 2196 "Python/bytecodes.c" if (check_except_star_type_valid(tstate, match_type) < 0) { - #line 3115 "Python/generated_cases.c.h" + #line 3114 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); #line 2198 "Python/bytecodes.c" @@ -3122,7 +3121,7 @@ rest = NULL; int res = exception_group_match(exc_value, match_type, &match, &rest); - #line 3126 "Python/generated_cases.c.h" + #line 3125 "Python/generated_cases.c.h" Py_DECREF(exc_value); Py_DECREF(match_type); #line 2206 "Python/bytecodes.c" @@ -3134,7 +3133,7 @@ if (!Py_IsNone(match)) { PyErr_SetHandledException(match); } - #line 3138 "Python/generated_cases.c.h" + #line 3137 "Python/generated_cases.c.h" stack_pointer[-1] = match; stack_pointer[-2] = rest; DISPATCH(); @@ -3147,18 +3146,18 @@ #line 2217 "Python/bytecodes.c" assert(PyExceptionInstance_Check(left)); if (check_except_type_valid(tstate, right) < 0) { - #line 3151 "Python/generated_cases.c.h" + #line 3150 "Python/generated_cases.c.h" Py_DECREF(right); #line 2220 "Python/bytecodes.c" if (true) goto pop_1_error; } int res = PyErr_GivenExceptionMatches(left, right); - #line 3158 "Python/generated_cases.c.h" + #line 3157 "Python/generated_cases.c.h" Py_DECREF(right); #line 2225 "Python/bytecodes.c" b = res ? Py_True : Py_False; - #line 3162 "Python/generated_cases.c.h" + #line 3161 "Python/generated_cases.c.h" stack_pointer[-1] = b; DISPATCH(); } @@ -3170,12 +3169,12 @@ #line 2229 "Python/bytecodes.c" PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_name(tstate, frame, name, fromlist, level); - #line 3174 "Python/generated_cases.c.h" + #line 3173 "Python/generated_cases.c.h" Py_DECREF(level); Py_DECREF(fromlist); #line 2232 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 3179 "Python/generated_cases.c.h" + #line 3178 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -3188,7 +3187,7 @@ PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); res = import_from(tstate, from, name); if (res == NULL) goto error; - #line 3192 "Python/generated_cases.c.h" + #line 3191 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3197,7 +3196,7 @@ TARGET(JUMP_FORWARD) { #line 2242 "Python/bytecodes.c" JUMPBY(oparg); - #line 3201 "Python/generated_cases.c.h" + #line 3200 "Python/generated_cases.c.h" DISPATCH(); } @@ -3221,7 +3220,7 @@ goto resume_frame; } #endif /* ENABLE_SPECIALIZATION */ - #line 3225 "Python/generated_cases.c.h" + #line 3224 "Python/generated_cases.c.h" DISPATCH(); } @@ -3241,7 +3240,7 @@ goto resume_with_error; } goto resume_frame; - #line 3245 "Python/generated_cases.c.h" + #line 3244 "Python/generated_cases.c.h" } TARGET(POP_JUMP_IF_FALSE) { @@ -3249,7 +3248,7 @@ #line 2294 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsFalse(cond)); - #line 3253 "Python/generated_cases.c.h" + #line 3252 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -3259,7 +3258,7 @@ #line 2299 "Python/bytecodes.c" assert(PyBool_Check(cond)); JUMPBY(oparg * Py_IsTrue(cond)); - #line 3263 "Python/generated_cases.c.h" + #line 3262 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -3268,12 +3267,12 @@ PyObject *value = stack_pointer[-1]; #line 2304 "Python/bytecodes.c" if (!Py_IsNone(value)) { - #line 3272 "Python/generated_cases.c.h" + #line 3271 "Python/generated_cases.c.h" Py_DECREF(value); #line 2306 "Python/bytecodes.c" JUMPBY(oparg); } - #line 3277 "Python/generated_cases.c.h" + #line 3276 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -3285,11 +3284,11 @@ JUMPBY(oparg); } else { - #line 3289 "Python/generated_cases.c.h" + #line 3288 "Python/generated_cases.c.h" Py_DECREF(value); #line 2316 "Python/bytecodes.c" } - #line 3293 "Python/generated_cases.c.h" + #line 3292 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -3302,7 +3301,7 @@ * (see bpo-30039). */ JUMPBY(-oparg); - #line 3306 "Python/generated_cases.c.h" + #line 3305 "Python/generated_cases.c.h" DISPATCH(); } @@ -3315,7 +3314,7 @@ if (len_i < 0) goto error; len_o = PyLong_FromSsize_t(len_i); if (len_o == NULL) goto error; - #line 3319 "Python/generated_cases.c.h" + #line 3318 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = len_o; DISPATCH(); @@ -3331,7 +3330,7 @@ // None on failure. assert(PyTuple_CheckExact(names)); attrs = match_class(tstate, subject, type, oparg, names); - #line 3335 "Python/generated_cases.c.h" + #line 3334 "Python/generated_cases.c.h" Py_DECREF(subject); Py_DECREF(type); Py_DECREF(names); @@ -3343,7 +3342,7 @@ if (_PyErr_Occurred(tstate)) goto pop_3_error; attrs = Py_None; // Failure! } - #line 3347 "Python/generated_cases.c.h" + #line 3346 "Python/generated_cases.c.h" STACK_SHRINK(2); stack_pointer[-1] = attrs; DISPATCH(); @@ -3355,7 +3354,7 @@ #line 2352 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING; res = match ? Py_True : Py_False; - #line 3359 "Python/generated_cases.c.h" + #line 3358 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3367,7 +3366,7 @@ #line 2357 "Python/bytecodes.c" int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE; res = match ? Py_True : Py_False; - #line 3371 "Python/generated_cases.c.h" + #line 3370 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3381,7 +3380,7 @@ // On successful match, PUSH(values). Otherwise, PUSH(None). values_or_none = match_keys(tstate, subject, keys); if (values_or_none == NULL) goto error; - #line 3385 "Python/generated_cases.c.h" + #line 3384 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = values_or_none; DISPATCH(); @@ -3393,11 +3392,11 @@ #line 2368 "Python/bytecodes.c" /* before: [obj]; after [getiter(obj)] */ iter = PyObject_GetIter(iterable); - #line 3397 "Python/generated_cases.c.h" + #line 3396 "Python/generated_cases.c.h" Py_DECREF(iterable); #line 2371 "Python/bytecodes.c" if (iter == NULL) goto pop_1_error; - #line 3401 "Python/generated_cases.c.h" + #line 3400 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3428,11 +3427,11 @@ if (iter == NULL) { goto error; } - #line 3432 "Python/generated_cases.c.h" + #line 3431 "Python/generated_cases.c.h" Py_DECREF(iterable); #line 2398 "Python/bytecodes.c" } - #line 3436 "Python/generated_cases.c.h" + #line 3435 "Python/generated_cases.c.h" stack_pointer[-1] = iter; DISPATCH(); } @@ -3474,7 +3473,7 @@ DISPATCH(); } // Common case: no jump, leave it to the code generator - #line 3478 "Python/generated_cases.c.h" + #line 3477 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3508,7 +3507,7 @@ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1; } INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH); - #line 3512 "Python/generated_cases.c.h" + #line 3511 "Python/generated_cases.c.h" DISPATCH(); } @@ -3536,7 +3535,7 @@ DISPATCH(); end_for_iter_list: // Common case: no jump, leave it to the code generator - #line 3540 "Python/generated_cases.c.h" + #line 3539 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3567,7 +3566,7 @@ DISPATCH(); end_for_iter_tuple: // Common case: no jump, leave it to the code generator - #line 3571 "Python/generated_cases.c.h" + #line 3570 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3596,7 +3595,7 @@ if (next == NULL) { goto error; } - #line 3600 "Python/generated_cases.c.h" + #line 3599 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; next_instr += 1; @@ -3621,7 +3620,7 @@ assert(next_instr[oparg].op.code == END_FOR || next_instr[oparg].op.code == INSTRUMENTED_END_FOR); DISPATCH_INLINED(gen_frame); - #line 3625 "Python/generated_cases.c.h" + #line 3624 "Python/generated_cases.c.h" } TARGET(BEFORE_ASYNC_WITH) { @@ -3651,7 +3650,7 @@ Py_DECREF(enter); goto error; } - #line 3655 "Python/generated_cases.c.h" + #line 3654 "Python/generated_cases.c.h" Py_DECREF(mgr); #line 2586 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); @@ -3660,7 +3659,7 @@ Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3664 "Python/generated_cases.c.h" + #line 3663 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3697,7 +3696,7 @@ Py_DECREF(enter); goto error; } - #line 3701 "Python/generated_cases.c.h" + #line 3700 "Python/generated_cases.c.h" Py_DECREF(mgr); #line 2621 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); @@ -3706,7 +3705,7 @@ Py_DECREF(exit); if (true) goto pop_1_error; } - #line 3710 "Python/generated_cases.c.h" + #line 3709 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; stack_pointer[-2] = exit; @@ -3739,7 +3738,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 3743 "Python/generated_cases.c.h" + #line 3742 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; DISPATCH(); @@ -3758,7 +3757,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 3762 "Python/generated_cases.c.h" + #line 3761 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -3789,7 +3788,7 @@ assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR)); res = self; assert(oparg & 1); - #line 3793 "Python/generated_cases.c.h" + #line 3792 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3813,7 +3812,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3817 "Python/generated_cases.c.h" + #line 3816 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3841,7 +3840,7 @@ res2 = Py_NewRef(descr); res = self; assert(oparg & 1); - #line 3845 "Python/generated_cases.c.h" + #line 3844 "Python/generated_cases.c.h" STACK_GROW(((oparg & 1) ? 1 : 0)); stack_pointer[-1] = res; if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; } @@ -3854,7 +3853,7 @@ assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); - #line 3858 "Python/generated_cases.c.h" + #line 3857 "Python/generated_cases.c.h" DISPATCH(); } @@ -3872,7 +3871,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; INCREMENT_ADAPTIVE_COUNTER(cache->counter); GO_TO_INSTRUCTION(CALL); - #line 3876 "Python/generated_cases.c.h" + #line 3875 "Python/generated_cases.c.h" } TARGET(CALL) { @@ -3964,7 +3963,7 @@ Py_DECREF(args[i]); } if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 3968 "Python/generated_cases.c.h" + #line 3967 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -3986,7 +3985,7 @@ PEEK(oparg + 2) = Py_NewRef(meth); // method Py_DECREF(callable); GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS); - #line 3990 "Python/generated_cases.c.h" + #line 3989 "Python/generated_cases.c.h" } TARGET(CALL_PY_EXACT_ARGS) { @@ -4021,7 +4020,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 4025 "Python/generated_cases.c.h" + #line 4024 "Python/generated_cases.c.h" } TARGET(CALL_PY_WITH_DEFAULTS) { @@ -4065,7 +4064,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL); frame->return_offset = 0; DISPATCH_INLINED(new_frame); - #line 4069 "Python/generated_cases.c.h" + #line 4068 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_TYPE_1) { @@ -4083,7 +4082,7 @@ res = Py_NewRef(Py_TYPE(obj)); Py_DECREF(obj); Py_DECREF(&PyType_Type); // I.e., callable - #line 4087 "Python/generated_cases.c.h" + #line 4086 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4107,7 +4106,7 @@ Py_DECREF(arg); Py_DECREF(&PyUnicode_Type); // I.e., callable if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4111 "Python/generated_cases.c.h" + #line 4110 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4132,7 +4131,7 @@ Py_DECREF(arg); Py_DECREF(&PyTuple_Type); // I.e., tuple if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4136 "Python/generated_cases.c.h" + #line 4135 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4196,7 +4195,7 @@ * as it will be checked after start_frame */ tstate->py_recursion_remaining--; goto start_frame; - #line 4200 "Python/generated_cases.c.h" + #line 4199 "Python/generated_cases.c.h" } TARGET(EXIT_INIT_CHECK) { @@ -4209,7 +4208,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 4213 "Python/generated_cases.c.h" + #line 4212 "Python/generated_cases.c.h" STACK_SHRINK(1); DISPATCH(); } @@ -4241,7 +4240,7 @@ } Py_DECREF(tp); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4245 "Python/generated_cases.c.h" + #line 4244 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4283,7 +4282,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4287 "Python/generated_cases.c.h" + #line 4286 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4329,7 +4328,7 @@ 'invalid'). In those cases an exception is set, so we must handle it. */ - #line 4333 "Python/generated_cases.c.h" + #line 4332 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4375,7 +4374,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4379 "Python/generated_cases.c.h" + #line 4378 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4414,7 +4413,7 @@ Py_DECREF(callable); Py_DECREF(arg); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4418 "Python/generated_cases.c.h" + #line 4417 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4454,7 +4453,7 @@ Py_DECREF(cls); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4458 "Python/generated_cases.c.h" + #line 4457 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4484,7 +4483,7 @@ SKIP_OVER(INLINE_CACHE_ENTRIES_CALL + 1); assert(next_instr[-1].op.code == POP_TOP); DISPATCH(); - #line 4488 "Python/generated_cases.c.h" + #line 4487 "Python/generated_cases.c.h" } TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { @@ -4522,7 +4521,7 @@ Py_DECREF(arg); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4526 "Python/generated_cases.c.h" + #line 4525 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4564,7 +4563,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4568 "Python/generated_cases.c.h" + #line 4567 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4606,7 +4605,7 @@ Py_DECREF(self); Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4610 "Python/generated_cases.c.h" + #line 4609 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4647,7 +4646,7 @@ } Py_DECREF(callable); if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } - #line 4651 "Python/generated_cases.c.h" + #line 4650 "Python/generated_cases.c.h" STACK_SHRINK(oparg); STACK_SHRINK(1); stack_pointer[-1] = res; @@ -4659,7 +4658,7 @@ TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { #line 3381 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); - #line 4663 "Python/generated_cases.c.h" + #line 4662 "Python/generated_cases.c.h" } TARGET(CALL_FUNCTION_EX) { @@ -4730,14 +4729,14 @@ } result = PyObject_Call(func, callargs, kwargs); } - #line 4734 "Python/generated_cases.c.h" + #line 4733 "Python/generated_cases.c.h" Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); #line 3447 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } - #line 4741 "Python/generated_cases.c.h" + #line 4740 "Python/generated_cases.c.h" STACK_SHRINK(((oparg & 1) ? 1 : 0)); STACK_SHRINK(2); stack_pointer[-1] = result; @@ -4760,7 +4759,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 4764 "Python/generated_cases.c.h" + #line 4763 "Python/generated_cases.c.h" stack_pointer[-1] = func; DISPATCH(); } @@ -4793,7 +4792,7 @@ default: Py_UNREACHABLE(); } - #line 4797 "Python/generated_cases.c.h" + #line 4796 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; DISPATCH(); @@ -4821,7 +4820,7 @@ frame = cframe.current_frame = prev; _PyFrame_StackPush(frame, (PyObject *)gen); goto resume_frame; - #line 4825 "Python/generated_cases.c.h" + #line 4824 "Python/generated_cases.c.h" } TARGET(BUILD_SLICE) { @@ -4831,13 +4830,13 @@ PyObject *slice; #line 3517 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 4835 "Python/generated_cases.c.h" + #line 4834 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); #line 3519 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 4841 "Python/generated_cases.c.h" + #line 4840 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -4854,7 +4853,7 @@ result = conv_fn(value); Py_DECREF(value); if (result == NULL) goto pop_1_error; - #line 4858 "Python/generated_cases.c.h" + #line 4857 "Python/generated_cases.c.h" stack_pointer[-1] = result; DISPATCH(); } @@ -4873,7 +4872,7 @@ else { res = value; } - #line 4877 "Python/generated_cases.c.h" + #line 4876 "Python/generated_cases.c.h" stack_pointer[-1] = res; DISPATCH(); } @@ -4887,7 +4886,7 @@ Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 4891 "Python/generated_cases.c.h" + #line 4890 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; DISPATCH(); @@ -4899,7 +4898,7 @@ #line 3552 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 4903 "Python/generated_cases.c.h" + #line 4902 "Python/generated_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; DISPATCH(); @@ -4926,12 +4925,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 4930 "Python/generated_cases.c.h" + #line 4929 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); #line 3572 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 4935 "Python/generated_cases.c.h" + #line 4934 "Python/generated_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; next_instr += 1; @@ -4943,7 +4942,7 @@ PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; #line 3577 "Python/bytecodes.c" assert(oparg >= 2); - #line 4947 "Python/generated_cases.c.h" + #line 4946 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; stack_pointer[-(2 + (oparg-2))] = top; DISPATCH(); @@ -4962,13 +4961,13 @@ assert(next_opcode > 0 && next_opcode < 256); opcode = next_opcode; DISPATCH_GOTO(); - #line 4966 "Python/generated_cases.c.h" + #line 4965 "Python/generated_cases.c.h" } TARGET(INSTRUMENTED_JUMP_FORWARD) { #line 3595 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); - #line 4972 "Python/generated_cases.c.h" + #line 4971 "Python/generated_cases.c.h" DISPATCH(); } @@ -4976,7 +4975,7 @@ #line 3599 "Python/bytecodes.c" CHECK_EVAL_BREAKER(); INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); - #line 4980 "Python/generated_cases.c.h" + #line 4979 "Python/generated_cases.c.h" DISPATCH(); } @@ -4987,7 +4986,7 @@ _Py_CODEUNIT *here = next_instr - 1; int offset = Py_IsTrue(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 4991 "Python/generated_cases.c.h" + #line 4990 "Python/generated_cases.c.h" DISPATCH(); } @@ -4998,7 +4997,7 @@ _Py_CODEUNIT *here = next_instr - 1; int offset = Py_IsFalse(cond) * oparg; INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5002 "Python/generated_cases.c.h" + #line 5001 "Python/generated_cases.c.h" DISPATCH(); } @@ -5015,7 +5014,7 @@ offset = 0; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5019 "Python/generated_cases.c.h" + #line 5018 "Python/generated_cases.c.h" DISPATCH(); } @@ -5032,7 +5031,7 @@ offset = oparg; } INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH); - #line 5036 "Python/generated_cases.c.h" + #line 5035 "Python/generated_cases.c.h" DISPATCH(); } @@ -5043,19 +5042,19 @@ oparg = oparg << 8 | next_instr->op.arg; PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); - #line 5047 "Python/generated_cases.c.h" + #line 5046 "Python/generated_cases.c.h" } TARGET(CACHE) { #line 3656 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); - #line 5054 "Python/generated_cases.c.h" + #line 5053 "Python/generated_cases.c.h" } TARGET(RESERVED) { #line 3661 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); - #line 5061 "Python/generated_cases.c.h" + #line 5060 "Python/generated_cases.c.h" } diff --git a/Python/specialize.c b/Python/specialize.c index 312fada24ca0f3..94ee3cb56cbc76 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -674,6 +674,8 @@ specialize_dict_access( PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); if (_PyDictOrValues_IsValues(dorv)) { // Virtual dictionary + unmaterializing: + ; // Load-bearing semicolon; don't touch! PyDictKeysObject *keys = ((PyHeapTypeObject *)type)->ht_cached_keys; assert(PyUnicode_CheckExact(name)); Py_ssize_t index = _PyDictKeys_StringLookup(keys, name); @@ -696,6 +698,16 @@ specialize_dict_access( return 0; } // We found an instance with a __dict__. + if (dict->ma_values) { + if (base_op == LOAD_ATTR && + Py_REFCNT(dict) == 1 && + dict->ma_keys == ((PyHeapTypeObject *)type)->ht_cached_keys) + { + goto unmaterializing; + } + SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_NON_STRING_OR_SPLIT); + return 0; + } Py_ssize_t index = _PyDict_LookupIndex(dict, name); if (index != (uint16_t)index) { From 5d76456f0e7c124512a1bb2442fba560e61f8035 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 7 Jul 2023 15:50:20 -0700 Subject: [PATCH 06/13] Fix test_opcache --- Lib/test/test_opcache.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py index 7d95abb5a65fd5..7d317c012a304e 100644 --- a/Lib/test/test_opcache.py +++ b/Lib/test/test_opcache.py @@ -864,20 +864,21 @@ class C: items = [] for _ in range(self.ITEMS): - o = C() - o.a = None - # Need to keep a __dict__ reference so it isn't un-materialized: - item = o, o.__dict__ + item = C() + item.a = None + # Resize into a combined unicode dict: + for i in range(29): + setattr(item, f"_{i}", None) items.append(item) return items def read(items): for item in items: - item[0].a + item.a def write(items): for item in items: - item[1][None] = None + item.__dict__[None] = None opname = "LOAD_ATTR_WITH_HINT" self.assert_races_do_not_crash(opname, get_items, read, write) @@ -933,7 +934,9 @@ class C: items = [] for _ in range(self.ITEMS): item = C() - item.__dict__ + # Resize into a combined unicode dict: + for i in range(29): + setattr(item, f"_{i}", None) items.append(item) return items From d00eefeccf9f901cc0faa20459b434e48b318300 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 7 Jul 2023 16:35:31 -0700 Subject: [PATCH 07/13] Clean up the diff --- Python/bytecodes.c | 6 +++--- Python/generated_cases.c.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 4325228eb1459d..d50bf711618c41 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1920,9 +1920,9 @@ dummy_func( 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); + 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(FRAME_CO_NAMES, oparg>>1); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index f00f89f67c4e52..0ee6031cc1360f 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2708,9 +2708,9 @@ 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); + 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(FRAME_CO_NAMES, oparg>>1); From 222469a61ec3a28fd100792c9e4f9b83339c0e26 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 14 Jul 2023 17:45:49 -0700 Subject: [PATCH 08/13] "Dematerialize" in other places too --- Include/internal/pycore_dict.h | 2 ++ Include/pystats.h | 2 +- Objects/dictobject.c | 29 +++++++++++++++++++++++++++ Python/bytecodes.c | 36 +++++++++++----------------------- Python/executor_cases.c.h | 24 +++-------------------- Python/generated_cases.c.h | 36 +++++++++++----------------------- Python/specialize.c | 24 ++++++++++------------- 7 files changed, 67 insertions(+), 86 deletions(-) diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h index 90be253f12edab..29079ccc7ce155 100644 --- a/Include/internal/pycore_dict.h +++ b/Include/internal/pycore_dict.h @@ -10,6 +10,7 @@ extern "C" { #endif #include "pycore_dict_state.h" +#include "pycore_object.h" #include "pycore_runtime.h" // _PyRuntime @@ -178,6 +179,7 @@ _PyDict_NotifyEvent(PyInterpreterState *interp, } extern PyObject *_PyObject_MakeDictFromInstanceAttributes(PyObject *obj, PyDictValues *values); +extern int _PyObject_MakeInstanceAttributesFromDict(PyObject *obj, PyDictOrValues *dorv); extern PyObject *_PyDict_FromItems( PyObject *const *keys, Py_ssize_t keys_offset, PyObject *const *values, Py_ssize_t values_offset, diff --git a/Include/pystats.h b/Include/pystats.h index 73fd4f3463f3fb..a4fb15ccc7fad3 100644 --- a/Include/pystats.h +++ b/Include/pystats.h @@ -65,7 +65,7 @@ typedef struct _object_stats { uint64_t dict_materialized_new_key; uint64_t dict_materialized_too_big; uint64_t dict_materialized_str_subclass; - uint64_t dict_unmaterialized; + uint64_t dict_dematerialized; uint64_t type_cache_hits; uint64_t type_cache_misses; uint64_t type_cache_dunder_hits; diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 013c21884032aa..ff82ce96133134 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -5418,6 +5418,35 @@ _PyObject_MakeDictFromInstanceAttributes(PyObject *obj, PyDictValues *values) return make_dict_from_instance_attributes(interp, keys, values); } +// Return 1 if the dict was dematerialized, 0 otherwise. +int +_PyObject_MakeInstanceAttributesFromDict(PyObject *obj, PyDictOrValues *dorv) +{ + assert(_PyObject_DictOrValuesPointer(obj) == dorv); + assert(!_PyDictOrValues_IsValues(*dorv)); + PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(*dorv); + if (dict == NULL) { + return 0; + } + // It's likely that this dict still shares its keys (if it was materialized + // on request and not heavily modified): + assert(PyDict_CheckExact(dict)); + assert(_PyType_HasFeature(Py_TYPE(obj), Py_TPFLAGS_HEAPTYPE)); + if (dict->ma_keys != CACHED_KEYS(Py_TYPE(obj)) || Py_REFCNT(dict) != 1) { + return 0; + } + assert(dict->ma_values); + // We have an opportunity to do something *really* cool: dematerialize it! + _PyDictKeys_DecRef(dict->ma_keys); + _PyDictOrValues_SetValues(dorv, dict->ma_values); + OBJECT_STAT_INC(dict_dematerialized); + // Don't try this at home, kids: + dict->ma_keys = NULL; + dict->ma_values = NULL; + Py_DECREF(dict); + return 1; +} + int _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values, PyObject *name, PyObject *value) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 913bc93409cada..c5170cbbac816c 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1828,27 +1828,9 @@ dummy_func( assert(Py_TYPE(owner)->tp_dictoffset < 0); assert(Py_TYPE(owner)->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner); - if (!_PyDictOrValues_IsValues(*dorv)) { - PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(*dorv); - // It's likely that this __dict__ still shares its keys (if it - // was materialized on request and not heavily modified): - assert(dict); - assert(PyDict_CheckExact(dict)); - assert(_PyType_HasFeature(Py_TYPE(owner), Py_TPFLAGS_HEAPTYPE)); - PyHeapTypeObject *ht = (PyHeapTypeObject *)Py_TYPE(owner); - DEOPT_IF(dict->ma_keys != ht->ht_cached_keys, LOAD_ATTR); - assert(dict->ma_values); - DEOPT_IF(Py_REFCNT(dict) != 1, LOAD_ATTR); - // We have an opportunity to do something *really* cool: - // un-materialize it! - _PyDictKeys_DecRef(dict->ma_keys); - _PyDictOrValues_SetValues(dorv, dict->ma_values); - OBJECT_STAT_INC(dict_unmaterialized); - // Don't try this at home, kids: - dict->ma_keys = NULL; - dict->ma_values = NULL; - Py_DECREF(dict); - } + DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && + !_PyObject_MakeInstanceAttributesFromDict(owner, dorv), + LOAD_ATTR); } op(_LOAD_ATTR_INSTANCE_VALUE, (index/1, unused/5, owner -- res2 if (oparg & 1), res)) { @@ -2728,8 +2710,10 @@ dummy_func( 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); + PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(self); + DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && + !_PyObject_MakeInstanceAttributesFromDict(self, dorv), + LOAD_ATTR); PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls; DEOPT_IF(self_heap_type->ht_cached_keys->dk_version != keys_version, LOAD_ATTR); @@ -2758,8 +2742,10 @@ dummy_func( 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); + PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(self); + DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && + !_PyObject_MakeInstanceAttributesFromDict(self, dorv), + LOAD_ATTR); PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls; DEOPT_IF(self_heap_type->ht_cached_keys->dk_version != keys_version, LOAD_ATTR); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 9e13df2a903e90..10b373c64182d1 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1439,27 +1439,9 @@ assert(Py_TYPE(owner)->tp_dictoffset < 0); assert(Py_TYPE(owner)->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner); - if (!_PyDictOrValues_IsValues(*dorv)) { - PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(*dorv); - // It's likely that this __dict__ still shares its keys (if it - // was materialized on request and not heavily modified): - assert(dict); - assert(PyDict_CheckExact(dict)); - assert(_PyType_HasFeature(Py_TYPE(owner), Py_TPFLAGS_HEAPTYPE)); - PyHeapTypeObject *ht = (PyHeapTypeObject *)Py_TYPE(owner); - DEOPT_IF(dict->ma_keys != ht->ht_cached_keys, LOAD_ATTR); - assert(dict->ma_values); - DEOPT_IF(Py_REFCNT(dict) != 1, LOAD_ATTR); - // We have an opportunity to do something *really* cool: - // un-materialize it! - _PyDictKeys_DecRef(dict->ma_keys); - _PyDictOrValues_SetValues(dorv, dict->ma_values); - OBJECT_STAT_INC(dict_unmaterialized); - // Don't try this at home, kids: - dict->ma_keys = NULL; - dict->ma_values = NULL; - Py_DECREF(dict); - } + DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && + !_PyObject_MakeInstanceAttributesFromDict(owner, dorv), + LOAD_ATTR); break; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 81333381d5fca5..aee5a4892e6588 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2257,27 +2257,9 @@ assert(Py_TYPE(owner)->tp_dictoffset < 0); assert(Py_TYPE(owner)->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner); - if (!_PyDictOrValues_IsValues(*dorv)) { - PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(*dorv); - // It's likely that this __dict__ still shares its keys (if it - // was materialized on request and not heavily modified): - assert(dict); - assert(PyDict_CheckExact(dict)); - assert(_PyType_HasFeature(Py_TYPE(owner), Py_TPFLAGS_HEAPTYPE)); - PyHeapTypeObject *ht = (PyHeapTypeObject *)Py_TYPE(owner); - DEOPT_IF(dict->ma_keys != ht->ht_cached_keys, LOAD_ATTR); - assert(dict->ma_values); - DEOPT_IF(Py_REFCNT(dict) != 1, LOAD_ATTR); - // We have an opportunity to do something *really* cool: - // un-materialize it! - _PyDictKeys_DecRef(dict->ma_keys); - _PyDictOrValues_SetValues(dorv, dict->ma_values); - OBJECT_STAT_INC(dict_unmaterialized); - // Don't try this at home, kids: - dict->ma_keys = NULL; - dict->ma_values = NULL; - Py_DECREF(dict); - } + DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && + !_PyObject_MakeInstanceAttributesFromDict(owner, dorv), + LOAD_ATTR); _tmp_2 = owner; } { @@ -3370,8 +3352,10 @@ 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); + PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(self); + DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && + !_PyObject_MakeInstanceAttributesFromDict(self, dorv), + LOAD_ATTR); PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls; DEOPT_IF(self_heap_type->ht_cached_keys->dk_version != keys_version, LOAD_ATTR); @@ -3421,8 +3405,10 @@ 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); + PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(self); + DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && + !_PyObject_MakeInstanceAttributesFromDict(self, dorv), + LOAD_ATTR); PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls; DEOPT_IF(self_heap_type->ht_cached_keys->dk_version != keys_version, LOAD_ATTR); diff --git a/Python/specialize.c b/Python/specialize.c index 31050ea83e74bc..6fcca09057aa86 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -191,7 +191,7 @@ print_object_stats(FILE *out, ObjectStats *stats) fprintf(out, "Object materialize dict (new key): %" PRIu64 "\n", stats->dict_materialized_new_key); fprintf(out, "Object materialize dict (too big): %" PRIu64 "\n", stats->dict_materialized_too_big); fprintf(out, "Object materialize dict (str subclass): %" PRIu64 "\n", stats->dict_materialized_str_subclass); - fprintf(out, "Object un-materialize dict: %" PRIu64 "\n", stats->dict_unmaterialized); + fprintf(out, "Object un-materialize dict: %" PRIu64 "\n", stats->dict_dematerialized); fprintf(out, "Object method cache hits: %" PRIu64 "\n", stats->type_cache_hits); fprintf(out, "Object method cache misses: %" PRIu64 "\n", stats->type_cache_misses); fprintf(out, "Object method cache collisions: %" PRIu64 "\n", stats->type_cache_collisions); @@ -671,11 +671,11 @@ specialize_dict_access( return 0; } _PyAttrCache *cache = (_PyAttrCache *)(instr + 1); - PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); - if (_PyDictOrValues_IsValues(dorv)) { + PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner); + if (_PyDictOrValues_IsValues(*dorv) || + _PyObject_MakeInstanceAttributesFromDict(owner, dorv)) + { // Virtual dictionary - unmaterializing: - ; // Load-bearing semicolon; don't touch! PyDictKeysObject *keys = ((PyHeapTypeObject *)type)->ht_cached_keys; assert(PyUnicode_CheckExact(name)); Py_ssize_t index = _PyDictKeys_StringLookup(keys, name); @@ -692,19 +692,13 @@ specialize_dict_access( instr->op.code = values_op; } else { - PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(dorv); + PyDictObject *dict = (PyDictObject *)_PyDictOrValues_GetDict(*dorv); if (dict == NULL || !PyDict_CheckExact(dict)) { SPECIALIZATION_FAIL(base_op, SPEC_FAIL_NO_DICT); return 0; } // We found an instance with a __dict__. if (dict->ma_values) { - if (base_op == LOAD_ATTR && - Py_REFCNT(dict) == 1 && - dict->ma_keys == ((PyHeapTypeObject *)type)->ht_cached_keys) - { - goto unmaterializing; - } SPECIALIZATION_FAIL(base_op, SPEC_FAIL_ATTR_NON_STRING_OR_SPLIT); return 0; } @@ -1090,9 +1084,11 @@ PyObject *descr, DescriptorClassification kind, bool is_method) assert(descr != NULL); assert((is_method && kind == METHOD) || (!is_method && kind == NON_DESCRIPTOR)); if (owner_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT) { - PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(owner); + PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner); PyDictKeysObject *keys = ((PyHeapTypeObject *)owner_cls)->ht_cached_keys; - if (!_PyDictOrValues_IsValues(dorv)) { + if (!_PyDictOrValues_IsValues(*dorv) && + !_PyObject_MakeInstanceAttributesFromDict(owner, dorv)) + { SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_HAS_MANAGED_DICT); return 0; } From fe19772a1cccaced81456f3e0706a623c57667d0 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sun, 16 Jul 2023 07:36:01 -0700 Subject: [PATCH 09/13] Fix whitespace --- Python/bytecodes.c | 12 ++++++------ Python/specialize.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 954d637d2e5f8c..8b5b32dd3590ce 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1828,8 +1828,8 @@ dummy_func( assert(Py_TYPE(owner)->tp_dictoffset < 0); assert(Py_TYPE(owner)->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner); - DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && - !_PyObject_MakeInstanceAttributesFromDict(owner, dorv), + DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && + !_PyObject_MakeInstanceAttributesFromDict(owner, dorv), LOAD_ATTR); } @@ -2721,8 +2721,8 @@ dummy_func( 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) && - !_PyObject_MakeInstanceAttributesFromDict(self, dorv), + DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && + !_PyObject_MakeInstanceAttributesFromDict(self, dorv), LOAD_ATTR); PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls; DEOPT_IF(self_heap_type->ht_cached_keys->dk_version != @@ -2753,8 +2753,8 @@ dummy_func( 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) && - !_PyObject_MakeInstanceAttributesFromDict(self, dorv), + DEOPT_IF(!_PyDictOrValues_IsValues(*dorv) && + !_PyObject_MakeInstanceAttributesFromDict(self, dorv), LOAD_ATTR); PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls; DEOPT_IF(self_heap_type->ht_cached_keys->dk_version != diff --git a/Python/specialize.c b/Python/specialize.c index 6fcca09057aa86..11cc1ce1a83279 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -672,7 +672,7 @@ specialize_dict_access( } _PyAttrCache *cache = (_PyAttrCache *)(instr + 1); PyDictOrValues *dorv = _PyObject_DictOrValuesPointer(owner); - if (_PyDictOrValues_IsValues(*dorv) || + if (_PyDictOrValues_IsValues(*dorv) || _PyObject_MakeInstanceAttributesFromDict(owner, dorv)) { // Virtual dictionary From 7f4fd05dc3a6a32b048862009f2d1ab13c60eaa3 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sun, 16 Jul 2023 07:40:37 -0700 Subject: [PATCH 10/13] fixup --- Python/specialize.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/specialize.c b/Python/specialize.c index 11cc1ce1a83279..7337d73764041a 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -191,7 +191,7 @@ print_object_stats(FILE *out, ObjectStats *stats) fprintf(out, "Object materialize dict (new key): %" PRIu64 "\n", stats->dict_materialized_new_key); fprintf(out, "Object materialize dict (too big): %" PRIu64 "\n", stats->dict_materialized_too_big); fprintf(out, "Object materialize dict (str subclass): %" PRIu64 "\n", stats->dict_materialized_str_subclass); - fprintf(out, "Object un-materialize dict: %" PRIu64 "\n", stats->dict_dematerialized); + fprintf(out, "Object dematerialize dict: %" PRIu64 "\n", stats->dict_dematerialized); fprintf(out, "Object method cache hits: %" PRIu64 "\n", stats->type_cache_hits); fprintf(out, "Object method cache misses: %" PRIu64 "\n", stats->type_cache_misses); fprintf(out, "Object method cache collisions: %" PRIu64 "\n", stats->type_cache_collisions); From 25202d9a088019512eda556a1ab93b114b4f0ae1 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sun, 16 Jul 2023 07:55:41 -0700 Subject: [PATCH 11/13] blurb add --- .../2023-07-16-07-55-19.gh-issue-106485.wPb1bH.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-07-16-07-55-19.gh-issue-106485.wPb1bH.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-07-16-07-55-19.gh-issue-106485.wPb1bH.rst b/Misc/NEWS.d/next/Core and Builtins/2023-07-16-07-55-19.gh-issue-106485.wPb1bH.rst new file mode 100644 index 00000000000000..1f80082821edac --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-07-16-07-55-19.gh-issue-106485.wPb1bH.rst @@ -0,0 +1,2 @@ +Reduce the number of materialized instances dictionaries by dematerializing +them when possible. From 125a15b909e63ec3d66d0f672cdd4124e7178a82 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 5 Aug 2023 00:07:16 -0700 Subject: [PATCH 12/13] Add missing stat inc --- Objects/dictobject.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index c64d5c7fdab74b..947a5d34470612 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -5717,6 +5717,7 @@ PyObject_GenericGetDict(PyObject *obj, void *context) dict = _PyDictOrValues_GetDict(*dorv_ptr); if (dict == NULL) { dictkeys_incref(CACHED_KEYS(tp)); + OBJECT_STAT_INC(dict_materialized_on_request); dict = new_dict_with_shared_keys(interp, CACHED_KEYS(tp)); dorv_ptr->dict = dict; } From d42d2e612af5d993204a769de9aa2674b83eea5b Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 5 Aug 2023 12:05:53 -0700 Subject: [PATCH 13/13] Add another missing increment --- Objects/dictobject.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 947a5d34470612..931103cdc1a064 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -5761,6 +5761,9 @@ _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr, dict = *dictptr; if (dict == NULL) { dictkeys_incref(cached); + if (_PyType_HasFeature(tp, Py_TPFLAGS_MANAGED_DICT)) { + OBJECT_STAT_INC(dict_materialized_on_request); + } dict = new_dict_with_shared_keys(interp, cached); if (dict == NULL) return -1;