[pypy-commit] lang-smalltalk storage-gcrefs: Extracted walking of gc references in separate module.
anton_gulenko
noreply at buildbot.pypy.org
Mon Jul 21 11:10:02 CEST 2014
Author: Anton Gulenko <anton.gulenko at googlemail.com>
Branch: storage-gcrefs
Changeset: r925:8476f6a16d21
Date: 2014-07-21 11:10 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/8476f6a16d21/
Log: Extracted walking of gc references in separate module. Implemented
walking the heap correctly without collecting a huge list of all
objects. someInstance primitive still fails in interpreted mode, due
to MemoryError in get_rpy_roots(). Don't see a way to fix except to
go 64 bit. Translated version segfaults.
diff --git a/spyvm/gcrefs.py b/spyvm/gcrefs.py
new file mode 100644
--- /dev/null
+++ b/spyvm/gcrefs.py
@@ -0,0 +1,67 @@
+
+from rpython.rlib import rgc, objectmodel, jit
+
+# ======== Internal functions ========
+
+def flag(gcref):
+ return rgc.get_gcflag_extra(gcref)
+
+def toggle_flag(gcref):
+ rgc.toggle_gcflag_extra(gcref)
+
+def references(gcref):
+ return rgc.get_rpy_referents(gcref)
+
+def gc_roots():
+ return rgc.get_rpy_roots()
+
+def _clear_all_flags(gcrefs):
+ for gcref in gcrefs:
+ if gcref and flag(gcref):
+ toggle_flag(gcref)
+ _clear_all_flags(references(gcref))
+
+def _walk_gc_references(func, extra_parameter, collect_into, gcrefs):
+ for gcref in gcrefs:
+ if gcref and not flag(gcref):
+ toggle_flag(gcref)
+ result = func(gcref, extra_parameter)
+ if result is not None:
+ collect_into.append(result)
+ _walk_gc_references(func, extra_parameter, collect_into, references(gcref))
+ return collect_into
+
+# ======== API of this module ========
+# The extra_parameter is here to avoid creating closures in the function parameters,
+# and still be able to pass some context into the functions. It should always be a short tuple,
+# so that rpython can autmatically specialize these functions. If it fails to do so, annotate
+# all functions with extra_parameter with @objectmodel.specialize.argtype(2).
+
+def try_cast(type, gcref):
+ return rgc.try_cast_gcref_to_instance(type, gcref)
+
+ at jit.dont_look_inside
+def walk_gc_references(func, extra_parameter = None):
+ roots = gc_roots()
+ result = _walk_gc_references(func, extra_parameter, [], roots)
+ _clear_all_flags(roots)
+ _clear_all_flags(gc_roots()) # Just in case
+ return result
+
+def walk_gc_references_of_type(type, func, extra_parameter = None):
+ def check_type(gcref, extra):
+ type, func, extra_parameter = extra
+ w_obj = try_cast(type, gcref)
+ if w_obj:
+ func(w_obj, extra_parameter)
+ return None
+ walk_gc_references(check_type, (type, func, extra_parameter))
+
+def collect_gc_references_of_type(type, filter_func = lambda obj, extra: True, extra_parameter = None):
+ def check_type(gcref, extra):
+ type, filter_func, extra_parameter = extra
+ w_obj = try_cast(type, gcref)
+ if w_obj and filter_func(w_obj, extra_parameter):
+ return w_obj
+ return None
+ return walk_gc_references(check_type, (type, filter_func, extra_parameter))
diff --git a/spyvm/primitives.py b/spyvm/primitives.py
--- a/spyvm/primitives.py
+++ b/spyvm/primitives.py
@@ -4,7 +4,7 @@
import operator
from spyvm import model, shadow, error, constants, display
from spyvm.error import PrimitiveFailedError, PrimitiveNotYetWrittenError
-from spyvm import wrapper
+from spyvm import wrapper, gcrefs
from rpython.rlib import rarithmetic, rfloat, unroll, jit, objectmodel
@@ -540,43 +540,25 @@
w_frame.store(interp.space, constants.CTXPART_STACKP_INDEX, interp.space.wrap_int(stackp))
return w_frame
-
def stm_enabled():
"""NOT RPYTHON"""
from rpython.rlib import rgc
return hasattr(rgc, "stm_is_enabled") and rgc.stm_is_enabled()
+
if stm_enabled():
def get_instances_array(space, s_frame, w_class):
return []
else:
def get_instances_array(space, s_frame, w_class):
- # This primitive returns some instance of the class on the stack.
- # Not sure quite how to do this; maintain a weak list of all
- # existing instances or something?
- match_w = s_frame.instances_array(w_class)
- if match_w is None:
- match_w = []
- from rpython.rlib import rgc
-
- roots = [gcref for gcref in rgc.get_rpy_roots() if gcref]
- pending = roots[:]
- while pending:
- gcref = pending.pop()
- if not rgc.get_gcflag_extra(gcref):
- rgc.toggle_gcflag_extra(gcref)
- w_obj = rgc.try_cast_gcref_to_instance(model.W_Object, gcref)
- if (w_obj is not None and w_obj.has_class()
- and w_obj.getclass(space) is w_class):
- match_w.append(w_obj)
- pending.extend(rgc.get_rpy_referents(gcref))
-
- while roots:
- gcref = roots.pop()
- if rgc.get_gcflag_extra(gcref):
- rgc.toggle_gcflag_extra(gcref)
- roots.extend(rgc.get_rpy_referents(gcref))
- s_frame.store_instances_array(w_class, match_w)
- return match_w
+ # TODO find a better way then always pre-collecting the entire list of objects.
+ instances = s_frame.instances_array(w_class)
+ if instances is None:
+ def filter_w_obj(w_obj, extra):
+ w_class, space = extra
+ return w_obj.has_class() and w_obj.getclass(space) is w_class
+ instances = gcrefs.collect_gc_references_of_type(model.W_Object, filter_w_obj, (w_class, space))
+ s_frame.store_instances_array(w_class, instances)
+ return instances
@expose_primitive(SOME_INSTANCE, unwrap_spec=[object])
def func(interp, s_frame, w_class):
@@ -935,32 +917,6 @@
w_class = assert_pointers(w_class)
w_class.as_class_get_shadow(interp.space).flush_method_caches()
return w_rcvr
-
- at objectmodel.specialize.arg(0)
-def walk_gc_references(func, gcrefs):
- from rpython.rlib import rgc
- for gcref in gcrefs:
- if gcref and not rgc.get_gcflag_extra(gcref):
- try:
- rgc.toggle_gcflag_extra(gcref)
- func(gcref)
- walk_gc_references(func, rgc.get_rpy_referents(gcref))
- finally:
- rgc.toggle_gcflag_extra(gcref)
-
- at objectmodel.specialize.arg(0)
-def walk_gc_objects(func):
- from rpython.rlib import rgc
- walk_gc_references(func, rgc.get_rpy_roots())
-
- at objectmodel.specialize.arg(0, 1)
-def walk_gc_objects_of_type(type, func):
- from rpython.rlib import rgc
- def check_type(gcref):
- w_obj = rgc.try_cast_gcref_to_instance(type, gcref)
- if w_obj:
- func(w_obj)
- walk_gc_objects(check_type)
if not stm_enabled():
# XXX: We don't have a global symbol cache. Instead, we walk all
@@ -969,7 +925,7 @@
def func(interp, s_frame, w_rcvr):
# This takes a long time (at least in interpreted mode), and is not really necessary.
# We are monitoring changes to MethodDictionaries, so there is no need for the image to tell us.
- #walk_gc_objects_of_type(shadow.MethodDictionaryShadow, lambda s_dict: s_dict.flush_method_cache())
+ # gcrefs.walk_gc_references_of_type(shadow.MethodDictionaryShadow, lambda s_dict: s_dict.flush_method_cache())
return w_rcvr
# ___________________________________________________________________________
More information about the pypy-commit
mailing list