From 002b033378f7b1550db6434f9184fa0f6fd46fea Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 11 Jul 2023 16:10:13 -0700 Subject: [PATCH] Tier 2 translation, with test This was remarkably straightforward --- Lib/test/test_capi/test_misc.py | 25 ++++++- Python/bytecodes.c | 7 ++ Python/executor_cases.c.h | 73 +++++++++++-------- Python/generated_cases.c.h | 124 ++++++++++++++++---------------- Python/opcode_metadata.h | 6 +- Python/optimizer.c | 22 ++++++ 6 files changed, 160 insertions(+), 97 deletions(-) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 9c14a501875b6dc..abdf7ed89763501 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2443,7 +2443,6 @@ def testfunc(x): i += 1 opt = _testinternalcapi.get_uop_optimizer() - with temporary_optimizer(opt): testfunc(1000) @@ -2580,13 +2579,33 @@ def testfunc(n): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) - # for i, (opname, oparg) in enumerate(ex): - # print(f"{i:4d}: {opname:<20s} {oparg:4d}") uops = {opname for opname, _ in ex} # Since there is no JUMP_FORWARD instruction, # look for indirect evidence: the += operator self.assertIn("_BINARY_OP_ADD_INT", uops) + def test_for_iter_range(self): + def testfunc(n): + total = 0 + for i in range(n): + total += i + return total + # import dis; dis.dis(testfunc) + + opt = _testinternalcapi.get_uop_optimizer() + with temporary_optimizer(opt): + total = testfunc(10) + self.assertEqual(total, 45) + + ex = get_first_executor(testfunc) + self.assertIsNotNone(ex) + # for i, (opname, oparg) in enumerate(ex): + # print(f"{i:4d}: {opname:<20s} {oparg:3d}") + uops = {opname for opname, _ in ex} + self.assertIn("_ITER_EXHAUSTED_RANGE", uops) + # Verification that the jump goes past END_FOR + # is done by manual inspection of the output + if __name__ == "__main__": unittest.main() diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 74e2f284de49f42..b931df6cb81c564 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2450,6 +2450,13 @@ dummy_func( } } + // Only used by Tier 2 + op(_ITER_EXHAUSTED_RANGE, (iter -- iter, exhausted)) { + _PyRangeIterObject *r = (_PyRangeIterObject *)iter; + assert(Py_TYPE(r) == &PyRangeIter_Type); + exhausted = r->len <= 0 ? Py_True : Py_False; + } + op(_ITER_NEXT_RANGE, (iter -- iter, next)) { _PyRangeIterObject *r = (_PyRangeIterObject *)iter; assert(Py_TYPE(r) == &PyRangeIter_Type); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 1fff8414322cf8c..e82f64e9ea437c9 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1989,10 +1989,23 @@ break; } + case _ITER_EXHAUSTED_RANGE: { + PyObject *iter = stack_pointer[-1]; + PyObject *exhausted; + #line 2455 "Python/bytecodes.c" + _PyRangeIterObject *r = (_PyRangeIterObject *)iter; + assert(Py_TYPE(r) == &PyRangeIter_Type); + exhausted = r->len <= 0 ? Py_True : Py_False; + #line 2000 "Python/executor_cases.c.h" + STACK_GROW(1); + stack_pointer[-1] = exhausted; + break; + } + case _ITER_NEXT_RANGE: { PyObject *iter = stack_pointer[-1]; PyObject *next; - #line 2454 "Python/bytecodes.c" + #line 2461 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; assert(Py_TYPE(r) == &PyRangeIter_Type); assert(r->len > 0); @@ -2001,7 +2014,7 @@ r->len--; next = PyLong_FromLong(value); if (next == NULL) goto error; - #line 2005 "Python/executor_cases.c.h" + #line 2018 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = next; break; @@ -2012,7 +2025,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2553 "Python/bytecodes.c" + #line 2560 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -2033,7 +2046,7 @@ res = PyObject_Vectorcall(exit_func, stack + 1, 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); if (res == NULL) goto error; - #line 2037 "Python/executor_cases.c.h" + #line 2050 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = res; break; @@ -2042,7 +2055,7 @@ case PUSH_EXC_INFO: { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2592 "Python/bytecodes.c" + #line 2599 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -2052,7 +2065,7 @@ } assert(PyExceptionInstance_Check(new_exc)); exc_info->exc_value = Py_NewRef(new_exc); - #line 2056 "Python/executor_cases.c.h" + #line 2069 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = new_exc; stack_pointer[-2] = prev_exc; @@ -2061,7 +2074,7 @@ case EXIT_INIT_CHECK: { PyObject *should_be_none = stack_pointer[-1]; - #line 2991 "Python/bytecodes.c" + #line 2998 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -2069,7 +2082,7 @@ Py_TYPE(should_be_none)->tp_name); goto error; } - #line 2073 "Python/executor_cases.c.h" + #line 2086 "Python/executor_cases.c.h" STACK_SHRINK(1); break; } @@ -2077,7 +2090,7 @@ case MAKE_FUNCTION: { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3405 "Python/bytecodes.c" + #line 3412 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -2089,7 +2102,7 @@ func_obj->func_version = ((PyCodeObject *)codeobj)->co_version; func = (PyObject *)func_obj; - #line 2093 "Python/executor_cases.c.h" + #line 2106 "Python/executor_cases.c.h" stack_pointer[-1] = func; break; } @@ -2097,7 +2110,7 @@ case SET_FUNCTION_ATTRIBUTE: { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3419 "Python/bytecodes.c" + #line 3426 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -2122,7 +2135,7 @@ default: Py_UNREACHABLE(); } - #line 2126 "Python/executor_cases.c.h" + #line 2139 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = func; break; @@ -2133,15 +2146,15 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3469 "Python/bytecodes.c" + #line 3476 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); - #line 2139 "Python/executor_cases.c.h" + #line 2152 "Python/executor_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3471 "Python/bytecodes.c" + #line 3478 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } - #line 2145 "Python/executor_cases.c.h" + #line 2158 "Python/executor_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); STACK_SHRINK(1); stack_pointer[-1] = slice; @@ -2151,14 +2164,14 @@ case CONVERT_VALUE: { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3475 "Python/bytecodes.c" + #line 3482 "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 2162 "Python/executor_cases.c.h" + #line 2175 "Python/executor_cases.c.h" stack_pointer[-1] = result; break; } @@ -2166,7 +2179,7 @@ case FORMAT_SIMPLE: { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3484 "Python/bytecodes.c" + #line 3491 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -2177,7 +2190,7 @@ else { res = value; } - #line 2181 "Python/executor_cases.c.h" + #line 2194 "Python/executor_cases.c.h" stack_pointer[-1] = res; break; } @@ -2186,12 +2199,12 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3497 "Python/bytecodes.c" + #line 3504 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); if (res == NULL) goto pop_2_error; - #line 2195 "Python/executor_cases.c.h" + #line 2208 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -2200,10 +2213,10 @@ case COPY: { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3504 "Python/bytecodes.c" + #line 3511 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); - #line 2207 "Python/executor_cases.c.h" + #line 2220 "Python/executor_cases.c.h" STACK_GROW(1); stack_pointer[-1] = top; break; @@ -2214,7 +2227,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3509 "Python/bytecodes.c" + #line 3516 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -2229,12 +2242,12 @@ assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops)); assert(binary_ops[oparg]); res = binary_ops[oparg](lhs, rhs); - #line 2233 "Python/executor_cases.c.h" + #line 2246 "Python/executor_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3524 "Python/bytecodes.c" + #line 3531 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; - #line 2238 "Python/executor_cases.c.h" + #line 2251 "Python/executor_cases.c.h" STACK_SHRINK(1); stack_pointer[-1] = res; break; @@ -2243,9 +2256,9 @@ case SWAP: { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3529 "Python/bytecodes.c" + #line 3536 "Python/bytecodes.c" assert(oparg >= 2); - #line 2249 "Python/executor_cases.c.h" + #line 2262 "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 a39ee1bb138b6ab..ad75e0f6346a46e 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3513,7 +3513,7 @@ { PyObject *iter = _tmp_2; PyObject *next; - #line 2454 "Python/bytecodes.c" + #line 2461 "Python/bytecodes.c" _PyRangeIterObject *r = (_PyRangeIterObject *)iter; assert(Py_TYPE(r) == &PyRangeIter_Type); assert(r->len > 0); @@ -3535,7 +3535,7 @@ TARGET(FOR_ITER_GEN) { PyObject *iter = stack_pointer[-1]; - #line 2468 "Python/bytecodes.c" + #line 2475 "Python/bytecodes.c" DEOPT_IF(tstate->interp->eval_frame, FOR_ITER); PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); @@ -3558,7 +3558,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2486 "Python/bytecodes.c" + #line 2493 "Python/bytecodes.c" PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__)); if (enter == NULL) { if (!_PyErr_Occurred(tstate)) { @@ -3583,7 +3583,7 @@ } #line 3585 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2509 "Python/bytecodes.c" + #line 2516 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { @@ -3601,7 +3601,7 @@ PyObject *mgr = stack_pointer[-1]; PyObject *exit; PyObject *res; - #line 2518 "Python/bytecodes.c" + #line 2525 "Python/bytecodes.c" /* pop the context manager, push its __exit__ and the * value returned from calling its __enter__ */ @@ -3629,7 +3629,7 @@ } #line 3631 "Python/generated_cases.c.h" Py_DECREF(mgr); - #line 2544 "Python/bytecodes.c" + #line 2551 "Python/bytecodes.c" res = _PyObject_CallNoArgs(enter); Py_DECREF(enter); if (res == NULL) { @@ -3648,7 +3648,7 @@ PyObject *lasti = stack_pointer[-3]; PyObject *exit_func = stack_pointer[-4]; PyObject *res; - #line 2553 "Python/bytecodes.c" + #line 2560 "Python/bytecodes.c" /* At the top of the stack are 4 values: - val: TOP = exc_info() - unused: SECOND = previous exception @@ -3678,7 +3678,7 @@ TARGET(PUSH_EXC_INFO) { PyObject *new_exc = stack_pointer[-1]; PyObject *prev_exc; - #line 2592 "Python/bytecodes.c" + #line 2599 "Python/bytecodes.c" _PyErr_StackItem *exc_info = tstate->exc_info; if (exc_info->exc_value != NULL) { prev_exc = exc_info->exc_value; @@ -3702,7 +3702,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 2604 "Python/bytecodes.c" + #line 2611 "Python/bytecodes.c" assert(oparg & 1); /* Cached method object */ PyTypeObject *self_cls = Py_TYPE(self); @@ -3733,7 +3733,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2623 "Python/bytecodes.c" + #line 2630 "Python/bytecodes.c" assert(oparg & 1); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3758,7 +3758,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 2635 "Python/bytecodes.c" + #line 2642 "Python/bytecodes.c" assert((oparg & 1) == 0); PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3773,7 +3773,7 @@ assert(descr != NULL); #line 3775 "Python/generated_cases.c.h" Py_DECREF(self); - #line 2648 "Python/bytecodes.c" + #line 2655 "Python/bytecodes.c" res = Py_NewRef(descr); #line 3779 "Python/generated_cases.c.h" STACK_GROW((0 ? 1 : 0)); @@ -3789,7 +3789,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2652 "Python/bytecodes.c" + #line 2659 "Python/bytecodes.c" assert((oparg & 1) == 0); PyTypeObject *self_cls = Py_TYPE(self); assert(type_version != 0); @@ -3799,7 +3799,7 @@ assert(descr != NULL); #line 3801 "Python/generated_cases.c.h" Py_DECREF(self); - #line 2660 "Python/bytecodes.c" + #line 2667 "Python/bytecodes.c" res = Py_NewRef(descr); #line 3805 "Python/generated_cases.c.h" STACK_GROW((0 ? 1 : 0)); @@ -3815,7 +3815,7 @@ PyObject *res; uint32_t type_version = read_u32(&next_instr[1].cache); PyObject *descr = read_obj(&next_instr[5].cache); - #line 2664 "Python/bytecodes.c" + #line 2671 "Python/bytecodes.c" assert(oparg & 1); PyTypeObject *self_cls = Py_TYPE(self); DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR); @@ -3838,7 +3838,7 @@ } TARGET(KW_NAMES) { - #line 2680 "Python/bytecodes.c" + #line 2687 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); kwnames = GETITEM(FRAME_CO_CONSTS, oparg); @@ -3847,7 +3847,7 @@ } TARGET(INSTRUMENTED_CALL) { - #line 2686 "Python/bytecodes.c" + #line 2693 "Python/bytecodes.c" int is_meth = PEEK(oparg+2) != NULL; int total_args = oparg + is_meth; PyObject *function = PEEK(total_args + 1); @@ -3870,7 +3870,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2732 "Python/bytecodes.c" + #line 2739 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -3964,7 +3964,7 @@ TARGET(CALL_BOUND_METHOD_EXACT_ARGS) { PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 2820 "Python/bytecodes.c" + #line 2827 "Python/bytecodes.c" DEOPT_IF(method != NULL, CALL); DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL); STAT_INC(CALL, hit); @@ -3983,7 +3983,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2832 "Python/bytecodes.c" + #line 2839 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -4017,7 +4017,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; uint32_t func_version = read_u32(&next_instr[1].cache); - #line 2860 "Python/bytecodes.c" + #line 2867 "Python/bytecodes.c" assert(kwnames == NULL); DEOPT_IF(tstate->interp->eval_frame, CALL); int is_meth = method != NULL; @@ -4061,7 +4061,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2898 "Python/bytecodes.c" + #line 2905 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4084,7 +4084,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2910 "Python/bytecodes.c" + #line 2917 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4109,7 +4109,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 2924 "Python/bytecodes.c" + #line 2931 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); @@ -4133,7 +4133,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *null = stack_pointer[-(2 + oparg)]; - #line 2938 "Python/bytecodes.c" + #line 2945 "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__``) @@ -4189,7 +4189,7 @@ TARGET(EXIT_INIT_CHECK) { PyObject *should_be_none = stack_pointer[-1]; - #line 2991 "Python/bytecodes.c" + #line 2998 "Python/bytecodes.c" assert(STACK_LEVEL() == 2); if (should_be_none != Py_None) { PyErr_Format(PyExc_TypeError, @@ -4207,7 +4207,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3001 "Python/bytecodes.c" + #line 3008 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4243,7 +4243,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3026 "Python/bytecodes.c" + #line 3033 "Python/bytecodes.c" /* Builtin METH_O functions */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4285,7 +4285,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3057 "Python/bytecodes.c" + #line 3064 "Python/bytecodes.c" /* Builtin METH_FASTCALL functions, without keywords */ assert(kwnames == NULL); int is_meth = method != NULL; @@ -4331,7 +4331,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3092 "Python/bytecodes.c" + #line 3099 "Python/bytecodes.c" /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ int is_meth = method != NULL; int total_args = oparg; @@ -4377,7 +4377,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3127 "Python/bytecodes.c" + #line 3134 "Python/bytecodes.c" assert(kwnames == NULL); /* len(o) */ int is_meth = method != NULL; @@ -4415,7 +4415,7 @@ PyObject *callable = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3154 "Python/bytecodes.c" + #line 3161 "Python/bytecodes.c" assert(kwnames == NULL); /* isinstance(o, o2) */ int is_meth = method != NULL; @@ -4454,7 +4454,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *self = stack_pointer[-(1 + oparg)]; PyObject *method = stack_pointer[-(2 + oparg)]; - #line 3184 "Python/bytecodes.c" + #line 3191 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 1); assert(method != NULL); @@ -4479,7 +4479,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3204 "Python/bytecodes.c" + #line 3211 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4523,7 +4523,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3238 "Python/bytecodes.c" + #line 3245 "Python/bytecodes.c" int is_meth = method != NULL; int total_args = oparg; if (is_meth) { @@ -4565,7 +4565,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3270 "Python/bytecodes.c" + #line 3277 "Python/bytecodes.c" assert(kwnames == NULL); assert(oparg == 0 || oparg == 1); int is_meth = method != NULL; @@ -4607,7 +4607,7 @@ PyObject **args = (stack_pointer - oparg); PyObject *method = stack_pointer[-(2 + oparg)]; PyObject *res; - #line 3302 "Python/bytecodes.c" + #line 3309 "Python/bytecodes.c" assert(kwnames == NULL); int is_meth = method != NULL; int total_args = oparg; @@ -4645,7 +4645,7 @@ } TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { - #line 3333 "Python/bytecodes.c" + #line 3340 "Python/bytecodes.c" GO_TO_INSTRUCTION(CALL_FUNCTION_EX); #line 4651 "Python/generated_cases.c.h" } @@ -4656,7 +4656,7 @@ PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))]; PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))]; PyObject *result; - #line 3337 "Python/bytecodes.c" + #line 3344 "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)); @@ -4722,7 +4722,7 @@ Py_DECREF(func); Py_DECREF(callargs); Py_XDECREF(kwargs); - #line 3399 "Python/bytecodes.c" + #line 3406 "Python/bytecodes.c" assert(PEEK(3 + (oparg & 1)) == NULL); if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; } #line 4729 "Python/generated_cases.c.h" @@ -4736,7 +4736,7 @@ TARGET(MAKE_FUNCTION) { PyObject *codeobj = stack_pointer[-1]; PyObject *func; - #line 3405 "Python/bytecodes.c" + #line 3412 "Python/bytecodes.c" PyFunctionObject *func_obj = (PyFunctionObject *) PyFunction_New(codeobj, GLOBALS()); @@ -4756,7 +4756,7 @@ TARGET(SET_FUNCTION_ATTRIBUTE) { PyObject *func = stack_pointer[-1]; PyObject *attr = stack_pointer[-2]; - #line 3419 "Python/bytecodes.c" + #line 3426 "Python/bytecodes.c" assert(PyFunction_Check(func)); PyFunctionObject *func_obj = (PyFunctionObject *)func; switch(oparg) { @@ -4788,7 +4788,7 @@ } TARGET(RETURN_GENERATOR) { - #line 3446 "Python/bytecodes.c" + #line 3453 "Python/bytecodes.c" assert(PyFunction_Check(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -4817,13 +4817,13 @@ PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))]; PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))]; PyObject *slice; - #line 3469 "Python/bytecodes.c" + #line 3476 "Python/bytecodes.c" slice = PySlice_New(start, stop, step); #line 4823 "Python/generated_cases.c.h" Py_DECREF(start); Py_DECREF(stop); Py_XDECREF(step); - #line 3471 "Python/bytecodes.c" + #line 3478 "Python/bytecodes.c" if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; } #line 4829 "Python/generated_cases.c.h" STACK_SHRINK(((oparg == 3) ? 1 : 0)); @@ -4835,7 +4835,7 @@ TARGET(CONVERT_VALUE) { PyObject *value = stack_pointer[-1]; PyObject *result; - #line 3475 "Python/bytecodes.c" + #line 3482 "Python/bytecodes.c" convertion_func_ptr conv_fn; assert(oparg >= FVC_STR && oparg <= FVC_ASCII); conv_fn = CONVERSION_FUNCTIONS[oparg]; @@ -4850,7 +4850,7 @@ TARGET(FORMAT_SIMPLE) { PyObject *value = stack_pointer[-1]; PyObject *res; - #line 3484 "Python/bytecodes.c" + #line 3491 "Python/bytecodes.c" /* If value is a unicode object, then we know the result * of format(value) is value itself. */ if (!PyUnicode_CheckExact(value)) { @@ -4870,7 +4870,7 @@ PyObject *fmt_spec = stack_pointer[-1]; PyObject *value = stack_pointer[-2]; PyObject *res; - #line 3497 "Python/bytecodes.c" + #line 3504 "Python/bytecodes.c" res = PyObject_Format(value, fmt_spec); Py_DECREF(value); Py_DECREF(fmt_spec); @@ -4884,7 +4884,7 @@ TARGET(COPY) { PyObject *bottom = stack_pointer[-(1 + (oparg-1))]; PyObject *top; - #line 3504 "Python/bytecodes.c" + #line 3511 "Python/bytecodes.c" assert(oparg > 0); top = Py_NewRef(bottom); #line 4891 "Python/generated_cases.c.h" @@ -4899,7 +4899,7 @@ PyObject *rhs = stack_pointer[-1]; PyObject *lhs = stack_pointer[-2]; PyObject *res; - #line 3509 "Python/bytecodes.c" + #line 3516 "Python/bytecodes.c" #if ENABLE_SPECIALIZATION _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { @@ -4917,7 +4917,7 @@ #line 4918 "Python/generated_cases.c.h" Py_DECREF(lhs); Py_DECREF(rhs); - #line 3524 "Python/bytecodes.c" + #line 3531 "Python/bytecodes.c" if (res == NULL) goto pop_2_error; #line 4923 "Python/generated_cases.c.h" STACK_SHRINK(1); @@ -4929,7 +4929,7 @@ TARGET(SWAP) { PyObject *top = stack_pointer[-1]; PyObject *bottom = stack_pointer[-(2 + (oparg-2))]; - #line 3529 "Python/bytecodes.c" + #line 3536 "Python/bytecodes.c" assert(oparg >= 2); #line 4935 "Python/generated_cases.c.h" stack_pointer[-1] = bottom; @@ -4938,7 +4938,7 @@ } TARGET(INSTRUMENTED_INSTRUCTION) { - #line 3533 "Python/bytecodes.c" + #line 3540 "Python/bytecodes.c" int next_opcode = _Py_call_instrumentation_instruction( tstate, frame, next_instr-1); if (next_opcode < 0) goto error; @@ -4954,14 +4954,14 @@ } TARGET(INSTRUMENTED_JUMP_FORWARD) { - #line 3547 "Python/bytecodes.c" + #line 3554 "Python/bytecodes.c" INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP); #line 4960 "Python/generated_cases.c.h" DISPATCH(); } TARGET(INSTRUMENTED_JUMP_BACKWARD) { - #line 3551 "Python/bytecodes.c" + #line 3558 "Python/bytecodes.c" CHECK_EVAL_BREAKER(); INSTRUMENTED_JUMP(next_instr-1, next_instr+1-oparg, PY_MONITORING_EVENT_JUMP); #line 4968 "Python/generated_cases.c.h" @@ -4969,7 +4969,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) { - #line 3556 "Python/bytecodes.c" + #line 3563 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; @@ -4980,7 +4980,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) { - #line 3564 "Python/bytecodes.c" + #line 3571 "Python/bytecodes.c" PyObject *cond = POP(); assert(PyBool_Check(cond)); _Py_CODEUNIT *here = next_instr - 1; @@ -4991,7 +4991,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) { - #line 3572 "Python/bytecodes.c" + #line 3579 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -5008,7 +5008,7 @@ } TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) { - #line 3586 "Python/bytecodes.c" + #line 3593 "Python/bytecodes.c" PyObject *value = POP(); _Py_CODEUNIT *here = next_instr-1; int offset; @@ -5025,7 +5025,7 @@ } TARGET(EXTENDED_ARG) { - #line 3600 "Python/bytecodes.c" + #line 3607 "Python/bytecodes.c" assert(oparg); opcode = next_instr->op.code; oparg = oparg << 8 | next_instr->op.arg; @@ -5035,14 +5035,14 @@ } TARGET(CACHE) { - #line 3608 "Python/bytecodes.c" + #line 3615 "Python/bytecodes.c" assert(0 && "Executing a cache."); Py_UNREACHABLE(); #line 5042 "Python/generated_cases.c.h" } TARGET(RESERVED) { - #line 3613 "Python/bytecodes.c" + #line 3620 "Python/bytecodes.c" assert(0 && "Executing RESERVED instruction."); Py_UNREACHABLE(); #line 5049 "Python/generated_cases.c.h" diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index fc4da28b1bd798e..286564c123e4cb6 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -38,7 +38,8 @@ #define _LOAD_FROM_DICT_OR_GLOBALS 316 #define IS_NONE 317 #define _ITER_CHECK_RANGE 318 -#define _ITER_NEXT_RANGE 319 +#define _ITER_EXHAUSTED_RANGE 319 +#define _ITER_NEXT_RANGE 320 #ifndef NEED_OPCODE_METADATA extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump); @@ -1316,6 +1317,7 @@ const char * const _PyOpcode_uop_name[512] = { [316] = "_LOAD_FROM_DICT_OR_GLOBALS", [317] = "IS_NONE", [318] = "_ITER_CHECK_RANGE", - [319] = "_ITER_NEXT_RANGE", + [319] = "_ITER_EXHAUSTED_RANGE", + [320] = "_ITER_NEXT_RANGE", }; #endif // NEED_OPCODE_METADATA diff --git a/Python/optimizer.c b/Python/optimizer.c index 7fc40e66057d305..8dc6e325dfe68bb 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -479,6 +479,28 @@ translate_bytecode_to_trace( break; } + case FOR_ITER_RANGE: + { + // Assume jump unlikely (can a for-loop exit be likely?) + // Reserve 9 entries (4 here, 3 stub, plus SAVE_IP + EXIT_TRACE) + if (trace_length + 9 > max_length) { + DPRINTF(1, "Ran out of space for FOR_ITER_RANGE\n"); + goto done; + } + _Py_CODEUNIT *target_instr = // +1 at the end skips over END_FOR + instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]] + oparg + 1; + max_length -= 3; // Really the start of the stubs + ADD_TO_TRACE(_ITER_CHECK_RANGE, 0); + ADD_TO_TRACE(_ITER_EXHAUSTED_RANGE, 0); + ADD_TO_TRACE(_POP_JUMP_IF_TRUE, max_length); + ADD_TO_TRACE(_ITER_NEXT_RANGE, 0); + + ADD_TO_STUB(max_length + 0, POP_TOP, 0); + ADD_TO_STUB(max_length + 1, SAVE_IP, INSTR_IP(target_instr, code)); + ADD_TO_STUB(max_length + 2, EXIT_TRACE, 0); + break; + } + default: { const struct opcode_macro_expansion *expansion = &_PyOpcode_macro_expansion[opcode];