Skip to content

Commit 6dadc03

Browse files
committed
tmp
1 parent e06a499 commit 6dadc03

1 file changed

Lines changed: 98 additions & 48 deletions

File tree

‎Objects/tracingregionobject.c‎

Lines changed: 98 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
/* Macro that jumps to error, if the expression `x` does not succeed. */
2828
#define SUCCEEDS(x) do { int r = (x); if (r != 0) goto error; } while (0)
2929

30+
#define Region_Check(x) Py_IS_TYPE((x), &_PyTracingRegion_Type)
31+
3032
// ###################################################################
3133
// Copied from gc.c
3234
// ###################################################################
@@ -296,10 +298,93 @@ get_reachable_proc(PyTypeObject *tp)
296298
static void
297299
gc_list_dissolve(PyGC_Head *list) {
298300
struct _gc_runtime_state* gc_state = get_gc_state();
299-
//gc_list_merge(list, &(gc_state->young.head));
300301
gc_list_merge(list, &(gc_state->old[0].head));
301302
}
302303

304+
static void detach_weak_refs(PyGC_Head *gc_list) {
305+
PyGC_Head *current = GC_NEXT(gc_list);
306+
while (current != gc_list) {
307+
PyObject *item = _Py_FROM_GC(current);
308+
#ifdef PY_DEBUG
309+
Py_ssize_t weak_ctn = _PyWeakref_GetWeakrefCount(item);
310+
if (weak_ctn) {
311+
trace("- Clearing %zd weak references to %p", weak_ctn, item);
312+
}
313+
#endif
314+
if (_PyType_SUPPORTS_WEAKREFS(Py_TYPE(item))) {
315+
_PyWeakref_ClearWeakRefsNoCallbacks(item);
316+
}
317+
318+
current = GC_NEXT(current);
319+
}
320+
}
321+
322+
typedef struct {
323+
PyObject_HEAD
324+
PyObject *dict;
325+
// The GC list containing all objects while the region is closed. The bridge
326+
// object is not in this GC list but in the list of the owning region or in no
327+
// list if it's owned by a released cown.
328+
PyGC_Head gc_list;
329+
// FIXME(regions): This can be inferred from the status of the gc_list
330+
// or stored in the lower bits of the GC list. For now we keep it separate
331+
// for the prototype
332+
bool open;
333+
// This is the number of references from inside the region that reference
334+
// this bridge object.
335+
Py_ssize_t internal_bridge_refs;
336+
} TracingRegionObject;
337+
338+
const int PER_REGION_TRACE_LIMIT = 2;
339+
340+
typedef struct {
341+
// This is the stack of pending regions needing to be closed to close
342+
// this region tree. Objects will be inqueued `PER_REGION_TRACE_LIMIT`
343+
// times. It the region is not closed when it hits the limit, the closing
344+
// will fail.
345+
PyObject *pending;
346+
// This tracks per region in the tree how often it has been traversed.
347+
// Some things require the trace to be redone, namely freezing an object
348+
// as that may create references and finding an open sub-region, as that
349+
// one needs to be traced and closed first.
350+
//
351+
// We limit the number of times we restart the trace per region.
352+
// Theoretically, this may reject some programs that would eventually
353+
// reach a fixed point, but if somebody wants to do dark magic, that's
354+
// really not our problem.
355+
_Py_hashtable_t *traceing_counts;
356+
} tree_trace_state_t;
357+
358+
static void tree_trace_state_destroy(tree_trace_state_t* state) {
359+
if (state->traceing_counts) {
360+
_Py_hashtable_destroy(state->traceing_counts);
361+
state->traceing_counts = NULL;
362+
}
363+
if (state->pending) {
364+
Py_CLEAR(state->pending);
365+
}
366+
}
367+
368+
static int tree_trace_state_init(tree_trace_state_t* state) {
369+
state->traceing_counts = _Py_hashtable_new(
370+
_Py_hashtable_hash_ptr,
371+
_Py_hashtable_compare_direct);
372+
if (state->traceing_counts == NULL) {
373+
goto error;
374+
}
375+
376+
state->pending = PyList_New(0);
377+
if (state->pending == NULL) {
378+
goto error;
379+
}
380+
381+
return 0;
382+
error:
383+
trace_state_destroy(state);
384+
return -1;
385+
}
386+
387+
// TODO: Continue Migration
303388

