mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	bpo-46329: Streamline calling sequence a bit. (GH-31465)
* Move handling of bound-methods to PRECALL. * Remove call_shape.postcall_shrink * Remove call_shape.callable * Remove call_shape.callable. Change CALL oparg to match PRECALL oparg. * Move KW_NAMES before PRECALL. * Update opcode docs in dis.rst
This commit is contained in:
		
							parent
							
								
									0a222db2bc
								
							
						
					
					
						commit
						59585d6b2e
					
				
					 7 changed files with 218 additions and 178 deletions
				
			
		
							
								
								
									
										269
									
								
								Python/ceval.c
									
										
									
									
									
								
							
							
						
						
									
										269
									
								
								Python/ceval.c
									
										
									
									
									
								
							|  | @ -1585,15 +1585,19 @@ pop_frame(PyThreadState *tstate, InterpreterFrame *frame) | |||
| } | ||||
| 
 | ||||
| /* It is only between the PRECALL instruction and the following CALL,
 | ||||
|  * that these values have any meaning. | ||||
|  * that this has any meaning. | ||||
|  */ | ||||
| typedef struct { | ||||
|     PyObject *callable; | ||||
|     PyObject *kwnames; | ||||
|     int total_args; | ||||
|     int postcall_shrink; | ||||
| } CallShape; | ||||
| 
 | ||||
| static inline bool | ||||
| is_method(PyObject **stack_pointer, int args) { | ||||
|     return PEEK(args+2) != NULL; | ||||
| } | ||||
| 
 | ||||
| #define KWNAMES_LEN() \ | ||||
|     (call_shape.kwnames == NULL ? 0 : ((int)PyTuple_GET_SIZE(call_shape.kwnames))) | ||||
| 
 | ||||
| PyObject* _Py_HOT_FUNCTION | ||||
| _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int throwflag) | ||||
|  | @ -1616,11 +1620,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|     CFrame cframe; | ||||
|     CallShape call_shape; | ||||
|     call_shape.kwnames = NULL; // Borrowed reference. Reset by CALL instructions.
 | ||||
|     /* The following three values are always set by the PRECALL instructions.
 | ||||
|        They are set here to keep the compiler happy. */ | ||||
|     call_shape.postcall_shrink = 0; | ||||
|     call_shape.total_args = 0; | ||||
|     call_shape.callable = NULL; // Strong reference
 | ||||
| 
 | ||||
|     /* WARNING: Because the CFrame lives on the C stack,
 | ||||
|      * but can be accessed from a heap allocated object (tstate) | ||||
|  | @ -4513,23 +4512,31 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             int nargs = oparg + is_method; | ||||
|             /* Move ownership of reference from stack to call_shape
 | ||||
|              * and make sure that NULL is cleared from stack */ | ||||
|             call_shape.callable = PEEK(nargs + 1); | ||||
|             call_shape.postcall_shrink = 2-is_method; | ||||
| 
 | ||||
|             call_shape.total_args = nargs; | ||||
|             assert(call_shape.kwnames == NULL); | ||||
|             PyObject *function = PEEK(nargs + 1); | ||||
| #ifdef Py_STATS | ||||
|             extern int _PySpecialization_ClassifyCallable(PyObject *); | ||||
|             SpecializationStats *stats = | ||||
|                 &_py_stats.opcode_stats[PRECALL].specialization; | ||||
|             stats->failure++; | ||||
|             int kind = _PySpecialization_ClassifyCallable(call_shape.callable); | ||||
|             int kind = _PySpecialization_ClassifyCallable(function); | ||||
|             stats->failure_kinds[kind]++; | ||||
| #endif | ||||
|             if (!is_method && Py_TYPE(function) == &PyMethod_Type) { | ||||
|                 PyObject *meth = ((PyMethodObject *)function)->im_func; | ||||
|                 PyObject *self = ((PyMethodObject *)function)->im_self; | ||||
|                 Py_INCREF(meth); | ||||
|                 Py_INCREF(self); | ||||
|                 PEEK(oparg+1) = self; | ||||
|                 PEEK(oparg+2) = meth; | ||||
|                 Py_DECREF(function); | ||||
|                 function = meth; | ||||
|             } | ||||
| 
 | ||||
|             DISPATCH(); | ||||
|         } | ||||
| 
 | ||||
