@@ -36,9 +36,10 @@ extern int _PyObject_GetMethod(PyObject *, PyObject *, PyObject **);
36
36
typedef PyObject * (* callproc )(PyObject * , PyObject * , PyObject * );
37
37
38
38
/* Forward declarations */
39
- Py_LOCAL_INLINE (PyObject * ) call_function (PyObject * * * , Py_ssize_t ,
40
- PyObject * );
41
- static PyObject * do_call_core (PyObject * , PyObject * , PyObject * );
39
+ static PyObject * profile_call (PyThreadState * , PyObject * ,
40
+ PyObject * , PyObject * );
41
+ Py_LOCAL_INLINE (PyObject * ) call_function (PyThreadState * ,
42
+ PyObject * * * , Py_ssize_t , PyObject * );
42
43
43
44
#ifdef LLTRACE
44
45
static int lltrace ;
@@ -3241,9 +3242,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
3241
3242
3242
3243
case TARGET (CALL_METHOD ): {
3243
3244
/* Designed to work in tamdem with LOAD_METHOD. */
3244
- PyObject * * sp , * res , * meth ;
3245
-
3246
- sp = stack_pointer ;
3245
+ PyObject * res , * meth ;
3247
3246
3248
3247
meth = PEEK (oparg + 2 );
3249
3248
if (meth == NULL ) {
@@ -3261,8 +3260,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
3261
3260
`callable` will be POPed by call_function.
3262
3261
NULL will will be POPed manually later.
3263
3262
*/
3264
- res = call_function (& sp , oparg , NULL );
3265
- stack_pointer = sp ;
3263
+ res = call_function (tstate , & stack_pointer , oparg , NULL );
3266
3264
(void )POP (); /* POP the NULL. */
3267
3265
}
3268
3266
else {
@@ -3278,8 +3276,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
3278
3276
We'll be passing `oparg + 1` to call_function, to
3279
3277
make it accept the `self` as a first argument.
3280
3278
*/
3281
- res = call_function (& sp , oparg + 1 , NULL );
3282
- stack_pointer = sp ;
3279
+ res = call_function (tstate , & stack_pointer , oparg + 1 , NULL );
3283
3280
}
3284
3281
3285
3282
PUSH (res );
@@ -3290,10 +3287,8 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
3290
3287
3291
3288
case TARGET (CALL_FUNCTION ): {
3292
3289
PREDICTED (CALL_FUNCTION );
3293
- PyObject * * sp , * res ;
3294
- sp = stack_pointer ;
3295
- res = call_function (& sp , oparg , NULL );
3296
- stack_pointer = sp ;
3290
+ PyObject * res ;
3291
+ res = call_function (tstate , & stack_pointer , oparg , NULL );
3297
3292
PUSH (res );
3298
3293
if (res == NULL ) {
3299
3294
goto error ;
@@ -3302,13 +3297,11 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
3302
3297
}
3303
3298
3304
3299
case TARGET (CALL_FUNCTION_KW ): {
3305
- PyObject * * sp , * res , * names ;
3300
+ PyObject * res , * names ;
3306
3301
3307
3302
names = POP ();
3308
3303
assert (PyTuple_CheckExact (names ) && PyTuple_GET_SIZE (names ) <= oparg );
3309
- sp = stack_pointer ;
3310
- res = call_function (& sp , oparg , names );
3311
- stack_pointer = sp ;
3304
+ res = call_function (tstate , & stack_pointer , oparg , names );
3312
3305
PUSH (res );
3313
3306
Py_DECREF (names );
3314
3307
@@ -3351,7 +3344,18 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
3351
3344
}
3352
3345
assert (PyTuple_CheckExact (callargs ));
3353
3346
3354
- result = do_call_core (func , callargs , kwargs );
3347
+ if (tstate -> use_tracing ) {
3348
+ result = profile_call (tstate , func , callargs , kwargs );
3349
+ }
3350
+ else if (PyCFunction_Check (func )) {
3351
+ result = _PyCFunction_FastCallDict (func ,
3352
+ _PyTuple_ITEMS (callargs ),
3353
+ PyTuple_GET_SIZE (callargs ),
3354
+ kwargs );
3355
+ }
3356
+ else {
3357
+ result = PyObject_Call (func , callargs , kwargs );
3358
+ }
3355
3359
Py_DECREF (func );
3356
3360
Py_DECREF (callargs );
3357
3361
Py_XDECREF (kwargs );
@@ -4624,7 +4628,7 @@ PyEval_GetFuncDesc(PyObject *func)
4624
4628
}
4625
4629
4626
4630
#define C_TRACE (x , call ) \
4627
- if (tstate->use_tracing && tstate-> c_profilefunc) { \
4631
+ if (tstate->c_profilefunc) { \
4628
4632
if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, \
4629
4633
tstate, tstate->frame, \
4630
4634
PyTrace_C_CALL, func)) { \
@@ -4652,55 +4656,103 @@ if (tstate->use_tracing && tstate->c_profilefunc) { \
4652
4656
} \
4653
4657
} else { \
4654
4658
x = call ; \
4659
+ }
4660
+
4661
+
4662
+ /* Call function when profiling is enabled */
4663
+ _Py_NO_INLINE static PyObject *
4664
+ profile_fastcall (PyThreadState * tstate , PyObject * func ,
4665
+ PyObject * const * argv , Py_ssize_t nargs ,
4666
+ PyObject * kwnames )
4667
+ {
4668
+ PyObject * result ;
4669
+ if (PyCFunction_Check (func )) {
4670
+ C_TRACE (result , _PyCFunction_FastCallKeywords (func , argv , nargs , kwnames ));
4671
+ return result ;
4655
4672
}
4673
+ else if (Py_TYPE (func ) == & PyMethodDescr_Type && nargs > 0 ) {
4674
+ /* We need to create a temporary bound method as argument
4675
+ for profiling.
4676
+
4677
+ If nargs == 0, then this cannot work because we have no
4678
+ "self". In any case, the call itself would raise
4679
+ TypeError (foo needs an argument), so we just skip
4680
+ profiling. */
4681
+ PyObject * self = * (argv ++ );
4682
+ nargs -- ;
4683
+ func = Py_TYPE (func )-> tp_descr_get (func , self , (PyObject * )Py_TYPE (self ));
4684
+ if (func == NULL ) {
4685
+ return NULL ;
4686
+ }
4687
+ C_TRACE (result , _PyCFunction_FastCallKeywords (func ,
4688
+ argv , nargs ,
4689
+ kwnames ));
4690
+ Py_DECREF (func );
4691
+ return result ;
4692
+ }
4693
+ return _PyObject_FastCallKeywords (func , argv , nargs , kwnames );
4694
+ }
4695
+
4696
+ /* Call function when profiling is enabled */
4697
+ _Py_NO_INLINE static PyObject *
4698
+ profile_call (PyThreadState * tstate , PyObject * func ,
4699
+ PyObject * args , PyObject * kwdict )
4700
+ {
4701
+ PyObject * result ;
4702
+ PyObject * const * argv = _PyTuple_ITEMS (args );
4703
+ Py_ssize_t nargs = PyTuple_GET_SIZE (args );
4704
+
4705
+ if (PyCFunction_Check (func )) {
4706
+ C_TRACE (result , _PyCFunction_FastCallDict (func , argv , nargs , kwdict ));
4707
+ return result ;
4708
+ }
4709
+ else if (Py_TYPE (func ) == & PyMethodDescr_Type && nargs > 0 ) {
4710
+ /* We need to create a temporary bound method as argument
4711
+ for profiling.
4712
+
4713
+ If nargs == 0, then this cannot work because we have no
4714
+ "self". In any case, the call itself would raise
4715
+ TypeError (foo needs an argument), so we just skip
4716
+ profiling. */
4717
+ PyObject * self = * (argv ++ );
4718
+ nargs -- ;
4719
+ func = Py_TYPE (func )-> tp_descr_get (func , self , (PyObject * )Py_TYPE (self ));
4720
+ if (func == NULL ) {
4721
+ return NULL ;
4722
+ }
4723
+ C_TRACE (result , _PyCFunction_FastCallDict (func ,
4724
+ argv , nargs ,
4725
+ kwdict ));
4726
+ Py_DECREF (func );
4727
+ return result ;
4728
+ }
4729
+ return PyObject_Call (func , args , kwdict );
4730
+ }
4731
+
4656
4732
4657
4733
/* Issue #29227: Inline call_function() into _PyEval_EvalFrameDefault()
4658
4734
to reduce the stack consumption. */
4659
4735
Py_LOCAL_INLINE (PyObject * ) _Py_HOT_FUNCTION
4660
- call_function (PyObject * * * pp_stack , Py_ssize_t oparg , PyObject * kwnames )
4736
+ call_function (PyThreadState * tstate , PyObject * * * pp_stack , Py_ssize_t oparg , PyObject * kwnames )
4661
4737
{
4662
- PyObject * * pfunc = (* pp_stack ) - oparg - 1 ;
4738
+ PyObject * * argv = (* pp_stack ) - oparg ;
4739
+ PyObject * * pfunc = argv - 1 ;
4663
4740
PyObject * func = * pfunc ;
4664
4741
PyObject * x , * w ;
4665
4742
Py_ssize_t nkwargs = (kwnames == NULL ) ? 0 : PyTuple_GET_SIZE (kwnames );
4666
4743
Py_ssize_t nargs = oparg - nkwargs ;
4667
- PyObject * * stack = (* pp_stack ) - nargs - nkwargs ;
4668
4744
4669
- /* Always dispatch PyCFunction first, because these are
4670
- presumed to be the most frequent callable object.
4671
- */
4672
- if (PyCFunction_Check (func )) {
4673
- PyThreadState * tstate = _PyThreadState_GET ();
4674
- C_TRACE (x , _PyCFunction_FastCallKeywords (func , stack , nargs , kwnames ));
4745
+ if (tstate -> use_tracing ) {
4746
+ x = profile_fastcall (tstate , func , argv , nargs , kwnames );
4747
+ }
4748
+ else if (PyCFunction_Check (func )) {
4749
+ x = _PyCFunction_FastCallKeywords (func , argv , nargs , kwnames );
4675
4750
}
4676
4751
else if (Py_TYPE (func ) == & PyMethodDescr_Type ) {
4677
- PyThreadState * tstate = _PyThreadState_GET ();
4678
- if (nargs > 0 && tstate -> use_tracing ) {
4679
- /* We need to create a temporary bound method as argument
4680
- for profiling.
4681
-
4682
- If nargs == 0, then this cannot work because we have no
4683
- "self". In any case, the call itself would raise
4684
- TypeError (foo needs an argument), so we just skip
4685
- profiling. */
4686
- PyObject * self = stack [0 ];
4687
- func = Py_TYPE (func )-> tp_descr_get (func , self , (PyObject * )Py_TYPE (self ));
4688
- if (func != NULL ) {
4689
- C_TRACE (x , _PyCFunction_FastCallKeywords (func ,
4690
- stack + 1 , nargs - 1 ,
4691
- kwnames ));
4692
- Py_DECREF (func );
4693
- }
4694
- else {
4695
- x = NULL ;
4696
- }
4697
- }
4698
- else {
4699
- x = _PyMethodDescr_FastCallKeywords (func , stack , nargs , kwnames );
4700
- }
4752
+ x = _PyMethodDescr_FastCallKeywords (func , argv , nargs , kwnames );
4701
4753
}
4702
4754
else {
4703
- if (PyMethod_Check (func ) && PyMethod_GET_SELF ( func ) != NULL ) {
4755
+ if (PyMethod_Check (func )) {
4704
4756
/* Optimize access to bound methods. Reuse the Python stack
4705
4757
to pass 'self' as the first argument, replace 'func'
4706
4758
with 'self'. It avoids the creation of a new temporary tuple
@@ -4712,17 +4764,17 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
4712
4764
Py_INCREF (func );
4713
4765
Py_SETREF (* pfunc , self );
4714
4766
nargs ++ ;
4715
- stack -- ;
4767
+ argv -- ;
4716
4768
}
4717
4769
else {
4718
4770
Py_INCREF (func );
4719
4771
}
4720
4772
4721
4773
if (PyFunction_Check (func )) {
4722
- x = _PyFunction_FastCallKeywords (func , stack , nargs , kwnames );
4774
+ x = _PyFunction_FastCallKeywords (func , argv , nargs , kwnames );
4723
4775
}
4724
4776
else {
4725
- x = _PyObject_FastCallKeywords (func , stack , nargs , kwnames );
4777
+ x = _PyObject_FastCallKeywords (func , argv , nargs , kwnames );
4726
4778
}
4727
4779
Py_DECREF (func );
4728
4780
}
@@ -4738,43 +4790,6 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
4738
4790
return x ;
4739
4791
}
4740
4792
4741
- static PyObject *
4742
- do_call_core (PyObject * func , PyObject * callargs , PyObject * kwdict )
4743
- {
4744
- PyObject * result ;
4745
-
4746
- if (PyCFunction_Check (func )) {
4747
- PyThreadState * tstate = _PyThreadState_GET ();
4748
- C_TRACE (result , PyCFunction_Call (func , callargs , kwdict ));
4749
- return result ;
4750
- }
4751
- else if (Py_TYPE (func ) == & PyMethodDescr_Type ) {
4752
- PyThreadState * tstate = _PyThreadState_GET ();
4753
- Py_ssize_t nargs = PyTuple_GET_SIZE (callargs );
4754
- if (nargs > 0 && tstate -> use_tracing ) {
4755
- /* We need to create a temporary bound method as argument
4756
- for profiling.
4757
-
4758
- If nargs == 0, then this cannot work because we have no
4759
- "self". In any case, the call itself would raise
4760
- TypeError (foo needs an argument), so we just skip
4761
- profiling. */
4762
- PyObject * self = PyTuple_GET_ITEM (callargs , 0 );
4763
- func = Py_TYPE (func )-> tp_descr_get (func , self , (PyObject * )Py_TYPE (self ));
4764
- if (func == NULL ) {
4765
- return NULL ;
4766
- }
4767
-
4768
- C_TRACE (result , _PyCFunction_FastCallDict (func ,
4769
- & _PyTuple_ITEMS (callargs )[1 ],
4770
- nargs - 1 ,
4771
- kwdict ));
4772
- Py_DECREF (func );
4773
- return result ;
4774
- }
4775
- }
4776
- return PyObject_Call (func , callargs , kwdict );
4777
- }
4778
4793
4779
4794
/* Extract a slice index from a PyLong or an object with the
4780
4795
nb_index slot defined, and store in *pi.
0 commit comments