[pypy-commit] pypy cpyext-gc-cycle: Refactored call to tp_traverse from incminimark so there are no dependencies to pypy
stevie_92
pypy.commits at gmail.com
Fri Jan 11 05:38:59 EST 2019
Author: Stefan Beyer <home at sbeyer.at>
Branch: cpyext-gc-cycle
Changeset: r95600:94b062729ca4
Date: 2018-03-23 11:46 +0100
http://bitbucket.org/pypy/pypy/changeset/94b062729ca4/
Log: Refactored call to tp_traverse from incminimark so there are no
dependencies to pypy
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -1719,11 +1719,6 @@
return make_generic_cpy_call(FT, False)(space, func, *args)
@specialize.ll()
-def generic_cpy_call_gc(func, *args):
- FT = lltype.typeOf(func).TO
- return make_generic_cpy_call_gc(FT, False)(func, *args)
-
- at specialize.ll()
def generic_cpy_call_expect_null(space, func, *args):
FT = lltype.typeOf(func).TO
return make_generic_cpy_call(FT, True)(space, func, *args)
diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py
--- a/pypy/module/cpyext/pyobject.py
+++ b/pypy/module/cpyext/pyobject.py
@@ -20,8 +20,7 @@
from rpython.rlib.debug import ll_assert, fatalerror, debug_print
from rpython.rlib.rawrefcount import (
REFCNT_MASK, REFCNT_FROM_PYPY, REFCNT_OVERFLOW, REFCNT_CYCLE_BUFFERED,
- REFCNT_CLR_MASK, REFCNT_CLR_GREEN, REFCNT_CLR_PURPLE,
- W_MARKER_DEALLOCATING)
+ REFCNT_CLR_MASK, REFCNT_CLR_GREEN, REFCNT_CLR_PURPLE)
from pypy.module.cpyext.api import slot_function
from pypy.module.cpyext.typeobjectdefs import visitproc
@@ -254,6 +253,8 @@
w_obj._cpyext_attach_pyobj(space, py_obj)
+w_marker_deallocating = W_Root()
+
@jit.dont_look_inside
def from_ref(space, ref):
"""
@@ -265,7 +266,7 @@
return None
w_obj = rawrefcount.to_obj(W_Root, ref)
if w_obj is not None:
- if w_obj is not W_MARKER_DEALLOCATING:
+ if w_obj is not w_marker_deallocating:
return w_obj
fatalerror(
"*** Invalid usage of a dying CPython object ***\n"
@@ -318,7 +319,7 @@
def pyobj_has_w_obj(pyobj):
w_obj = rawrefcount.to_obj(W_Root, pyobj)
- return w_obj is not None and w_obj is not W_MARKER_DEALLOCATING
+ return w_obj is not None and w_obj is not w_marker_deallocating
def w_obj_has_pyobj(w_obj):
return bool(rawrefcount.from_obj(PyObject, w_obj))
@@ -454,7 +455,7 @@
@init_function
def write_w_marker_deallocating(space):
if we_are_translated():
- llptr = cast_instance_to_base_ptr(W_MARKER_DEALLOCATING)
+ llptr = cast_instance_to_base_ptr(w_marker_deallocating)
state = space.fromcache(State)
state.C.set_marker(rffi.cast(Py_ssize_t, llptr))
diff --git a/pypy/module/cpyext/state.py b/pypy/module/cpyext/state.py
--- a/pypy/module/cpyext/state.py
+++ b/pypy/module/cpyext/state.py
@@ -1,8 +1,8 @@
from rpython.rlib.objectmodel import we_are_translated, specialize
-from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rtyper.lltypesystem import rffi, lltype, llmemory
from pypy.interpreter.error import OperationError, oefmt
from pypy.interpreter import executioncontext
-from rpython.rtyper.annlowlevel import llhelper
+from rpython.rtyper.annlowlevel import llhelper, llhelper_args
from rpython.rlib.rdynload import DLLHANDLE
from rpython.rlib import rawrefcount
import sys
@@ -70,7 +70,10 @@
decref(space, ob)
print 'dealloc_trigger DONE'
return "RETRY"
- rawrefcount.init(dealloc_trigger)
+ def tp_traverse(obj_addr, callback, args):
+ # TODO: implement
+ pass
+ rawrefcount.init(dealloc_trigger, tp_traverse)
else:
if space.config.translation.gc == "boehm":
action = BoehmPyObjDeallocAction(space)
@@ -80,6 +83,25 @@
pyobj_dealloc_action = PyObjDeallocAction(space)
self.dealloc_trigger = lambda: pyobj_dealloc_action.fire()
+ def _rawrefcount_tp_traverse(space, pyobj_ptr, callback, args):
+ from pypy.module.cpyext.api import (generic_cpy_call,
+ PyObject)
+ from pypy.module.cpyext.typeobjectdefs import visitproc
+ # convert to pointers with correct types (PyObject)
+ callback_addr = llmemory.cast_ptr_to_adr(callback)
+ callback_ptr = llmemory.cast_adr_to_ptr(callback_addr,
+ visitproc)
+ pyobj_addr = llmemory.cast_ptr_to_adr(pyobj_ptr)
+ pyobj = llmemory.cast_adr_to_ptr(pyobj_addr, PyObject)
+ # now call tp_traverse (if possible)
+ if pyobj.c_ob_type and pyobj.c_ob_type.c_tp_traverse:
+ generic_cpy_call(space, pyobj.c_ob_type.c_tp_traverse,
+ pyobj,
+ callback_ptr, args)
+ self.tp_traverse = (lambda o, v, a:
+ _rawrefcount_tp_traverse(self.space,
+ o, v, a))
+
def build_api(self):
"""NOT_RPYTHON
This function is called when at object space creation,
@@ -111,7 +133,9 @@
# does something different. Sigh.
rawrefcount.init(
llhelper(rawrefcount.RAWREFCOUNT_DEALLOC_TRIGGER,
- self.dealloc_trigger))
+ self.dealloc_trigger),
+ llhelper(rawrefcount.RAWREFCOUNT_TRAVERSE,
+ self.tp_traverse))
self.builder.attach_all(space)
setup_new_method_def(space)
diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -74,7 +74,6 @@
from rpython.rlib.objectmodel import specialize
from rpython.rlib import rgc
from rpython.memory.gc.minimarkpage import out_of_memory
-from pypy.module.cpyext.api import slot_function, PyObject
from rpython.rtyper.lltypesystem import rffi
#
@@ -190,30 +189,6 @@
('forw', llmemory.Address))
FORWARDSTUBPTR = lltype.Ptr(FORWARDSTUB)
NURSARRAY = lltype.Array(llmemory.Address)
-VISIT_FUNCTYPE = rffi.CCallback([PyObject, rffi.VOIDP],
- rffi.INT_real)
-
-
-def visit_trace_non_rc_roots(pyobj, self_ptr):
- from rpython.rlib.rawrefcount import (REFCNT_CLR_BLACK,
- REFCNT_CLR_MASK)
- from rpython.rtyper.annlowlevel import cast_adr_to_nongc_instance
-
- self_adr = rffi.cast(llmemory.Address, self_ptr)
- self = cast_adr_to_nongc_instance(IncrementalMiniMarkGC, self_adr)
-
- # if the pyobj is not marked, remember it and if there is a linked pypy
- # object also remember it
- if pyobj.c_ob_refcnt & REFCNT_CLR_MASK != REFCNT_CLR_BLACK:
- pyobject = llmemory.cast_ptr_to_adr(pyobj)
- self.rrc_more_pyobjects_to_scan.append(pyobject)
- intobj = pyobj.c_ob_pypy_link
- if intobj != 0:
- obj = llmemory.cast_int_to_adr(intobj)
- hdr = self.header(obj)
- if not (hdr.tid & GCFLAG_VISITED):
- self.objects_to_trace.append(obj)
- return rffi.cast(rffi.INT_real, 0)
# ____________________________________________________________
@@ -3020,11 +2995,17 @@
('c_ob_pypy_link', lltype.Signed))
PYOBJ_HDR_PTR = lltype.Ptr(PYOBJ_HDR)
RAWREFCOUNT_DEALLOC_TRIGGER = lltype.Ptr(lltype.FuncType([], lltype.Void))
+ VISIT_FUNCTYPE = lltype.Ptr(lltype.FuncType([PYOBJ_HDR_PTR, rffi.VOIDP],
+ rffi.INT_real))
+ RAWREFCOUNT_TRAVERSE = lltype.Ptr(lltype.FuncType([PYOBJ_HDR_PTR,
+ VISIT_FUNCTYPE,
+ rffi.VOIDP],
+ lltype.Void))
def _pyobj(self, pyobjaddr):
- return llmemory.cast_adr_to_ptr(pyobjaddr, lltype.Ptr(PyObject.TO))
+ return llmemory.cast_adr_to_ptr(pyobjaddr, self.PYOBJ_HDR_PTR)
- def rawrefcount_init(self, dealloc_trigger_callback):
+ def rawrefcount_init(self, dealloc_trigger_callback, tp_traverse):
# see pypy/doc/discussion/rawrefcount.rst
if not self.rrc_enabled:
self.rrc_p_list_young = self.AddressStack()
@@ -3035,6 +3016,7 @@
self.rrc_p_dict = self.AddressDict() # non-nursery keys only
self.rrc_p_dict_nurs = self.AddressDict() # nursery keys only
self.rrc_dealloc_trigger_callback = dealloc_trigger_callback
+ self.rrc_tp_traverse = tp_traverse
self.rrc_dealloc_pending = self.AddressStack()
self.rrc_pyobjects_to_scan = self.AddressStack()
self.rrc_more_pyobjects_to_scan = self.AddressStack()
@@ -3214,10 +3196,13 @@
NO_CYCLE_DETECTION = False
def rrc_major_collection_trace(self):
+ debug_start("gc-rrc-trace")
if self.NO_CYCLE_DETECTION:
self.rrc_p_list_old.foreach(self._rrc_major_trace, None)
else:
self.rrc_major_collection_trace_cycle()
+ self.rrc_p_list_old.foreach(self._rrc_major_trace, None) # for now, remove later
+ debug_stop("gc-rrc-trace")
def _rrc_major_trace(self, pyobject, ignore):
from rpython.rlib.rawrefcount import REFCNT_MASK
@@ -3238,20 +3223,22 @@
assert not self.rrc_more_pyobjects_to_scan.non_empty()
assert not self.rrc_pyobjects_to_trace.non_empty()
- # initially, scan all old pyobjects which are linked to objects
- self.rrc_p_list_old.foreach(self._rrc_major_scan_non_rc_roots, None)
+ # initially, scan all real pyobjects (not proxies) which are linked to objects
+ #self.rrc_p_list_old.foreach(self._rrc_major_scan_non_rc_roots, None)
+ self.rrc_o_list_old.foreach(self._rrc_major_scan_non_rc_roots, None)
# as long as we find new pyobjects which should be marked, recursively
# mark them
while self.rrc_pyobjects_to_trace.non_empty():
while self.rrc_pyobjects_to_trace.non_empty():
- pyobj = self.rrc_pyobjects_to_trace.pop()
- self._rrc_major_trace_non_rc_roots(pyobj)
+ pyobject = self.rrc_pyobjects_to_trace.pop()
+ self._rrc_traverse(pyobject)
# see if we found new pypy objects to trace
if self.objects_to_trace.non_empty():
self.visit_all_objects()
self.objects_to_trace.delete()
+ self.objects_to_trace = self.AddressStack()
# look if there are some pyobjects with linked objects which were
# not marked previously, but are marked now
@@ -3261,26 +3248,29 @@
self.rrc_pyobjects_to_scan.foreach(
self._rrc_major_scan_non_rc_roots, None)
self.rrc_pyobjects_to_scan.delete()
+ self.rrc_pyobjects_to_scan = self.AddressStack()
- def traverse(self, pyobject, func_ptr):
- from pypy.module.cpyext.api import generic_cpy_call_gc
- from pypy.module.cpyext.typeobjectdefs import visitproc
- from rpython.rtyper.annlowlevel import cast_nongc_instance_to_adr
- self_addr = cast_nongc_instance_to_adr(self)
- pyobj = self._pyobj(pyobject)
- if pyobj.c_ob_type and pyobj.c_ob_type.c_tp_traverse:
- visitproc_ptr = rffi.cast(visitproc, func_ptr)
- generic_cpy_call_gc(pyobj.c_ob_type.c_tp_traverse, pyobj,
- visitproc_ptr, rffi.cast(rffi.VOIDP, self_addr))
- #cast_nongc_instance_to_adr(self)
+ self.rrc_more_pyobjects_to_scan.delete()
+ self.rrc_more_pyobjects_to_scan = self.AddressStack()
- def _rrc_major_trace_non_rc_roots(self, pyobject):
- from rpython.rtyper.annlowlevel import llhelper
- func_ptr = llhelper(VISIT_FUNCTYPE, visit_trace_non_rc_roots)
- self.traverse(pyobject, func_ptr)
+ def _rrc_mark_cpyobj(self, pyobj):
+ from rpython.rlib.rawrefcount import (REFCNT_CLR_GRAY,
+ REFCNT_CLR_MASK)
+ # if the pyobj is not marked, remember it and if there is a linked pypy
+ # object also remember it
+ if pyobj.c_ob_refcnt & REFCNT_CLR_MASK != REFCNT_CLR_GRAY:
+ pyobj.c_ob_refcnt = REFCNT_CLR_GRAY
+ pyobject = llmemory.cast_ptr_to_adr(pyobj)
+ self.rrc_more_pyobjects_to_scan.append(pyobject)
+ intobj = pyobj.c_ob_pypy_link
+ if intobj != 0:
+ obj = llmemory.cast_int_to_adr(intobj)
+ hdr = self.header(obj)
+ if not (hdr.tid & GCFLAG_VISITED):
+ self.objects_to_trace.append(obj)
def _rrc_major_scan_non_rc_roots(self, pyobject, ignore):
- from rpython.rlib.rawrefcount import (REFCNT_CLR_BLACK,
+ from rpython.rlib.rawrefcount import (REFCNT_CLR_GRAY,
REFCNT_CLR_MASK)
# check in the object header of the linked pypy object, if it is marked
# or not
@@ -3289,8 +3279,9 @@
obj = llmemory.cast_int_to_adr(intobj)
hdr = self.header(obj)
if hdr.tid & GCFLAG_VISITED:
- if pyobj.c_ob_refcnt & REFCNT_CLR_MASK != REFCNT_CLR_BLACK:
+ if pyobj.c_ob_refcnt & REFCNT_CLR_MASK != REFCNT_CLR_GRAY: # TODO change to black, but make white default
# process the pyobject now
+ pyobj.c_ob_refcnt = REFCNT_CLR_GRAY
self.rrc_pyobjects_to_trace.append(pyobject)
else:
# save the pyobject for later, in case its linked object becomes
@@ -3330,3 +3321,22 @@
surviving_dict.insertclean(obj, pyobject)
else:
self._rrc_free(pyobject)
+
+ def _rrc_visit(pyobj, self_ptr):
+ from rpython.rtyper.annlowlevel import cast_adr_to_nongc_instance
+ #
+ debug_print("visit called!")
+ self_adr = rffi.cast(llmemory.Address, self_ptr)
+ self = cast_adr_to_nongc_instance(IncrementalMiniMarkGC, self_adr)
+ self._rrc_mark_cpyobj(pyobj)
+ return rffi.cast(rffi.INT_real, 0)
+
+ def _rrc_traverse(self, pyobject):
+ from rpython.rtyper.annlowlevel import (cast_nongc_instance_to_adr,
+ llhelper)
+ #
+ pyobj = self._pyobj(pyobject)
+ callback_ptr = llhelper(self.VISIT_FUNCTYPE,
+ IncrementalMiniMarkGC._rrc_visit)
+ self_ptr = rffi.cast(rffi.VOIDP, cast_nongc_instance_to_adr(self))
+ self.rrc_tp_traverse(pyobj, callback_ptr, self_ptr)
\ No newline at end of file
diff --git a/rpython/memory/gc/test/test_rawrefcount.py b/rpython/memory/gc/test/test_rawrefcount.py
--- a/rpython/memory/gc/test/test_rawrefcount.py
+++ b/rpython/memory/gc/test/test_rawrefcount.py
@@ -53,7 +53,9 @@
else:
rc = REFCNT_FROM_PYPY
self.trigger = []
- self.gc.rawrefcount_init(lambda: self.trigger.append(1))
+ self.trigger2 = []
+ self.gc.rawrefcount_init(lambda: self.trigger.append(1),
+ lambda: self.trigger2.append(1))
#
if create_immortal:
p1 = lltype.malloc(S, immortal=True)
diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -475,7 +475,8 @@
if hasattr(GCClass, 'rawrefcount_init'):
self.rawrefcount_init_ptr = getfn(
GCClass.rawrefcount_init,
- [s_gc, SomePtr(GCClass.RAWREFCOUNT_DEALLOC_TRIGGER)],
+ [s_gc, SomePtr(GCClass.RAWREFCOUNT_DEALLOC_TRIGGER),
+ SomePtr(GCClass.RAWREFCOUNT_TRAVERSE)],
annmodel.s_None)
self.rawrefcount_create_link_pypy_ptr = getfn(
GCClass.rawrefcount_create_link_pypy,
@@ -1314,10 +1315,12 @@
self.pop_roots(hop, livevars)
def gct_gc_rawrefcount_init(self, hop):
- [v_fnptr] = hop.spaceop.args
+ [v_fnptr, v_fnptr2] = hop.spaceop.args
assert v_fnptr.concretetype == self.GCClass.RAWREFCOUNT_DEALLOC_TRIGGER
+ assert v_fnptr2.concretetype == self.GCClass.RAWREFCOUNT_TRAVERSE
hop.genop("direct_call",
- [self.rawrefcount_init_ptr, self.c_const_gc, v_fnptr])
+ [self.rawrefcount_init_ptr, self.c_const_gc, v_fnptr,
+ v_fnptr2])
def gct_gc_rawrefcount_create_link_pypy(self, hop):
[v_gcobj, v_pyobject] = hop.spaceop.args
diff --git a/rpython/rlib/rawrefcount.py b/rpython/rlib/rawrefcount.py
--- a/rpython/rlib/rawrefcount.py
+++ b/rpython/rlib/rawrefcount.py
@@ -10,7 +10,6 @@
from rpython.rtyper.extregistry import ExtRegistryEntry
from rpython.translator.tool.cbuild import ExternalCompilationInfo
from rpython.rlib import rgc, objectmodel
-from pypy.interpreter.baseobjspace import W_Root
MAX_BIT = int(math.log(sys.maxint, 2))
@@ -44,9 +43,17 @@
REFCNT_OVERFLOW = 1 << REFCNT_BITS
REFCNT_MASK = (1 << REFCNT_BITS + 1) - 1
-
+PYOBJ_HDR = lltype.Struct('GCHdr_PyObject',
+ ('c_ob_refcnt', lltype.Signed),
+ ('c_ob_pypy_link', lltype.Signed))
+PYOBJ_HDR_PTR = lltype.Ptr(PYOBJ_HDR)
RAWREFCOUNT_DEALLOC_TRIGGER = lltype.Ptr(lltype.FuncType([], lltype.Void))
-W_MARKER_DEALLOCATING = W_Root()
+VISIT_FUNCTYPE = lltype.Ptr(lltype.FuncType([PYOBJ_HDR_PTR, rffi.VOIDP],
+ rffi.INT_real))
+RAWREFCOUNT_TRAVERSE = lltype.Ptr(lltype.FuncType([PYOBJ_HDR_PTR,
+ VISIT_FUNCTYPE,
+ rffi.VOIDP],
+ lltype.Void))
def _build_pypy_link(p):
@@ -97,12 +104,12 @@
# TODO: _cyclic_refcount_overflow = dict()
@not_rpython
-def init(dealloc_trigger_callback=None):
+def init(dealloc_trigger_callback=None, tp_traverse=None):
"""set up rawrefcount with the GC. This is only used
for tests; it should not be called at all during translation.
"""
global _p_list, _o_list, _adr2pypy, _pypy2ob, _pypy2ob_rev
- global _d_list, _dealloc_trigger_callback
+ global _d_list, _dealloc_trigger_callback, _tp_traverse
_p_list = []
_o_list = []
_adr2pypy = [None]
@@ -111,6 +118,7 @@
_d_list = []
_d_marker = None
_dealloc_trigger_callback = dealloc_trigger_callback
+ _tp_traverse = tp_traverse
# def init_traverse(traverse_cpy_call):
# global _traverse_cpy_call
@@ -308,14 +316,15 @@
class Entry(ExtRegistryEntry):
_about_ = init
- def compute_result_annotation(self, s_dealloc_callback):
+ def compute_result_annotation(self, s_dealloc_callback, tp_traverse):
from rpython.rtyper.llannotation import SomePtr
assert isinstance(s_dealloc_callback, SomePtr) # ll-ptr-to-function
+ # add assert?
def specialize_call(self, hop):
hop.exception_cannot_occur()
- [v_dealloc_callback] = hop.inputargs(hop.args_r[0])
- hop.genop('gc_rawrefcount_init', [v_dealloc_callback])
+ v_dealloc_callback, v_tp_traverse = hop.inputargs(*hop.args_r)
+ hop.genop('gc_rawrefcount_init', [v_dealloc_callback, v_tp_traverse])
class Entry(ExtRegistryEntry):
More information about the pypy-commit
mailing list