|         TARGET(KW_NAMES) { | ||||
|             assert(call_shape.kwnames == NULL); | ||||
|             assert(oparg < PyTuple_GET_SIZE(consts)); | ||||
|             call_shape.kwnames = GETITEM(consts, oparg); | ||||
|             DISPATCH(); | ||||
|  | @ -4537,25 +4544,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
| 
 | ||||
|         TARGET(CALL) { | ||||
|             PREDICTED(CALL); | ||||
|             PyObject *function; | ||||
|             assert((oparg == 0 && call_shape.kwnames == NULL) | ||||
|                 || (oparg != 0 && oparg == PyTuple_GET_SIZE(call_shape.kwnames))); | ||||
|             int is_meth; | ||||
|         call_function: | ||||
|             function = call_shape.callable; | ||||
|             if (Py_TYPE(function) == &PyMethod_Type) { | ||||
|                 PyObject *meth = ((PyMethodObject *)function)->im_func; | ||||
|                 PyObject *self = ((PyMethodObject *)function)->im_self; | ||||
|                 Py_INCREF(meth); | ||||
|                 Py_INCREF(self); | ||||
|                 PEEK(call_shape.total_args + 1) = self; | ||||
|                 Py_DECREF(function); | ||||
|                 function = meth; | ||||
|                 call_shape.total_args++; | ||||
|                 assert(call_shape.postcall_shrink >= 1); | ||||
|                 call_shape.postcall_shrink--; | ||||
|             } | ||||
|             int total_args = call_shape.total_args; | ||||
|             int positional_args = total_args - oparg; | ||||
|             is_meth = is_method(stack_pointer, oparg); | ||||
|             int total_args = oparg + is_meth; | ||||
|             PyObject *function = PEEK(total_args + 1); | ||||
|             int positional_args = total_args - KWNAMES_LEN(); | ||||
|             // Check if the call can be inlined or not
 | ||||
|             if (Py_TYPE(function) == &PyFunction_Type && tstate->interp->eval_frame == NULL) { | ||||
|                 int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(function))->co_flags; | ||||
|  | @ -4566,7 +4560,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|                     stack_pointer, positional_args, call_shape.kwnames | ||||
|                 ); | ||||
|                 call_shape.kwnames = NULL; | ||||
|                 STACK_SHRINK(call_shape.postcall_shrink); | ||||
|                 STACK_SHRINK(2-is_meth); | ||||
|                 // The frame has stolen all the arguments from the stack,
 | ||||
|                 // so there is no need to clean them up.
 | ||||
|                 if (new_frame == NULL) { | ||||
|  | @ -4599,7 +4593,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             for (int i = 0; i < total_args; i++) { | ||||
|                 Py_DECREF(stack_pointer[i]); | ||||
|             } | ||||
|             STACK_SHRINK(call_shape.postcall_shrink); | ||||
|             STACK_SHRINK(2-is_meth); | ||||
|             PUSH(res); | ||||
|             if (res == NULL) { | ||||
|                 goto error; | ||||
|  | @ -4610,14 +4604,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
| 
 | ||||
|         TARGET(CALL_ADAPTIVE) { | ||||
|             SpecializedCacheEntry *cache = GET_CACHE(); | ||||
|             int named_args = cache->adaptive.original_oparg; | ||||
|             assert((named_args == 0 && call_shape.kwnames == NULL) | ||||
|                 || (named_args != 0 && named_args == PyTuple_GET_SIZE(call_shape.kwnames))); | ||||
|             int original_oparg = cache->adaptive.original_oparg; | ||||
|             if (cache->adaptive.counter == 0) { | ||||
|                 next_instr--; | ||||
|                 int nargs = call_shape.total_args; | ||||
|                 int is_meth = is_method(stack_pointer, original_oparg); | ||||
|                 int nargs = original_oparg + is_meth; | ||||
|                 PyObject *callable = PEEK(nargs + 1); | ||||
|                 int err = _Py_Specialize_CallNoKw( | ||||
|                     call_shape.callable, next_instr, nargs, | ||||
|                     callable, next_instr, nargs, | ||||
|                     call_shape.kwnames, cache, BUILTINS()); | ||||
|                 if (err < 0) { | ||||
|                     goto error; | ||||
|  | @ -4627,7 +4621,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             else { | ||||
|                 STAT_INC(CALL, deferred); | ||||
|                 cache->adaptive.counter--; | ||||
|                 oparg = named_args; | ||||
|                 oparg = original_oparg; | ||||
|                 goto call_function; | ||||
|             } | ||||
|         } | ||||
|  | @ -4635,10 +4629,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|         TARGET(CALL_PY_EXACT_ARGS) { | ||||
|             assert(call_shape.kwnames == NULL); | ||||
|             SpecializedCacheEntry *caches = GET_CACHE(); | ||||
|             int argcount = call_shape.total_args; | ||||
|             DEOPT_IF(!PyFunction_Check(call_shape.callable), CALL); | ||||
|             int original_oparg = caches->adaptive.original_oparg; | ||||
|             int is_meth = is_method(stack_pointer, original_oparg); | ||||
|             int argcount = original_oparg + is_meth; | ||||
|             PyObject *callable = PEEK(argcount + 1); | ||||
|             DEOPT_IF(!PyFunction_Check(callable), CALL); | ||||
|             _PyCallCache *cache1 = &caches[-1].call; | ||||
|             PyFunctionObject *func = (PyFunctionObject *)call_shape.callable; | ||||
|             PyFunctionObject *func = (PyFunctionObject *)callable; | ||||
|             DEOPT_IF(func->func_version != cache1->func_version, CALL); | ||||
|             PyCodeObject *code = (PyCodeObject *)func->func_code; | ||||
|             DEOPT_IF(code->co_argcount != argcount, CALL); | ||||
|  | @ -4654,7 +4651,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             for (int i = argcount; i < code->co_nlocalsplus; i++) { | ||||
|                 new_frame->localsplus[i] = NULL; | ||||
|             } | ||||
|             STACK_SHRINK(call_shape.postcall_shrink); | ||||
|             STACK_SHRINK(2-is_meth); | ||||
|             _PyFrame_SetStackPointer(frame, stack_pointer); | ||||
|             new_frame->previous = frame; | ||||
|             frame = cframe.current_frame = new_frame; | ||||
|  | @ -4664,10 +4661,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|         TARGET(CALL_PY_WITH_DEFAULTS) { | ||||
|             assert(call_shape.kwnames == NULL); | ||||
|             SpecializedCacheEntry *caches = GET_CACHE(); | ||||
|             int argcount = call_shape.total_args; | ||||
|             DEOPT_IF(!PyFunction_Check(call_shape.callable), CALL); | ||||
|             int original_oparg = caches->adaptive.original_oparg; | ||||
|             int is_meth = is_method(stack_pointer, original_oparg); | ||||
|             int argcount = original_oparg + is_meth; | ||||
|             PyObject *callable = PEEK(argcount + 1); | ||||
|             DEOPT_IF(!PyFunction_Check(callable), CALL); | ||||
|             _PyCallCache *cache1 = &caches[-1].call; | ||||
|             PyFunctionObject *func = (PyFunctionObject *)call_shape.callable; | ||||
|             PyFunctionObject *func = (PyFunctionObject *)callable; | ||||
|             DEOPT_IF(func->func_version != cache1->func_version, CALL); | ||||
|             PyCodeObject *code = (PyCodeObject *)func->func_code; | ||||
|             DEOPT_IF(argcount > code->co_argcount, CALL); | ||||
|  | @ -4691,7 +4691,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             for (int i = code->co_argcount; i < code->co_nlocalsplus; i++) { | ||||
|                 new_frame->localsplus[i] = NULL; | ||||
|             } | ||||
|             STACK_SHRINK(call_shape.postcall_shrink); | ||||
|             STACK_SHRINK(2-is_meth); | ||||
|             _PyFrame_SetStackPointer(frame, stack_pointer); | ||||
|             new_frame->previous = frame; | ||||
|             frame = cframe.current_frame = new_frame; | ||||
|  | @ -4701,14 +4701,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|         TARGET(CALL_NO_KW_TYPE_1) { | ||||
|             assert(call_shape.kwnames == NULL); | ||||
|             assert(cframe.use_tracing == 0); | ||||
|             DEOPT_IF(call_shape.total_args != 1, CALL); | ||||
|             assert(GET_CACHE()->adaptive.original_oparg == 1); | ||||
|             DEOPT_IF(is_method(stack_pointer, 1), CALL); | ||||
|             PyObject *obj = TOP(); | ||||
|             PyObject *callable = SECOND(); | ||||
|             DEOPT_IF(callable != (PyObject *)&PyType_Type, CALL); | ||||
|             PyObject *res = Py_NewRef(Py_TYPE(obj)); | ||||
|             Py_DECREF(callable); | ||||
|             Py_DECREF(obj); | ||||
|             STACK_SHRINK(call_shape.postcall_shrink); | ||||
|             STACK_SHRINK(2); | ||||
|             SET_TOP(res); | ||||
|             NOTRACE_DISPATCH(); | ||||
|         } | ||||
|  | @ -4716,16 +4717,18 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|         TARGET(CALL_NO_KW_STR_1) { | ||||
|             assert(call_shape.kwnames == NULL); | ||||
|             assert(cframe.use_tracing == 0); | ||||
|             DEOPT_IF(!PyType_Check(call_shape.callable), CALL); | ||||
|             PyTypeObject *tp = (PyTypeObject *)call_shape.callable; | ||||
|             DEOPT_IF(call_shape.total_args != 1, CALL); | ||||
|             assert(GET_CACHE()->adaptive.original_oparg == 1); | ||||
|             PyObject *callable = PEEK(2); | ||||
|             DEOPT_IF(!PyType_Check(callable), CALL); | ||||
|             PyTypeObject *tp = (PyTypeObject *)callable; | ||||
|             DEOPT_IF(is_method(stack_pointer, 1), CALL); | ||||
|             DEOPT_IF(tp != &PyUnicode_Type, CALL); | ||||
|             STAT_INC(CALL, hit); | ||||
|             PyObject *arg = TOP(); | ||||
|             PyObject *res = PyObject_Str(arg); | ||||
|             Py_DECREF(arg); | ||||
|             Py_DECREF(&PyUnicode_Type); | ||||
|             STACK_SHRINK(call_shape.postcall_shrink); | ||||
|             STACK_SHRINK(2); | ||||
|             SET_TOP(res); | ||||
|             if (res == NULL) { | ||||
|                 goto error; | ||||
|  | @ -4736,16 +4739,19 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
| 
 | ||||
|         TARGET(CALL_NO_KW_TUPLE_1) { | ||||
|             assert(call_shape.kwnames == NULL); | ||||
|             DEOPT_IF(!PyType_Check(call_shape.callable), CALL); | ||||
|             PyTypeObject *tp = (PyTypeObject *)call_shape.callable; | ||||
|             DEOPT_IF(call_shape.total_args != 1, CALL); | ||||
|             assert(GET_CACHE()->adaptive.original_oparg == 1); | ||||
|             int is_meth = is_method(stack_pointer, 1); | ||||
|             PyObject *callable = PEEK(2); | ||||
|             DEOPT_IF(!PyType_Check(callable), CALL); | ||||
|             PyTypeObject *tp = (PyTypeObject *)callable; | ||||
|             DEOPT_IF(is_meth, CALL); | ||||
|             DEOPT_IF(tp != &PyTuple_Type, CALL); | ||||
|             STAT_INC(CALL, hit); | ||||
|             PyObject *arg = TOP(); | ||||
|             PyObject *res = PySequence_Tuple(arg); | ||||
|             Py_DECREF(arg); | ||||
|             Py_DECREF(&PyTuple_Type); | ||||
|             STACK_SHRINK(call_shape.postcall_shrink); | ||||
|             STACK_SHRINK(2); | ||||
|             SET_TOP(res); | ||||
|             if (res == NULL) { | ||||
|                 goto error; | ||||
|  | @ -4755,22 +4761,25 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|         } | ||||
| 
 | ||||
|         TARGET(CALL_BUILTIN_CLASS) { | ||||
|             DEOPT_IF(!PyType_Check(call_shape.callable), CALL); | ||||
|             PyTypeObject *tp = (PyTypeObject *)call_shape.callable; | ||||
|             int original_oparg = GET_CACHE()->adaptive.original_oparg; | ||||
|             int is_meth = is_method(stack_pointer, original_oparg); | ||||
|             int total_args = original_oparg + is_meth; | ||||
|             int kwnames_len = KWNAMES_LEN(); | ||||
|             PyObject *callable = PEEK(total_args + 1); | ||||
|             DEOPT_IF(!PyType_Check(callable), CALL); | ||||
|             PyTypeObject *tp = (PyTypeObject *)callable; | ||||
|             DEOPT_IF(tp->tp_vectorcall == NULL, CALL); | ||||
|             STAT_INC(CALL, hit); | ||||
|             int kwnames_len = GET_CACHE()->adaptive.original_oparg; | ||||
| 
 | ||||
|             int nargs = call_shape.total_args - kwnames_len; | ||||
|             STACK_SHRINK(call_shape.total_args); | ||||
|             PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer, nargs, call_shape.kwnames); | ||||
|             STACK_SHRINK(total_args); | ||||
|             PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer, | ||||
|                                               total_args-kwnames_len, call_shape.kwnames); | ||||
|             call_shape.kwnames = NULL; | ||||
|             /* Free the arguments. */ | ||||
|             for (int i = 0; i < call_shape.total_args; i++) { | ||||
|             for (int i = 0; i < total_args; i++) { | ||||
|                 Py_DECREF(stack_pointer[i]); | ||||
|             } | ||||
|             Py_DECREF(tp); | ||||
|             STACK_SHRINK(call_shape.postcall_shrink-1); | ||||
|             STACK_SHRINK(1-is_meth); | ||||
|             SET_TOP(res); | ||||
|             if (res == NULL) { | ||||
|                 goto error; | ||||
|  | @ -4783,8 +4792,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             assert(cframe.use_tracing == 0); | ||||
|             /* Builtin METH_O functions */ | ||||
|             assert(call_shape.kwnames == NULL); | ||||
|             DEOPT_IF(call_shape.total_args != 1, CALL); | ||||
|             PyObject *callable = call_shape.callable; | ||||
|             SpecializedCacheEntry *caches = GET_CACHE(); | ||||
|             int original_oparg = caches->adaptive.original_oparg; | ||||
|             int is_meth = is_method(stack_pointer, original_oparg); | ||||
|             int total_args = original_oparg + is_meth; | ||||
|             DEOPT_IF(total_args != 1, CALL); | ||||
|             PyObject *callable = PEEK(total_args + 1); | ||||
|             DEOPT_IF(!PyCFunction_CheckExact(callable), CALL); | ||||
|             DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_O, CALL); | ||||
|             STAT_INC(CALL, hit); | ||||
|  | @ -4802,7 +4815,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
| 
 | ||||
|             Py_DECREF(arg); | ||||
|             Py_DECREF(callable); | ||||
|             STACK_SHRINK(call_shape.postcall_shrink); | ||||
|             STACK_SHRINK(2-is_meth); | ||||
|             SET_TOP(res); | ||||
|             if (res == NULL) { | ||||
|                 goto error; | ||||
|  | @ -4815,27 +4828,30 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             assert(cframe.use_tracing == 0); | ||||
|             /* Builtin METH_FASTCALL functions, without keywords */ | ||||
|             assert(call_shape.kwnames == NULL); | ||||
|             PyObject *callable = call_shape.callable; | ||||
|             SpecializedCacheEntry *caches = GET_CACHE(); | ||||
|             int original_oparg = caches->adaptive.original_oparg; | ||||
|             int is_meth = is_method(stack_pointer, original_oparg); | ||||
|             int total_args = original_oparg + is_meth; | ||||
|             PyObject *callable = PEEK(total_args + 1); | ||||
|             DEOPT_IF(!PyCFunction_CheckExact(callable), CALL); | ||||
|             DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_FASTCALL, | ||||
|                 CALL); | ||||
|             STAT_INC(CALL, hit); | ||||
| 
 | ||||
|             int nargs = call_shape.total_args; | ||||
|             PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable); | ||||
|             STACK_SHRINK(nargs); | ||||
|             STACK_SHRINK(total_args); | ||||
|             /* res = func(self, args, nargs) */ | ||||
|             PyObject *res = ((_PyCFunctionFast)(void(*)(void))cfunc)( | ||||
|                 PyCFunction_GET_SELF(callable), | ||||
|                 stack_pointer, | ||||
|                 nargs); | ||||
|                 total_args); | ||||
|             assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); | ||||
| 
 | ||||
|             /* Free the arguments. */ | ||||
|             for (int i = 0; i < nargs; i++) { | ||||
|             for (int i = 0; i < total_args; i++) { | ||||
|                 Py_DECREF(stack_pointer[i]); | ||||
|             } | ||||
|             STACK_SHRINK(call_shape.postcall_shrink); | ||||
|             STACK_SHRINK(2-is_meth); | ||||
|             PUSH(res); | ||||
|             Py_DECREF(callable); | ||||
|             if (res == NULL) { | ||||
|  | @ -4853,19 +4869,16 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|         TARGET(CALL_BUILTIN_FAST_WITH_KEYWORDS) { | ||||
|             assert(cframe.use_tracing == 0); | ||||
|             /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ | ||||
|             PyObject *callable = call_shape.callable; | ||||
|             SpecializedCacheEntry *caches = GET_CACHE(); | ||||
|             int original_oparg = caches->adaptive.original_oparg; | ||||
|             int is_meth = is_method(stack_pointer, original_oparg); | ||||
|             int total_args = original_oparg + is_meth; | ||||
|             PyObject *callable = PEEK(total_args + 1); | ||||
|             DEOPT_IF(!PyCFunction_CheckExact(callable), CALL); | ||||
|             DEOPT_IF(PyCFunction_GET_FLAGS(callable) != | ||||
|                 (METH_FASTCALL | METH_KEYWORDS), CALL); | ||||
|             STAT_INC(CALL, hit); | ||||
|             int kwnames_len = GET_CACHE()->adaptive.original_oparg; | ||||
|             assert( | ||||
|                 (call_shape.kwnames == NULL && kwnames_len == 0) || | ||||
|                 (call_shape.kwnames != NULL && | ||||
|                  PyTuple_GET_SIZE(call_shape.kwnames) == kwnames_len) | ||||
|             ); | ||||
|             int nargs = call_shape.total_args - kwnames_len; | ||||
|             STACK_SHRINK(call_shape.total_args); | ||||
|             STACK_SHRINK(total_args); | ||||
|             /* res = func(self, args, nargs, kwnames) */ | ||||
|             _PyCFunctionFastWithKeywords cfunc = | ||||
|                 (_PyCFunctionFastWithKeywords)(void(*)(void)) | ||||
|  | @ -4873,17 +4886,17 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             PyObject *res = cfunc( | ||||
|                 PyCFunction_GET_SELF(callable), | ||||
|                 stack_pointer, | ||||
|                 nargs, | ||||
|                 total_args - KWNAMES_LEN(), | ||||
|                 call_shape.kwnames | ||||
|             ); | ||||
|             assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); | ||||
|             call_shape.kwnames = NULL; | ||||
| 
 | ||||
|             /* Free the arguments. */ | ||||
|             for (int i = 0; i < call_shape.total_args; i++) { | ||||
|             for (int i = 0; i < total_args; i++) { | ||||
|                 Py_DECREF(stack_pointer[i]); | ||||
|             } | ||||
|             STACK_SHRINK(call_shape.postcall_shrink); | ||||
|             STACK_SHRINK(2-is_meth); | ||||
|             PUSH(res); | ||||
|             Py_DECREF(callable); | ||||
|             if (res == NULL) { | ||||
|  | @ -4898,11 +4911,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             assert(call_shape.kwnames == NULL); | ||||
|             /* len(o) */ | ||||
|             SpecializedCacheEntry *caches = GET_CACHE(); | ||||
|             DEOPT_IF(call_shape.total_args != 1, CALL); | ||||
|             assert(caches[0].adaptive.original_oparg == 0); | ||||
|             int original_oparg = caches->adaptive.original_oparg; | ||||
|             int is_meth = is_method(stack_pointer, original_oparg); | ||||
|             int total_args = original_oparg + is_meth; | ||||
|             DEOPT_IF(total_args != 1, CALL); | ||||
|             _PyObjectCache *cache1 = &caches[-1].obj; | ||||
| 
 | ||||
|             PyObject *callable = call_shape.callable; | ||||
|             PyObject *callable = PEEK(total_args + 1); | ||||
|             DEOPT_IF(callable != cache1->obj, CALL); | ||||
|             STAT_INC(CALL, hit); | ||||
| 
 | ||||
|  | @ -4914,7 +4928,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             PyObject *res = PyLong_FromSsize_t(len_i); | ||||
|             assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); | ||||
| 
 | ||||
|             STACK_SHRINK(call_shape.postcall_shrink); | ||||
|             STACK_SHRINK(2-is_meth); | ||||
|             SET_TOP(res); | ||||
|             Py_DECREF(callable); | ||||
|             Py_DECREF(arg); | ||||
|  | @ -4929,11 +4943,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             assert(call_shape.kwnames == NULL); | ||||
|             /* isinstance(o, o2) */ | ||||
|             SpecializedCacheEntry *caches = GET_CACHE(); | ||||
|             assert(caches[0].adaptive.original_oparg == 0); | ||||
|             DEOPT_IF(call_shape.total_args != 2, CALL); | ||||
|             int original_oparg = caches->adaptive.original_oparg; | ||||
|             int is_meth = is_method(stack_pointer, original_oparg); | ||||
|             int total_args = original_oparg + is_meth; | ||||
|             PyObject *callable = PEEK(total_args + 1); | ||||
|             DEOPT_IF(total_args != 2, CALL); | ||||
|             _PyObjectCache *cache1 = &caches[-1].obj; | ||||
| 
 | ||||
|             DEOPT_IF(call_shape.callable != cache1->obj, CALL); | ||||
|             DEOPT_IF(callable != cache1->obj, CALL); | ||||
|             STAT_INC(CALL, hit); | ||||
| 
 | ||||
|             PyObject *cls = POP(); | ||||
|  | @ -4946,11 +4963,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             PyObject *res = PyBool_FromLong(retval); | ||||
|             assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); | ||||
| 
 | ||||
|             STACK_SHRINK(call_shape.postcall_shrink); | ||||
|             STACK_SHRINK(2-is_meth); | ||||
|             SET_TOP(res); | ||||
|             Py_DECREF(inst); | ||||
|             Py_DECREF(cls); | ||||
|             Py_DECREF(call_shape.callable); | ||||
|             Py_DECREF(callable); | ||||
|             if (res == NULL) { | ||||
|                 goto error; | ||||
|             } | ||||
|  | @ -4961,9 +4978,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             assert(cframe.use_tracing == 0); | ||||
|             assert(call_shape.kwnames == NULL); | ||||
|             SpecializedCacheEntry *caches = GET_CACHE(); | ||||
|             int original_oparg = caches->adaptive.original_oparg; | ||||
|             _PyObjectCache *cache1 = &caches[-1].obj; | ||||
|             DEOPT_IF(call_shape.total_args != 2, CALL); | ||||
|             DEOPT_IF(call_shape.callable != cache1->obj, CALL); | ||||
|             int is_meth = is_method(stack_pointer, original_oparg); | ||||
|             int total_args = original_oparg + is_meth; | ||||
|             PyObject *callable = PEEK(total_args + 1); | ||||
|             DEOPT_IF(total_args != 2, CALL); | ||||
|             DEOPT_IF(callable != cache1->obj, CALL); | ||||
|             PyObject *list = SECOND(); | ||||
|             DEOPT_IF(!PyList_Check(list), CALL); | ||||
|             STAT_INC(CALL, hit); | ||||
|  | @ -4974,18 +4995,22 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             } | ||||
|             Py_DECREF(arg); | ||||
|             Py_DECREF(list); | ||||
|             STACK_SHRINK(call_shape.postcall_shrink+1); | ||||
|             STACK_SHRINK(3-is_meth); | ||||
|             Py_INCREF(Py_None); | ||||
|             SET_TOP(Py_None); | ||||
|             Py_DECREF(call_shape.callable); | ||||
|             Py_DECREF(callable); | ||||
|             NOTRACE_DISPATCH(); | ||||
|         } | ||||
| 
 | ||||
|         TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { | ||||
|             assert(call_shape.kwnames == NULL); | ||||
|             DEOPT_IF(call_shape.total_args != 2, CALL); | ||||
|             DEOPT_IF(!Py_IS_TYPE(call_shape.callable, &PyMethodDescr_Type), CALL); | ||||
|             PyMethodDef *meth = ((PyMethodDescrObject *)call_shape.callable)->d_method; | ||||
|             int original_oparg = GET_CACHE()->adaptive.original_oparg; | ||||
|             int is_meth = is_method(stack_pointer, original_oparg); | ||||
|             int total_args = original_oparg + is_meth; | ||||
|             PyObject *callable = PEEK(total_args + 1); | ||||
|             DEOPT_IF(total_args != 2, CALL); | ||||
|             DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); | ||||
|             PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method; | ||||
|             DEOPT_IF(meth->ml_flags != METH_O, CALL); | ||||
|             STAT_INC(CALL, hit); | ||||
|             PyCFunction cfunc = meth->ml_meth; | ||||
|  | @ -5001,9 +5026,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); | ||||
|             Py_DECREF(self); | ||||
|             Py_DECREF(arg); | ||||
|             STACK_SHRINK(call_shape.postcall_shrink+1); | ||||
|             STACK_SHRINK(3-is_meth); | ||||
|             SET_TOP(res); | ||||
|             Py_DECREF(call_shape.callable); | ||||
|             Py_DECREF(callable); | ||||
|             if (res == NULL) { | ||||
|                 goto error; | ||||
|             } | ||||
|  | @ -5013,9 +5038,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
| 
 | ||||
|         TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) { | ||||
|             assert(call_shape.kwnames == NULL); | ||||
|             DEOPT_IF(call_shape.total_args != 1, CALL); | ||||
|             DEOPT_IF(!Py_IS_TYPE(call_shape.callable, &PyMethodDescr_Type), CALL); | ||||
|             PyMethodDef *meth = ((PyMethodDescrObject *)call_shape.callable)->d_method; | ||||
|             int original_oparg = GET_CACHE()->adaptive.original_oparg; | ||||
|             int is_meth = is_method(stack_pointer, original_oparg); | ||||
|             int total_args = original_oparg + is_meth; | ||||
|             PyObject *callable = PEEK(total_args + 1); | ||||
|             DEOPT_IF(total_args != 1, CALL); | ||||
|             DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); | ||||
|             PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method; | ||||
|             DEOPT_IF(meth->ml_flags != METH_NOARGS, CALL); | ||||
|             STAT_INC(CALL, hit); | ||||
|             PyCFunction cfunc = meth->ml_meth; | ||||
|  | @ -5029,9 +5058,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             _Py_LeaveRecursiveCall(tstate); | ||||
|             assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); | ||||
|             Py_DECREF(self); | ||||
|             STACK_SHRINK(call_shape.postcall_shrink); | ||||
|             STACK_SHRINK(2-is_meth); | ||||
|             SET_TOP(res); | ||||
|             Py_DECREF(call_shape.callable); | ||||
|             Py_DECREF(callable); | ||||
|             if (res == NULL) { | ||||
|                 goto error; | ||||
|             } | ||||
|  | @ -5041,13 +5070,17 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
| 
 | ||||
|         TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_FAST) { | ||||
|             assert(call_shape.kwnames == NULL); | ||||
|             int original_oparg = GET_CACHE()->adaptive.original_oparg; | ||||
|             int is_meth = is_method(stack_pointer, original_oparg); | ||||
|             int total_args = original_oparg + is_meth; | ||||
|             PyObject *callable = PEEK(total_args + 1); | ||||
|             /* Builtin METH_FASTCALL methods, without keywords */ | ||||
|             DEOPT_IF(!Py_IS_TYPE(call_shape.callable, &PyMethodDescr_Type), CALL); | ||||
|             PyMethodDef *meth = ((PyMethodDescrObject *)call_shape.callable)->d_method; | ||||
|             DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL); | ||||
|             PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method; | ||||
|             DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL); | ||||
|             STAT_INC(CALL, hit); | ||||
|             _PyCFunctionFast cfunc = (_PyCFunctionFast)(void(*)(void))meth->ml_meth; | ||||
|             int nargs = call_shape.total_args-1; | ||||
|             int nargs = total_args-1; | ||||
|             STACK_SHRINK(nargs); | ||||
|             PyObject *self = TOP(); | ||||
|             PyObject *res = cfunc(self, stack_pointer, nargs); | ||||
|  | @ -5057,9 +5090,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|                 Py_DECREF(stack_pointer[i]); | ||||
|             } | ||||
|             Py_DECREF(self); | ||||
|             STACK_SHRINK(call_shape.postcall_shrink); | ||||
|             STACK_SHRINK(2-is_meth); | ||||
|             SET_TOP(res); | ||||
|             Py_DECREF(call_shape.callable); | ||||
|             Py_DECREF(callable); | ||||
|             if (res == NULL) { | ||||
|                 goto error; | ||||
|             } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Mark Shannon
						Mark Shannon