Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
34e6b9f
Fix a few wrong steals in bytecodes.c
Fidget-Spinner Jun 28, 2024
b3b6851
Deferred refcount GC
Fidget-Spinner Jun 28, 2024
a90a074
add a steal
Fidget-Spinner Jun 29, 2024
e82c2dc
Conversion function should have steal variant
Fidget-Spinner Jun 29, 2024
5df23bf
remove a steal
Fidget-Spinner Jun 29, 2024
6b63066
Fix double decref in error path
Fidget-Spinner Jun 30, 2024
634adcc
Revert "Fix double decref in error path"
Fidget-Spinner Jun 30, 2024
5b55760
Merge remote-tracking branch 'upstream/main' into deferred_gc
Fidget-Spinner Jul 3, 2024
8cb139f
Remove immortalize visitor
Fidget-Spinner Jul 3, 2024
c260fc9
fix the JIT builds
Fidget-Spinner Jul 3, 2024
700c2fd
fix buildbot bug
Fidget-Spinner Jul 3, 2024
cde931d
don't deref NULL
Fidget-Spinner Jul 3, 2024
4e59420
Remove steal conversion, add list_fromstackrefsteal
Fidget-Spinner Jul 3, 2024
98f9c0f
Silence warnings
Fidget-Spinner Jul 3, 2024
32aaf2b
Fix error case in CALL
Fidget-Spinner Jul 3, 2024
41c6218
remove all temporary immortalization
Fidget-Spinner Jul 3, 2024
dca2ec3
Revert "remove all temporary immortalization"
Fidget-Spinner Jul 3, 2024
39e8a56
Apply suggestions
Fidget-Spinner Jul 4, 2024
3e14b1c
fix non-free-threaded
Fidget-Spinner Jul 4, 2024
2bfe017
Merge remote-tracking branch 'upstream/main' into deferred_gc
Fidget-Spinner Jul 9, 2024
07f78ce
fix bytecodes.c to use arrays instead of pointers
Fidget-Spinner Jul 9, 2024
34b047e
Merge remote-tracking branch 'upstream/main' into deferred_gc
Fidget-Spinner Jul 18, 2024
f4b4022
Automatically flush to stack new
Fidget-Spinner Jul 18, 2024
4c0afa1
lint
Fidget-Spinner Jul 18, 2024
71aed5c
Simpler implementation
Fidget-Spinner Jul 18, 2024
1d19a97
reduce diff
Fidget-Spinner Jul 18, 2024
2b383b1
reduce diff
Fidget-Spinner Jul 18, 2024
2d2cd7c
reduce diff again (sorry)
Fidget-Spinner Jul 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Revert "remove all temporary immortalization"
This reverts commit 41c6218.
  • Loading branch information
Fidget-Spinner committed Jul 3, 2024
commit dca2ec39c544a090e43916da2cbbc78d21bc29d7
8 changes: 8 additions & 0 deletions Include/internal/pycore_gc.h
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,14 @@ struct _gc_runtime_state {
collections, and are awaiting to undergo a full collection for
the first time. */
Py_ssize_t long_lived_pending;

/* gh-117783: Deferred reference counting is not fully implemented yet, so
as a temporary measure we treat objects using deferred reference
counting as immortal. The value may be zero, one, or a negative number:
0: immortalize deferred RC objects once the first thread is created
1: immortalize all deferred RC objects immediately
<0: suppressed; don't immortalize objects */
int immortalize;
#endif
};

Expand Down
14 changes: 14 additions & 0 deletions Modules/_testinternalcapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1968,13 +1968,27 @@ get_py_thread_id(PyObject *self, PyObject *Py_UNUSED(ignored))
static PyObject *
suppress_immortalization(PyObject *self, PyObject *value)
{
#ifdef Py_GIL_DISABLED
int suppress = PyObject_IsTrue(value);
if (suppress < 0) {
return NULL;
}
PyInterpreterState *interp = PyInterpreterState_Get();
// Subtract two to suppress immortalization (so that 1 -> -1)
_Py_atomic_add_int(&interp->gc.immortalize, suppress ? -2 : 2);
#endif
Py_RETURN_NONE;
}

static PyObject *
get_immortalize_deferred(PyObject *self, PyObject *Py_UNUSED(ignored))
{
#ifdef Py_GIL_DISABLED
PyInterpreterState *interp = PyInterpreterState_Get();
return PyBool_FromLong(_Py_atomic_load_int(&interp->gc.immortalize) >= 0);
#else
Py_RETURN_FALSE;
#endif
}