304389
typedef struct {
305390
// These are the objects with incoming references, that
@@ -751,41 +836,26 @@ static int trace_object(PyObject* obj, trace_info_t* result, PyGC_Head *gc_list)
751836
return res;
752837
}
753838

754-
static void detach_weak_refs(PyGC_Head *gc_list) {
755-
PyGC_Head *current = GC_NEXT(gc_list);
756-
while (current != gc_list) {
757-
PyObject *item = _Py_FROM_GC(current);
758-
#ifdef PY_DEBUG
759-
Py_ssize_t weak_ctn = _PyWeakref_GetWeakrefCount(item);
760-
if (weak_ctn) {
761-
trace("- Clearing %zd weak references to %p", weak_ctn, item);
762-
}
763-
#endif
764-
if (_PyType_SUPPORTS_WEAKREFS(Py_TYPE(item))) {
765-
_PyWeakref_ClearWeakRefsNoCallbacks(item);
766-
}
839+
static int try_close_region_tree(PyObject *root) {
840+
tree_trace_state_t state;
841+
if (tree_trace_state_init(&state)) {
842+
return -1;
843+
}
767844

768-
current = GC_NEXT(current);
845+
while (PyList_GET_SIZE(state.pending) > 0) {
846+
// Find the next pending item:
847+
PyObject *region = list_pop(state.pending);
848+
assert(Region_Check(region));
849+
850+
851+
// TODO: Continue....
769852
}
770853
}
771854

772855
// ###################################################################
773856
// Region Object
774857
// ###################################################################
775858

776-
typedef struct {
777-
PyObject_HEAD
778-
PyObject *dict;
779-
// The GC list containing all objects while the region is closed. The bridge
780-
// object is not in this GC list but in the list of the owning region or in no
781-
// list if it's owned by a released cown.
782-
PyGC_Head gc_list;
783-
// FIXME(regions): This can be inferred from the status of the gc_list
784-
// or stored in the lower bits of the GC list. For now we keep it separate
785-
// for the prototype
786-
bool open;
787-
} TracingRegionObject;
788-
789859
static int
790860
TracingRegion_init(TracingRegionObject *self, PyObject *args, PyObject *kwargs) {
791861
gc_list_init(&self->gc_list);
@@ -894,24 +964,6 @@ TracingRegion_set_dict(PyObject *op, PyObject *value, void *Py_UNUSED(context))
894964
return 0;
895965
}
896966

897-
static PyObject* TracingRegion_trace(PyObject *op) {
898-
trace_info_t result;
899-
if (trace_object(op, &result, NULL)) {
900-
return NULL; // propagate Python exception
901-
}
902-
903-
if (result.obj_table != NULL) {
904-
_Py_hashtable_destroy(result.obj_table);
905-
}
906-
907-
PyObject *t = Py_BuildValue("(ii)", result.objs, result.incoming_refs);
908-
if (t == NULL) {
909-
return NULL; // propagate Python exception
910-
}
911-
912-
return t;
913-
}
914-
915967
// State threaded through `_report_incoming_ref` while building the
916968
// "region could not be closed" error message.
917969
typedef struct {
@@ -1051,8 +1103,6 @@ int _PyTracingRegion_IsClosed(PyObject* region) {
10511103
}
10521104

10531105
static PyMethodDef TracingRegion_methods[] = {
1054-
{"trace", _PyCFunction_CAST(TracingRegion_trace), METH_NOARGS,
1055-
"This traces the region and returns the number of incoming references"},
10561106
{NULL, NULL} /* sentinel */
10571107
};
10581108

0 commit comments

Comments
 (0)