Skip to content

Commit 7aca84e

Browse files
authored
GH-117224: Move the body of a few large-ish micro-ops into helper functions (GH-122601)
1 parent 498376d commit 7aca84e

File tree

5 files changed

+163
-335
lines changed

5 files changed

+163
-335
lines changed

Include/internal/pycore_ceval.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,10 @@ PyAPI_FUNC(PyObject **) _PyObjectArray_FromStackRefArray(_PyStackRef *input, Py_
270270

271271
PyAPI_FUNC(void) _PyObjectArray_Free(PyObject **array, PyObject **scratch);
272272

273+
PyAPI_FUNC(PyObject *) _PyEval_GetANext(PyObject *aiter);
274+
PyAPI_FUNC(PyObject *) _PyEval_LoadGlobal(PyObject *globals, PyObject *builtins, PyObject *name);
275+
PyAPI_FUNC(PyObject *) _PyEval_GetAwaitable(PyObject *iterable, int oparg);
276+
PyAPI_FUNC(PyObject *) _PyEval_LoadName(PyThreadState *tstate, _PyInterpreterFrame *frame, PyObject *name);
273277

274278
/* Bits that can be set in PyThreadState.eval_breaker */
275279
#define _PY_GIL_DROP_REQUEST_BIT (1U << 0)

Python/bytecodes.c

Lines changed: 8 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,77 +1010,16 @@ dummy_func(
10101010
}
10111011

10121012
inst(GET_ANEXT, (aiter -- aiter, awaitable)) {
1013-
unaryfunc getter = NULL;
1014-
PyObject *next_iter = NULL;
1015-
PyObject *awaitable_o;
1016-
PyObject *aiter_o = PyStackRef_AsPyObjectBorrow(aiter);
1017-
PyTypeObject *type = Py_TYPE(aiter_o);
1018-
1019-
if (PyAsyncGen_CheckExact(aiter_o)) {
1020-
awaitable_o = type->tp_as_async->am_anext(aiter_o);
1021-
if (awaitable_o == NULL) {
1022-
ERROR_NO_POP();
1023-
}
1024-
} else {
1025-
if (type->tp_as_async != NULL){
1026-
getter = type->tp_as_async->am_anext;
1027-
}
1028-
1029-
if (getter != NULL) {
1030-
next_iter = (*getter)(aiter_o);
1031-
if (next_iter == NULL) {
1032-
ERROR_NO_POP();
1033-
}
1034-
}
1035-
else {
1036-
_PyErr_Format(tstate, PyExc_TypeError,
1037-
"'async for' requires an iterator with "
1038-
"__anext__ method, got %.100s",
1039-
type->tp_name);
1040-
ERROR_NO_POP();
1041-
}
1042-
1043-
awaitable_o = _PyCoro_GetAwaitableIter(next_iter);
1044-
if (awaitable_o == NULL) {
1045-
_PyErr_FormatFromCause(
1046-
PyExc_TypeError,
1047-
"'async for' received an invalid object "
1048-
"from __anext__: %.100s",
1049-
Py_TYPE(next_iter)->tp_name);
1050-
1051-
Py_DECREF(next_iter);
1052-
ERROR_NO_POP();
1053-
} else {
1054-
Py_DECREF(next_iter);
1055-
}
1013+
PyObject *awaitable_o = _PyEval_GetANext(PyStackRef_AsPyObjectBorrow(aiter));
1014+
if (awaitable_o == NULL) {
1015+
ERROR_NO_POP();
10561016
}
10571017
awaitable = PyStackRef_FromPyObjectSteal(awaitable_o);
10581018
}
10591019

10601020
inst(GET_AWAITABLE, (iterable -- iter)) {
1061-
PyObject *iter_o = _PyCoro_GetAwaitableIter(PyStackRef_AsPyObjectBorrow(iterable));
1062-
1063-
if (iter_o == NULL) {
1064-
_PyEval_FormatAwaitableError(tstate,
1065-
Py_TYPE(PyStackRef_AsPyObjectBorrow(iterable)), oparg);
1066-
}
1067-
1021+
PyObject *iter_o = _PyEval_GetAwaitable(PyStackRef_AsPyObjectBorrow(iterable), oparg);
10681022
DECREF_INPUTS();
1069-
1070-
if (iter_o != NULL && PyCoro_CheckExact(iter_o)) {
1071-
PyObject *yf = _PyGen_yf((PyGenObject*)iter_o);
1072-
if (yf != NULL) {
1073-
/* `iter` is a coroutine object that is being
1074-
awaited, `yf` is a pointer to the current awaitable
1075-
being awaited on. */
1076-
Py_DECREF(yf);
1077-
Py_CLEAR(iter_o);
1078-
_PyErr_SetString(tstate, PyExc_RuntimeError,
1079-
"coroutine is being awaited already");
1080-
/* The code below jumps to `error` if `iter` is NULL. */
1081-
}
1082-
}
1083-
10841023
ERROR_IF(iter_o == NULL, error);
10851024
iter = PyStackRef_FromPyObjectSteal(iter_o);
10861025
}
@@ -1527,27 +1466,9 @@ dummy_func(
15271466
}
15281467

15291468
inst(LOAD_NAME, (-- v)) {
1530-
PyObject *v_o;
1531-
PyObject *mod_or_class_dict = LOCALS();
1532-
if (mod_or_class_dict == NULL) {
1533-
_PyErr_SetString(tstate, PyExc_SystemError,
1534-
"no locals found");
1535-
ERROR_IF(true, error);
1536-
}
15371469
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
1538-
ERROR_IF(PyMapping_GetOptionalItem(mod_or_class_dict, name, &v_o) < 0, error);
1539-
if (v_o == NULL) {
1540-
ERROR_IF(PyDict_GetItemRef(GLOBALS(), name, &v_o) < 0, error);
1541-
if (v_o == NULL) {
1542-
ERROR_IF(PyMapping_GetOptionalItem(BUILTINS(), name, &v_o) < 0, error);
1543-
if (v_o == NULL) {
1544-
_PyEval_FormatExcCheckArg(
1545-
tstate, PyExc_NameError,
1546-
NAME_ERROR_MSG, name);
1547-
ERROR_IF(true, error);
1548-
}
1549-
}
1550-
}
1470+
PyObject *v_o = _PyEval_LoadName(tstate, frame, name);
1471+
ERROR_IF(v_o == NULL, error);
15511472
v = PyStackRef_FromPyObjectSteal(v_o);
15521473
}
15531474

@@ -1571,38 +1492,8 @@ dummy_func(
15711492

15721493
op(_LOAD_GLOBAL, ( -- res, null if (oparg & 1))) {
15731494
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1);
1574-
PyObject *res_o;
1575-
if (PyDict_CheckExact(GLOBALS())
1576-
&& PyDict_CheckExact(BUILTINS()))
1577-
{
1578-
res_o = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(),
1579-
(PyDictObject *)BUILTINS(),
1580-
name);
1581-
if (res_o == NULL) {
1582-
if (!_PyErr_Occurred(tstate)) {
1583-
/* _PyDict_LoadGlobal() returns NULL without raising
1584-
* an exception if the key doesn't exist */
1585-
_PyEval_FormatExcCheckArg(tstate, PyExc_NameError,
1586-
NAME_ERROR_MSG, name);
1587-
}
1588-
ERROR_IF(true, error);
1589-
}
1590-
}
1591-
else {
1592-
/* Slow-path if globals or builtins is not a dict */
1593-
/* namespace 1: globals */
1594-
ERROR_IF(PyMapping_GetOptionalItem(GLOBALS(), name, &res_o) < 0, error);
1595-
if (res_o == NULL) {
1596-
/* namespace 2: builtins */
1597-
ERROR_IF(PyMapping_GetOptionalItem(BUILTINS(), name, &res_o) < 0, error);
1598-
if (res_o == NULL) {
1599-
_PyEval_FormatExcCheckArg(
1600-
tstate, PyExc_NameError,
1601-
NAME_ERROR_MSG, name);
1602-
ERROR_IF(true, error);
1603-
}
1604-
}
1605-
}
1495+
PyObject *res_o = _PyEval_LoadGlobal(GLOBALS(), BUILTINS(), name);
1496+
ERROR_IF(res_o == NULL, error);
16061497
null = PyStackRef_NULL;
16071498
res = PyStackRef_FromPyObjectSteal(res_o);
16081499
}

Python/ceval.c

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,7 @@ _PyObjectArray_Free(PyObject **array, PyObject **scratch)
720720
}
721721
}
722722

