Maciej Fijalkowski avatar Maciej Fijalkowski committed 5bffe8e

an API I want from a custom tracer (that can be run directly too)

Comments (0)

Files changed (5)

pypy/rpython/lltypesystem/lltype.py

         Struct._install_extras(self, **kwds)
 
     def _attach_runtime_type_info_funcptr(self, funcptr, destrptr,
-                                          customtraceptr):
+                                          custom_trace_func):
         if self._runtime_type_info is None:
             raise TypeError("attachRuntimeTypeInfo: %r must have been built "
                             "with the rtti=True argument" % (self,))
                 raise TypeError("expected a destructor function "
                                 "implementation, got: %s" % destrptr)
             self._runtime_type_info.destructor_funcptr = destrptr
-        if customtraceptr is not None:
-            from pypy.rpython.lltypesystem import llmemory
-            T = typeOf(customtraceptr)
-            if (not isinstance(T, Ptr) or
-                not isinstance(T.TO, FuncType) or
-                len(T.TO.ARGS) != 2 or
-                T.TO.RESULT != llmemory.Address or
-                T.TO.ARGS[0] != llmemory.Address or
-                T.TO.ARGS[1] != llmemory.Address):
-                raise TypeError("expected a custom trace function "
-                                "implementation, got: %s" % customtraceptr)
-            self._runtime_type_info.custom_trace_funcptr = customtraceptr
+        if custom_trace_func is not None:
+            self._runtime_type_info.custom_trace_func = custom_trace_func
 
 class GcStruct(RttiStruct):
     _gckind = 'gc'
     return _ptr(PTRTYPE, oddint, solid=True)
 
 def attachRuntimeTypeInfo(GCSTRUCT, funcptr=None, destrptr=None,
-                          customtraceptr=None):
+                          custom_trace_func=None):
     if not isinstance(GCSTRUCT, RttiStruct):
         raise TypeError, "expected a RttiStruct: %s" % GCSTRUCT
     GCSTRUCT._attach_runtime_type_info_funcptr(funcptr, destrptr,
-                                               customtraceptr)
+                                               custom_trace_func)
     return _ptr(Ptr(RuntimeTypeInfo), GCSTRUCT._runtime_type_info)
 
 def getRuntimeTypeInfo(GCSTRUCT):

pypy/rpython/memory/gc/base.py

                             member_index,
                             is_rpython_class,
                             has_custom_trace,
-                            get_custom_trace,
                             fast_path_tracing):
         self.getfinalizer = getfinalizer
         self.getlightfinalizer = getlightfinalizer
         self.member_index = member_index
         self.is_rpython_class = is_rpython_class
         self.has_custom_trace = has_custom_trace
-        self.get_custom_trace = get_custom_trace
         self.fast_path_tracing = fast_path_tracing
 
     def get_member_index(self, type_id):
             i += 1
     trace._annspecialcase_ = 'specialize:arg(2)'
 
+    def _call_custom_trace(self, obj, typeid, callback, arg):
+        def wrapper(item, arg):
+            if self.is_valid_gc_object(item):
+                callback(item, arg)
+        
+        self.custom_trace_funcs[typeid.index](obj, wrapper, arg)
+
     def _trace_slow_path(self, obj, callback, arg):
         typeid = self.get_type_id(obj)
         if self.has_gcptr_in_varsize(typeid):
                 item += itemlength
                 length -= 1
         if self.has_custom_trace(typeid):
-            generator = self.get_custom_trace(typeid)
-            item = llmemory.NULL
-            while True:
-                item = generator(obj, item)
-                if not item:
-                    break
-                if self.points_to_valid_gc_object(item):
-                    callback(item, arg)
+            self._call_custom_trace(obj, typeid, callback, arg)
     _trace_slow_path._annspecialcase_ = 'specialize:arg(2)'
 
     def trace_partial(self, obj, start, stop, callback, arg):

pypy/rpython/memory/gctypelayout.py

         infobits = self.get(typeid).infobits
         return infobits & T_HAS_CUSTOM_TRACE != 0
 
-    def q_get_custom_trace(self, typeid):
-        ll_assert(self.q_has_custom_trace(typeid),
-                  "T_HAS_CUSTOM_TRACE missing")
-        typeinfo = self.get(typeid)
-        return typeinfo.finalizer_or_customtrace
-
     def q_fast_path_tracing(self, typeid):
         # return True if none of the flags T_HAS_GCPTR_IN_VARSIZE,
         # T_IS_GCARRAY_OF_GCPTR or T_HAS_CUSTOM_TRACE is set
             self.q_member_index,
             self.q_is_rpython_class,
             self.q_has_custom_trace,
-            self.q_get_custom_trace,
             self.q_fast_path_tracing)
 
 
             infobits |= T_HAS_FINALIZER
         elif kind == 'light_finalizer':
             infobits |= T_HAS_FINALIZER | T_HAS_LIGHTWEIGHT_FINALIZER
