@@ -149,6 +149,7 @@ typedef struct {
149149 PyTypeObject * TaskType ;
150150
151151 PyObject * asyncio_mod ;
152+ PyObject * call_soon_private_name ;
152153 PyObject * context_kwname ;
153154
154155 /* WeakSet containing scheduled 3rd party tasks which don't
@@ -370,27 +371,78 @@ call_soon(asyncio_state *state, PyObject *loop, PyObject *func, PyObject *arg,
370371 PyObject * ctx )
371372{
372373 state -> bench_call_soon_calls ++ ;
373- PyObject * handle ;
374+ PyObject * handle = NULL ;
374375
375- if ( ctx == NULL ) {
376- PyObject * stack [] = { loop , func , arg } ;
377- size_t nargsf = 3 | PY_VECTORCALL_ARGUMENTS_OFFSET ;
378- handle = PyObject_VectorcallMethod ( & _Py_ID ( call_soon ), stack , nargsf , NULL ) ;
376+ PyTypeObject * loop_type = Py_TYPE ( loop );
377+ PyObject * module_name = PyDict_GetItemWithError ( loop_type -> tp_dict , & _Py_ID ( __module__ )) ;
378+ if ( module_name == NULL && PyErr_Occurred ()) {
379+ return -1 ;
379380 }
380- else {
381- /* All refs in 'stack' are borrowed. */
382- PyObject * stack [4 ];
383- size_t nargs = 2 ;
384- stack [0 ] = loop ;
385- stack [1 ] = func ;
381+
382+ int use_fastpath = (
383+ module_name != NULL &&
384+ PyUnicode_Check (module_name ) &&
385+ (
386+ (strcmp (loop_type -> tp_name , "BaseEventLoop" ) == 0 &&
387+ PyUnicode_CompareWithASCIIString (module_name , "asyncio.base_events" ) == 0 ) ||
388+ (strcmp (loop_type -> tp_name , "BaseSelectorEventLoop" ) == 0 &&
389+ PyUnicode_CompareWithASCIIString (module_name , "asyncio.selector_events" ) == 0 ) ||
390+ (strcmp (loop_type -> tp_name , "_UnixSelectorEventLoop" ) == 0 &&
391+ PyUnicode_CompareWithASCIIString (module_name , "asyncio.unix_events" ) == 0 ) ||
392+ (strcmp (loop_type -> tp_name , "_WindowsSelectorEventLoop" ) == 0 &&
393+ PyUnicode_CompareWithASCIIString (module_name , "asyncio.windows_events" ) == 0 ) ||
394+ (strcmp (loop_type -> tp_name , "BaseProactorEventLoop" ) == 0 &&
395+ PyUnicode_CompareWithASCIIString (module_name , "asyncio.proactor_events" ) == 0 ) ||
396+ (strcmp (loop_type -> tp_name , "ProactorEventLoop" ) == 0 &&
397+ PyUnicode_CompareWithASCIIString (module_name , "asyncio.windows_events" ) == 0 )
398+ )
399+ );
400+
401+ if (use_fastpath ) {
402+ PyObject * args ;
403+ if (arg == NULL ) {
404+ args = Py_GetConstantBorrowed (Py_CONSTANT_EMPTY_TUPLE );
405+ }
406+ else {
407+ args = PyTuple_Pack (1 , arg );
408+ if (args == NULL ) {
409+ return -1 ;
410+ }
411+ }
412+
413+ PyObject * stack [] = {loop , func , args , ctx ? ctx : Py_None };
414+ size_t nargsf = 4 | PY_VECTORCALL_ARGUMENTS_OFFSET ;
415+ handle = PyObject_VectorcallMethod (state -> call_soon_private_name , stack ,
416+ nargsf , NULL );
386417 if (arg != NULL ) {
387- stack [2 ] = arg ;
388- nargs ++ ;
418+ Py_DECREF (args );
419+ }
420+
421+ if (handle == NULL && PyErr_ExceptionMatches (PyExc_AttributeError )) {
422+ PyErr_Clear ();
423+ }
424+ }
425+
426+ if (handle == NULL ) {
427+ if (ctx == NULL ) {
428+ PyObject * stack [] = {loop , func , arg };
429+ size_t nargsf = 3 | PY_VECTORCALL_ARGUMENTS_OFFSET ;
430+ handle = PyObject_VectorcallMethod (& _Py_ID (call_soon ), stack , nargsf , NULL );
431+ }
432+ else {
433+ PyObject * stack [4 ];
434+ size_t nargs = 2 ;
435+ stack [0 ] = loop ;
436+ stack [1 ] = func ;
437+ if (arg != NULL ) {
438+ stack [2 ] = arg ;
439+ nargs ++ ;
440+ }
441+ stack [nargs ] = (PyObject * )ctx ;
442+ size_t nargsf = nargs | PY_VECTORCALL_ARGUMENTS_OFFSET ;
443+ handle = PyObject_VectorcallMethod (& _Py_ID (call_soon ), stack , nargsf ,
444+ state -> context_kwname );
389445 }
390- stack [nargs ] = (PyObject * )ctx ;
391- size_t nargsf = nargs | PY_VECTORCALL_ARGUMENTS_OFFSET ;
392- handle = PyObject_VectorcallMethod (& _Py_ID (call_soon ), stack , nargsf ,
393- state -> context_kwname );
394446 }
395447
396448 if (handle == NULL ) {
@@ -4204,6 +4256,7 @@ module_traverse(PyObject *mod, visitproc visit, void *arg)
42044256 Py_VISIT (state -> TaskType );
42054257
42064258 Py_VISIT (state -> asyncio_mod );
4259+ Py_VISIT (state -> call_soon_private_name );
42074260 Py_VISIT (state -> traceback_extract_stack );
42084261 Py_VISIT (state -> asyncio_future_repr_func );
42094262 Py_VISIT (state -> asyncio_get_event_loop );
@@ -4234,6 +4287,7 @@ module_clear(PyObject *mod)
42344287 Py_CLEAR (state -> TaskType );
42354288
42364289 Py_CLEAR (state -> asyncio_mod );
4290+ Py_CLEAR (state -> call_soon_private_name );
42374291 Py_CLEAR (state -> traceback_extract_stack );
42384292 Py_CLEAR (state -> asyncio_future_repr_func );
42394293 Py_CLEAR (state -> asyncio_get_event_loop );
@@ -4285,6 +4339,11 @@ module_init(asyncio_state *state)
42854339 goto fail ;
42864340 }
42874341
4342+ state -> call_soon_private_name = PyUnicode_InternFromString ("_call_soon" );
4343+ if (state -> call_soon_private_name == NULL ) {
4344+ goto fail ;
4345+ }
4346+
42884347#define WITH_MOD (NAME ) \
42894348 Py_CLEAR(module); \
42904349 module = PyImport_ImportModule(NAME); \
0 commit comments