@@ -918,6 +918,19 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
918
918
return f ;
919
919
}
920
920
921
+ int
922
+ _PyFrame_OpAlreadyRan (PyFrameObject * f , int opcode , int oparg )
923
+ {
924
+ const _Py_CODEUNIT * code =
925
+ (const _Py_CODEUNIT * )PyBytes_AS_STRING (f -> f_code -> co_code );
926
+ for (int i = 0 ; i < f -> f_lasti ; i ++ ) {
927
+ if (_Py_OPCODE (code [i ]) == opcode && _Py_OPARG (code [i ]) == oparg ) {
928
+ return 1 ;
929
+ }
930
+ }
931
+ return 0 ;
932
+ }
933
+
921
934
int
922
935
PyFrame_FastToLocalsWithError (PyFrameObject * f )
923
936
{
@@ -966,32 +979,40 @@ PyFrame_FastToLocalsWithError(PyFrameObject *f)
966
979
967
980
PyObject * name = PyTuple_GET_ITEM (co -> co_localsplusnames , i );
968
981
PyObject * value = fast [i ];
969
- if (kind & (CO_FAST_CELL | CO_FAST_FREE )) {
982
+ int cellargoffset = CO_CELL_NOT_AN_ARG ;
983
+ if (co -> co_cell2arg != NULL ) {
984
+ cellargoffset = co -> co_cell2arg [i - co -> co_nlocals ];
985
+ }
986
+ if (kind & CO_FAST_FREE ) {
987
+ // The cell was set by _PyEval_MakeFrameVector() from
988
+ // the function's closure.
989
+ assert (value != NULL && PyCell_Check (value ));
990
+ value = PyCell_GET (value );
991
+ }
992
+ else if (kind & CO_FAST_CELL ) {
993
+ // Note that no *_DEREF ops can happen before MAKE_CELL
994
+ // executes. So there's no need to duplicate the work
995
+ // that MAKE_CELL would otherwise do later, if it hasn't
996
+ // run yet.
970
997
if (value != NULL ) {
971
- // MAKE_CELL must have executed already.
972
- assert (PyCell_Check (value ));
973
- value = PyCell_GET (value );
998
+ if (PyCell_Check (value ) &&
999
+ _PyFrame_OpAlreadyRan (f , MAKE_CELL , i )) {
1000
+ // (likely) MAKE_CELL must have executed already.
1001
+ value = PyCell_GET (value );
1002
+ }
1003
+ // (unlikely) Otherwise it must be an initial value set
1004
+ // by an earlier call to PyFrame_FastToLocals().
974
1005
}
975
1006
else {
976
- // MAKE_CELL hasn't executed yet. (This is unlikely.)
977
- PyObject * cell = PyCell_New (NULL );
978
- if (cell == NULL ) {
979
- PyErr_Clear ();
980
- }
981
- else {
982
- if (co -> co_cell2arg != NULL ) {
983
- int argoffset = co -> co_cell2arg [i - co -> co_nlocals ];
984
- if (argoffset != CO_CELL_NOT_AN_ARG ) {
985
- // It will have been set in initialize_locals().
986
- value = fast [argoffset ];
987
- assert (value != NULL );
988
- Py_INCREF (value );
989
- PyCell_SET (cell , value );
990
- // Clear the arg slot.
991
- Py_SETREF (fast [argoffset ], NULL );
992
- }
993
- }
994
- fast [i ] = cell ;
1007
+ // (unlikely) MAKE_CELL hasn't executed yet.
1008
+ if (cellargoffset != CO_CELL_NOT_AN_ARG ) {
1009
+ // It is an arg that escapes into an inner
1010
+ // function so we use the initial value that
1011
+ // was already set by _PyEval_MakeFrameVector().
1012
+ // Normally the arg value would always be set.
1013
+ // However, it can be NULL if it was deleted via
1014
+ // PyFrame_LocalsToFast().
1015
+ value = fast [cellargoffset ];
995
1016
}
996
1017
}
997
1018
}
@@ -1064,36 +1085,66 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
1064
1085
}
1065
1086
}
1066
1087
PyObject * oldvalue = fast [i ];
1067
- if (kind & (CO_FAST_CELL | CO_FAST_FREE )) {
1068
- if (oldvalue != NULL ) {
1069
- // MAKE_CELL must have executed already.
1088
+ int cellargoffset = CO_CELL_NOT_AN_ARG ;
1089
+ if (co -> co_cell2arg != NULL ) {
1090
+ cellargoffset = co -> co_cell2arg [i - co -> co_nlocals ];
1091
+ }
1092
+ PyObject * cell = NULL ;
1093
+ if (kind == CO_FAST_FREE ) {
1094
+ // The cell was cell by _PyEval_MakeFrameVector() from
1095
+ // the function's closure.
1096
+ assert (oldvalue != NULL && PyCell_Check (oldvalue ));
1097
+ cell = oldvalue ;
1098
+ }
1099
+ else if (kind & CO_FAST_CELL && oldvalue != NULL ) {
1100
+ if (cellargoffset != CO_CELL_NOT_AN_ARG ) {
1101
+ // (likely) MAKE_CELL must have executed already.
1102
+ // It's the cell for an arg.
1070
1103
assert (PyCell_Check (oldvalue ));
1071
- Py_XDECREF (PyCell_GET (oldvalue ));
1072
- Py_XINCREF (value );
1073
- PyCell_SET (oldvalue , value );
1104
+ cell = oldvalue ;
1074
1105
}
1075
1106
else {
1076
- // MAKE_CELL hasn't executed yet. (This is unlikely.)
1077
- PyObject * cell = PyCell_New ( value );
1078
- if ( cell == NULL ) {
1079
- PyErr_Clear () ;
1107
+ if ( PyCell_Check ( oldvalue ) &&
1108
+ _PyFrame_OpAlreadyRan ( f , MAKE_CELL , i )) {
1109
+ // (likely) MAKE_CELL must have executed already.
1110
+ cell = oldvalue ;
1080
1111
}
1081
- else {
1082
- fast [i ] = cell ;
1083
- // Clear the corresponding arg if there is one.
1084
- if (co -> co_cell2arg != NULL ) {
1085
- int argoffset = co -> co_cell2arg [i - co -> co_nlocals ];
1086
- if (argoffset != CO_CELL_NOT_AN_ARG ) {
1087
- // It will have been set in initialize_locals().
1088
- assert (fast [argoffset ] != NULL );
1089
- Py_SETREF (fast [argoffset ], NULL );
1090
- }
1091
- }
1112
+ // (unlikely) Otherwise, it must have been set to some
1113
+ // initial value by an earlier call to PyFrame_LocalsToFast().
1114
+ }
1115
+ }
1116
+ if (cell != NULL ) {
1117
+ PyObject * oldvalue = PyCell_GET (cell );
1118
+ if (value != oldvalue ) {
1119
+ Py_XDECREF (oldvalue );
1120
+ Py_XINCREF (value );
1121
+ PyCell_SET (cell , value );
1122
+ }
1123
+ }
1124
+ else {
1125
+ int offset = i ;
1126
+ if (kind & CO_FAST_CELL ) {
1127
+ // (unlikely) MAKE_CELL hasn't executed yet.
1128
+ // Note that there is no need to create the cell that
1129
+ // MAKE_CELL would otherwise create later, since no
1130
+ // *_DEREF ops can happen before MAKE_CELL has run.
1131
+ if (cellargoffset != CO_CELL_NOT_AN_ARG ) {
1132
+ // It's the cell for an arg.
1133
+ // Replace the initial value that was set by
1134
+ // _PyEval_MakeFrameVector().
1135
+ // Normally the arg value would always be set.
1136
+ // However, it can be NULL if it was deleted
1137
+ // via an earlier PyFrame_LocalsToFast() call.
1138
+ offset = cellargoffset ;
1139
+ oldvalue = fast [offset ];
1092
1140
}
1141
+ // Otherwise set an initial value for MAKE_CELL to use
1142
+ // when it runs later.
1143
+ }
1144
+ if (value != oldvalue ) {
1145
+ Py_XINCREF (value );
1146
+ Py_XSETREF (fast [offset ], value );
1093
1147
}
1094
- } else if (fast [i ] != value ) {
1095
- Py_XINCREF (value );
1096
- Py_XSETREF (oldvalue , value );
1097
1148
}
1098
1149
Py_XDECREF (value );
1099
1150
}
0 commit comments