-        elif kind == "custom_trace":
-            infobits |= T_HAS_CUSTOM_TRACE
         else:
             assert 0, kind
+    custom_trace_func = builder.get_custom_trace_func(TYPE)
+    if custom_trace_func is not None:
+        infobits |= T_HAS_CUSTOM_TRACE
+        builder.record_custom_trace(index, custom_trace_func)
     #
     if not TYPE._is_varsize():
         info.fixedsize = llarena.round_up_for_allocation(
         if TYPE in self._special_funcptrs:
             return self._special_funcptrs[TYPE]
         fptr1, is_lightweight = self.make_finalizer_funcptr_for_type(TYPE)
-        fptr2 = self.make_custom_trace_funcptr_for_type(TYPE)
-        assert not (fptr1 and fptr2), (
-            "type %r needs both a finalizer and a custom tracer" % (TYPE,))
         if fptr1:
             if is_lightweight:
                 kind_and_fptr = "light_finalizer", fptr1
             else:
                 kind_and_fptr = "finalizer", fptr1
-        elif fptr2:
-            kind_and_fptr = "custom_trace", fptr2
         else:
             kind_and_fptr = None
         self._special_funcptrs[TYPE] = kind_and_fptr

pypy/rpython/memory/gcwrapper.py

 
     def prepare_graphs(self, flowgraphs):
         lltype2vtable = self.llinterp.typer.lltype2vtable
+        # only valid for direct layout builder
+        self.gc.custom_trace_funcs = {}
         layoutbuilder = DirectRunLayoutBuilder(self.gc.__class__,
                                                lltype2vtable,
-                                               self.llinterp)
+                                               self.llinterp,
+                                               self.gc.custom_trace_funcs)
         self.get_type_id = layoutbuilder.get_type_id
         layoutbuilder.initialize_gc_query_function(self.gc)
 
 
 class DirectRunLayoutBuilder(gctypelayout.TypeLayoutBuilder):
 
-    def __init__(self, GCClass, lltype2vtable, llinterp):
+    def __init__(self, GCClass, lltype2vtable, llinterp, custom_trace_funcs):
         self.llinterp = llinterp
         super(DirectRunLayoutBuilder, self).__init__(GCClass, lltype2vtable)
+        self.custom_trace_funcs = custom_trace_funcs
 
     def make_finalizer_funcptr_for_type(self, TYPE):
         from pypy.rpython.memory.gctransform.support import get_rtti
             return llmemory.NULL
         return llhelper(gctypelayout.GCData.FINALIZER_OR_CT, ll_finalizer), light
 
-    def make_custom_trace_funcptr_for_type(self, TYPE):
+    def record_custom_trace(self, tid, custom_trace_func):
+        self.custom_trace_funcs[tid] = custom_trace_func
+
+    def get_custom_trace_func(self, TYPE):
         from pypy.rpython.memory.gctransform.support import get_rtti
         rtti = get_rtti(TYPE)
-        if rtti is not None and hasattr(rtti._obj, 'custom_trace_funcptr'):
-            return rtti._obj.custom_trace_funcptr
+        if rtti is not None and hasattr(rtti._obj, 'custom_trace_func'):
+            return rtti._obj.custom_trace_func
         else:
             return None
 

pypy/rpython/memory/test/test_gc.py

 from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib.objectmodel import compute_unique_id
+from pypy.rlib.objectmodel import compute_unique_id, specialize
 from pypy.rlib import rgc
 from pypy.rlib.rstring import StringBuilder
 from pypy.rlib.rarithmetic import LONG_BIT
+from pypy.jit.backend.llsupport import jitframe
 
 WORD = LONG_BIT // 8
 
         assert 160 <= res <= 165
 
     def test_custom_trace(self):
-        from pypy.rpython.annlowlevel import llhelper
         from pypy.rpython.lltypesystem import llmemory
         from pypy.rpython.lltypesystem.llarena import ArenaError
         #
                                  ('y', llmemory.Address), rtti=True)
         T = lltype.GcStruct('T', ('z', lltype.Signed))
         offset_of_x = llmemory.offsetof(S, 'x')
-        def customtrace(obj, prev):
-            if not prev:
-                return obj + offset_of_x
-            else:
-                return llmemory.NULL
-        CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address],
-                                          llmemory.Address)
-        customtraceptr = llhelper(lltype.Ptr(CUSTOMTRACEFUNC), customtrace)
-        lltype.attachRuntimeTypeInfo(S, customtraceptr=customtraceptr)
+        def customtrace(obj, callback, arg):
+            callback(obj + offset_of_x, arg)
+
+        lltype.attachRuntimeTypeInfo(S, custom_trace_func=customtrace)
         #
         for attrname in ['x', 'y']:
             def setup():
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.