static PyObject *
Expand Down
65 changes: 65 additions & 0 deletions Objects/codeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,16 @@ PyCode_ClearWatcher(int watcher_id)
static int
should_intern_string(PyObject *o)
{
#ifdef Py_GIL_DISABLED
// The free-threaded build interns (and immortalizes) all string constants
// unless we've disabled immortalizing objects that use deferred reference
// counting.
PyInterpreterState *interp = _PyInterpreterState_GET();
if (_Py_atomic_load_int(&interp->gc.immortalize) < 0) {
return 1;
}
#endif

// compute if s matches [a-zA-Z0-9_]
const unsigned char *s, *e;

Expand All @@ -120,6 +130,10 @@ should_intern_string(PyObject *o)
return 1;
}

#ifdef Py_GIL_DISABLED
static PyObject *intern_one_constant(PyObject *op);
#endif

static int
intern_strings(PyObject *tuple)
{
Expand Down Expand Up @@ -221,6 +235,27 @@ intern_constants(PyObject *tuple, int *modified)
}
Py_DECREF(tmp);
}

// Intern non-string constants in the free-threaded build, but only if
// we are also immortalizing objects that use deferred reference
// counting.
PyThreadState *tstate = PyThreadState_GET();
if (!_Py_IsImmortal(v) && !PyCode_Check(v) &&
!PyUnicode_CheckExact(v) &&
_Py_atomic_load_int(&tstate->interp->gc.immortalize) >= 0)
{
PyObject *interned = intern_one_constant(v);
if (interned == NULL) {
return -1;
}
else if (interned != v) {
PyTuple_SET_ITEM(tuple, i, interned);
Py_SETREF(v, interned);
if (modified) {
*modified = 1;
}
}
}
#endif
}
return 0;
Expand Down Expand Up @@ -2460,6 +2495,36 @@ _PyCode_ConstantKey(PyObject *op)
}

#ifdef Py_GIL_DISABLED
static PyObject *
intern_one_constant(PyObject *op)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
_Py_hashtable_t *consts = interp->code_state.constants;

assert(!PyUnicode_CheckExact(op)); // strings are interned separately

_Py_hashtable_entry_t *entry = _Py_hashtable_get_entry(consts, op);
if (entry == NULL) {
if (_Py_hashtable_set(consts, op, op) != 0) {
return NULL;
}

#ifdef Py_REF_DEBUG
Py_ssize_t refcnt = Py_REFCNT(op);
if (refcnt != 1) {
// Adjust the reftotal to account for the fact that we only
// restore a single reference in _PyCode_Fini.
_Py_AddRefTotal(_PyThreadState_GET(), -(refcnt - 1));
}
#endif

_Py_SetImmortal(op);
return op;
}

assert(_Py_IsImmortal(entry->value));
return (PyObject *)entry->value;
}

static int
compare_constants(const void *key1, const void *key2) {
Expand Down
13 changes: 13 additions & 0 deletions Python/bltinmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -866,8 +866,21 @@ builtin_compile_impl(PyObject *module, PyObject *source, PyObject *filename,
if (str == NULL)
goto error;

#ifdef Py_GIL_DISABLED
// gh-118527: Disable immortalization of code constants for explicit
// compile() calls to get consistent frozen outputs between the default
// and free-threaded builds.
// Subtract two to suppress immortalization (so that 1 -> -1)
PyInterpreterState *interp = _PyInterpreterState_GET();
_Py_atomic_add_int(&interp->gc.immortalize, -2);
#endif

result = Py_CompileStringObject(str, filename, start[compile_mode], &cf, optimize);

#ifdef Py_GIL_DISABLED
_Py_atomic_add_int(&interp->gc.immortalize, 2);
#endif

Py_XDECREF(source_copy);
goto finally;

Expand Down
4 changes: 4 additions & 0 deletions Python/gc_free_threading.c
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,10 @@ _PyGC_Init(PyInterpreterState *interp)
{
GCState *gcstate = &interp->gc;

// gh-117783: immortalize objects that would use deferred refcounting
// once the first non-main thread is created (but not in subinterpreters).
gcstate->immortalize = _Py_IsMainInterpreter(interp) ? 0 : -1;

gcstate->garbage = PyList_New(0);
if (gcstate->garbage == NULL) {
return _PyStatus_NO_MEMORY();
Expand Down