Use critical sections to lock around accesses to cell contents. The critical sections are no-ops in the default (with GIL) build.
--- /dev/null
+#ifndef Py_INTERNAL_CELL_H
+#define Py_INTERNAL_CELL_H
+
+#include "pycore_critical_section.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef Py_BUILD_CORE
+# error "this header requires Py_BUILD_CORE define"
+#endif
+
+// Sets the cell contents to `value` and return previous contents. Steals a
+// reference to `value`.
+static inline PyObject *
+PyCell_SwapTakeRef(PyCellObject *cell, PyObject *value)
+{
+ PyObject *old_value;
+ Py_BEGIN_CRITICAL_SECTION(cell);
+ old_value = cell->ob_ref;
+ cell->ob_ref = value;
+ Py_END_CRITICAL_SECTION();
+ return old_value;
+}
+
+static inline void
+PyCell_SetTakeRef(PyCellObject *cell, PyObject *value)
+{
+ PyObject *old_value = PyCell_SwapTakeRef(cell, value);
+ Py_XDECREF(old_value);
+}
+
+// Gets the cell contents. Returns a new reference.
+static inline PyObject *
+PyCell_GetRef(PyCellObject *cell)
+{
+ PyObject *res;
+ Py_BEGIN_CRITICAL_SECTION(cell);
+ res = Py_XNewRef(cell->ob_ref);
+ Py_END_CRITICAL_SECTION();
+ return res;
+}
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_INTERNAL_CELL_H */
$(srcdir)/Include/internal/pycore_bytesobject.h \
$(srcdir)/Include/internal/pycore_call.h \
$(srcdir)/Include/internal/pycore_capsule.h \
+ $(srcdir)/Include/internal/pycore_cell.h \
$(srcdir)/Include/internal/pycore_ceval.h \
$(srcdir)/Include/internal/pycore_ceval_state.h \
$(srcdir)/Include/internal/pycore_code.h \
/* Cell object implementation */
#include "Python.h"
+#include "pycore_cell.h" // PyCell_GetRef()
#include "pycore_modsupport.h" // _PyArg_NoKeywords()
#include "pycore_object.h"
PyErr_BadInternalCall();
return NULL;
}
- PyObject *value = PyCell_GET(op);
- return Py_XNewRef(value);
+ return PyCell_GetRef((PyCellObject *)op);
}
int
PyErr_BadInternalCall();
return -1;
}
- PyObject *old_value = PyCell_GET(op);
- PyCell_SET(op, Py_XNewRef(value));
- Py_XDECREF(old_value);
+ PyCell_SetTakeRef((PyCellObject *)op, Py_XNewRef(value));
return 0;
}
<ClInclude Include="..\Include\internal\pycore_bytesobject.h" />
<ClInclude Include="..\Include\internal\pycore_call.h" />
<ClInclude Include="..\Include\internal\pycore_capsule.h" />
+ <ClInclude Include="..\Include\internal\pycore_cell.h" />
<ClInclude Include="..\Include\internal\pycore_ceval.h" />
<ClInclude Include="..\Include\internal\pycore_ceval_state.h" />
<ClInclude Include="..\Include\internal\pycore_cfg.h" />
<ClInclude Include="..\Include\internal\pycore_capsule.h">
<Filter>Include\internal</Filter>
</ClInclude>
+ <ClInclude Include="..\Include\internal\pycore_cell.h">
+ <Filter>Include\internal</Filter>
+ </ClInclude>
<ClInclude Include="..\Include\internal\pycore_ceval.h">
<Filter>Include\internal</Filter>
</ClInclude>
#include "Python.h"
#include "pycore_abstract.h" // _PyIndex_Check()
+#include "pycore_cell.h" // PyCell_GetRef()
#include "pycore_code.h"
#include "pycore_emscripten_signal.h" // _Py_CHECK_EMSCRIPTEN_SIGNALS
#include "pycore_function.h"
inst(DELETE_DEREF, (--)) {
PyObject *cell = GETLOCAL(oparg);
- PyObject *oldobj = PyCell_GET(cell);
// Can't use ERROR_IF here.
// Fortunately we don't need its superpower.
+ PyObject *oldobj = PyCell_SwapTakeRef((PyCellObject *)cell, NULL);
if (oldobj == NULL) {
_PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg);
ERROR_NO_POP();
}
- PyCell_SET(cell, NULL);
Py_DECREF(oldobj);
}
ERROR_NO_POP();
}
if (!value) {
- PyObject *cell = GETLOCAL(oparg);
- value = PyCell_GET(cell);
+ PyCellObject *cell = (PyCellObject *)GETLOCAL(oparg);
+ value = PyCell_GetRef(cell);
if (value == NULL) {
_PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg);
ERROR_NO_POP();
}
- Py_INCREF(value);
}
Py_DECREF(class_dict);
}
inst(LOAD_DEREF, ( -- value)) {
- PyObject *cell = GETLOCAL(oparg);
- value = PyCell_GET(cell);
+ PyCellObject *cell = (PyCellObject *)GETLOCAL(oparg);
+ value = PyCell_GetRef(cell);
if (value == NULL) {
_PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg);
ERROR_IF(true, error);
}
- Py_INCREF(value);
}
inst(STORE_DEREF, (v --)) {
- PyObject *cell = GETLOCAL(oparg);
- PyObject *oldobj = PyCell_GET(cell);
- PyCell_SET(cell, v);
- Py_XDECREF(oldobj);
+ PyCellObject *cell = (PyCellObject *)GETLOCAL(oparg);
+ PyCell_SetTakeRef(cell, v);
}
inst(COPY_FREE_VARS, (--)) {
#include "Python.h"
#include "pycore_abstract.h" // _PyIndex_Check()
#include "pycore_call.h" // _PyObject_CallNoArgs()
+#include "pycore_cell.h" // PyCell_GetRef()
#include "pycore_ceval.h"
#include "pycore_code.h"
#include "pycore_emscripten_signal.h" // _Py_CHECK_EMSCRIPTEN_SIGNALS
case _DELETE_DEREF: {
oparg = CURRENT_OPARG();
PyObject *cell = GETLOCAL(oparg);
- PyObject *oldobj = PyCell_GET(cell);
// Can't use ERROR_IF here.
// Fortunately we don't need its superpower.
+ PyObject *oldobj = PyCell_SwapTakeRef((PyCellObject *)cell, NULL);
if (oldobj == NULL) {
_PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg);
JUMP_TO_ERROR();
}
- PyCell_SET(cell, NULL);
Py_DECREF(oldobj);
break;
}
JUMP_TO_ERROR();
}
if (!value) {
- PyObject *cell = GETLOCAL(oparg);
- value = PyCell_GET(cell);
+ PyCellObject *cell = (PyCellObject *)GETLOCAL(oparg);
+ value = PyCell_GetRef(cell);
if (value == NULL) {
_PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg);
JUMP_TO_ERROR();
}
- Py_INCREF(value);
}
Py_DECREF(class_dict);
stack_pointer[-1] = value;
case _LOAD_DEREF: {
PyObject *value;
oparg = CURRENT_OPARG();
- PyObject *cell = GETLOCAL(oparg);
- value = PyCell_GET(cell);
+ PyCellObject *cell = (PyCellObject *)GETLOCAL(oparg);
+ value = PyCell_GetRef(cell);
if (value == NULL) {
_PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg);
if (true) JUMP_TO_ERROR();
}
- Py_INCREF(value);
stack_pointer[0] = value;
stack_pointer += 1;
break;
PyObject *v;
oparg = CURRENT_OPARG();
v = stack_pointer[-1];
- PyObject *cell = GETLOCAL(oparg);
- PyObject *oldobj = PyCell_GET(cell);
- PyCell_SET(cell, v);
- Py_XDECREF(oldobj);
+ PyCellObject *cell = (PyCellObject *)GETLOCAL(oparg);
+ PyCell_SetTakeRef(cell, v);
stack_pointer += -1;
break;
}
next_instr += 1;
INSTRUCTION_STATS(DELETE_DEREF);
PyObject *cell = GETLOCAL(oparg);
- PyObject *oldobj = PyCell_GET(cell);
// Can't use ERROR_IF here.
// Fortunately we don't need its superpower.
+ PyObject *oldobj = PyCell_SwapTakeRef((PyCellObject *)cell, NULL);
if (oldobj == NULL) {
_PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg);
goto error;
}
- PyCell_SET(cell, NULL);
Py_DECREF(oldobj);
DISPATCH();
}
next_instr += 1;
INSTRUCTION_STATS(LOAD_DEREF);
PyObject *value;
- PyObject *cell = GETLOCAL(oparg);
- value = PyCell_GET(cell);
+ PyCellObject *cell = (PyCellObject *)GETLOCAL(oparg);
+ value = PyCell_GetRef(cell);
if (value == NULL) {
_PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg);
if (true) goto error;
}
- Py_INCREF(value);
stack_pointer[0] = value;
stack_pointer += 1;
DISPATCH();
goto error;
}
if (!value) {
- PyObject *cell = GETLOCAL(oparg);
- value = PyCell_GET(cell);
+ PyCellObject *cell = (PyCellObject *)GETLOCAL(oparg);
+ value = PyCell_GetRef(cell);
if (value == NULL) {
_PyEval_FormatExcUnbound(tstate, _PyFrame_GetCode(frame), oparg);
goto error;
}
- Py_INCREF(value);
}
Py_DECREF(class_dict);
stack_pointer[-1] = value;
INSTRUCTION_STATS(STORE_DEREF);
PyObject *v;
v = stack_pointer[-1];
- PyObject *cell = GETLOCAL(oparg);
- PyObject *oldobj = PyCell_GET(cell);
- PyCell_SET(cell, v);
- Py_XDECREF(oldobj);
+ PyCellObject *cell = (PyCellObject *)GETLOCAL(oparg);
+ PyCell_SetTakeRef(cell, v);
stack_pointer += -1;
DISPATCH();
}
def compute_properties(op: parser.InstDef) -> Properties:
has_free = (
variable_used(op, "PyCell_New")
- or variable_used(op, "PyCell_GET")
- or variable_used(op, "PyCell_SET")
+ or variable_used(op, "PyCell_GetRef")
+ or variable_used(op, "PyCell_SetTakeRef")
+ or variable_used(op, "PyCell_SwapTakeRef")
)
deopts_if = variable_used(op, "DEOPT_IF")
exits_if = variable_used(op, "EXIT_IF")
#include "pycore_call.h"
#include "pycore_ceval.h"
+#include "pycore_cell.h"
#include "pycore_dict.h"
#include "pycore_emscripten_signal.h"
#include "pycore_intrinsics.h"