723+
723724
/* _PyEval_EvalFrameDefault() is a *big* function,
724725
* so consume 3 units of C stack */
725726
#define PY_EVAL_C_STACK_UNITS 2
@@ -3031,3 +3032,137 @@ void Py_LeaveRecursiveCall(void)
30313032
{
30323033
_Py_LeaveRecursiveCall();
30333034
}
3035+
3036+
PyObject *
3037+
_PyEval_GetANext(PyObject *aiter)
3038+
{
3039+
unaryfunc getter = NULL;
3040+
PyObject *next_iter = NULL;
3041+
PyTypeObject *type = Py_TYPE(aiter);
3042+
if (PyAsyncGen_CheckExact(aiter)) {
3043+
return type->tp_as_async->am_anext(aiter);
3044+
}
3045+
if (type->tp_as_async != NULL){
3046+
getter = type->tp_as_async->am_anext;
3047+
}
3048+
3049+
if (getter != NULL) {
3050+
next_iter = (*getter)(aiter);
3051+
if (next_iter == NULL) {
3052+
return NULL;
3053+
}
3054+
}
3055+
else {
3056+
PyErr_Format(PyExc_TypeError,
3057+
"'async for' requires an iterator with "
3058+
"__anext__ method, got %.100s",
3059+
type->tp_name);
3060+
return NULL;
3061+
}
3062+
3063+
PyObject *awaitable = _PyCoro_GetAwaitableIter(next_iter);
3064+
if (awaitable == NULL) {
3065+
_PyErr_FormatFromCause(
3066+
PyExc_TypeError,
3067+
"'async for' received an invalid object "
3068+
"from __anext__: %.100s",
3069+
Py_TYPE(next_iter)->tp_name);
3070+
}
3071+
Py_DECREF(next_iter);
3072+
return awaitable;
3073+
}
3074+
3075+
PyObject *
3076+
_PyEval_LoadGlobal(PyObject *globals, PyObject *builtins, PyObject *name)
3077+
{
3078+
PyObject *res;
3079+
if (PyDict_CheckExact(globals) && PyDict_CheckExact(builtins)) {
3080+
res = _PyDict_LoadGlobal((PyDictObject *)globals,
3081+
(PyDictObject *)builtins,
3082+
name);
3083+
if (res == NULL && !PyErr_Occurred()) {
3084+
/* _PyDict_LoadGlobal() returns NULL without raising
3085+
* an exception if the key doesn't exist */
3086+
_PyEval_FormatExcCheckArg(PyThreadState_GET(), PyExc_NameError,
3087+
NAME_ERROR_MSG, name);
3088+
}
3089+
}
3090+
else {
3091+
/* Slow-path if globals or builtins is not a dict */
3092+
/* namespace 1: globals */
3093+
if (PyMapping_GetOptionalItem(globals, name, &res) < 0) {
3094+
return NULL;
3095+
}
3096+
if (res == NULL) {
3097+
/* namespace 2: builtins */
3098+
if (PyMapping_GetOptionalItem(builtins, name, &res) < 0) {
3099+
return NULL;
3100+
}
3101+
if (res == NULL) {
3102+
_PyEval_FormatExcCheckArg(
3103+
PyThreadState_GET(), PyExc_NameError,
3104+
NAME_ERROR_MSG, name);
3105+
}
3106+
}
3107+
}
3108+
return res;
3109+
}
3110+
3111+
PyObject *
3112+
_PyEval_GetAwaitable(PyObject *iterable, int oparg)
3113+
{
3114+
PyObject *iter = _PyCoro_GetAwaitableIter(iterable);
3115+
3116+
if (iter == NULL) {
3117+
_PyEval_FormatAwaitableError(PyThreadState_GET(),
3118+
Py_TYPE(iterable), oparg);
3119+
}
3120+
else if (PyCoro_CheckExact(iter)) {
3121+
PyObject *yf = _PyGen_yf((PyGenObject*)iter);
3122+
if (yf != NULL) {
3123+
/* `iter` is a coroutine object that is being
3124+
awaited, `yf` is a pointer to the current awaitable
3125+
being awaited on. */
3126+
Py_DECREF(yf);
3127+
Py_CLEAR(iter);
3128+
_PyErr_SetString(PyThreadState_GET(), PyExc_RuntimeError,
3129+
"coroutine is being awaited already");
3130+
}
3131+
}
3132+
return iter;
3133+
}
3134+
3135+
PyObject *
3136+
_PyEval_LoadName(PyThreadState *tstate, _PyInterpreterFrame *frame, PyObject *name)
3137+
{
3138+
3139+
PyObject *value;
3140+
if (frame->f_locals == NULL) {
3141+
_PyErr_SetString(tstate, PyExc_SystemError,
3142+
"no locals found");
3143+
return NULL;
3144+
}
3145+
if (PyMapping_GetOptionalItem(frame->f_locals, name, &value) < 0) {
3146+
return NULL;
3147+
}
3148+
if (value != NULL) {
3149+
return value;
3150+
}
3151+
if (PyDict_GetItemRef(frame->f_globals, name, &value) < 0) {
3152+
return NULL;
3153+
}
3154+
if (value != NULL) {
3155+
return value;
3156+
}
3157+
if (PyMapping_GetOptionalItem(frame->f_builtins, name, &value) < 0) {
3158+
return NULL;
3159+
}
3160+
if (value == NULL) {
3161+
_PyEval_FormatExcCheckArg(
3162+
tstate, PyExc_NameError,
3163+
NAME_ERROR_MSG, name);
3164+
}
3165+
return value;
3166+
}
3167+
3168+

0 commit comments

Comments
 (0)