[pypy-commit] lang-smalltalk default: try to fix nextInstance if not called in the same frame as someInstance

timfel noreply at buildbot.pypy.org
Thu Dec 5 23:36:04 CET 2013


Author: Tim Felgentreff <timfelgentreff at gmail.com>
Branch: 
Changeset: r516:e06588225b5a
Date: 2013-12-05 23:22 +0100
http://bitbucket.org/pypy/lang-smalltalk/changeset/e06588225b5a/

Log:	try to fix nextInstance if not called in the same frame as
	someInstance

diff --git a/spyvm/primitives.py b/spyvm/primitives.py
--- a/spyvm/primitives.py
+++ b/spyvm/primitives.py
@@ -515,54 +515,70 @@
     w_frame.store(interp.space, constants.CTXPART_STACKP_INDEX, interp.space.wrap_int(stackp))
     return w_frame
 
- at expose_primitive(SOME_INSTANCE, unwrap_spec=[object])
-def func(interp, s_frame, w_class):
+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?
-    from rpython.rlib import rgc
 
-    match_w = []
-    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(interp.space) is w_class):
-                match_w.append(w_obj)
-            pending.extend(rgc.get_rpy_referents(gcref))
+    match_w = s_frame.instances_array(w_class)
+    if match_w is None:
+        from rpython.rlib import rgc
 
-    while roots:
-        gcref = roots.pop()
-        if rgc.get_gcflag_extra(gcref):
-            rgc.toggle_gcflag_extra(gcref)
-            roots.extend(rgc.get_rpy_referents(gcref))
+        match_w = []
+        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))
 
-    s_frame.store_instances_array(match_w)
+        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
+
+ at expose_primitive(SOME_INSTANCE, unwrap_spec=[object])
+def func(interp, s_frame, w_class):
+    match_w = get_instances_array(interp.space, s_frame, w_class)
     try:
-        return match_w.pop()
+        return match_w[0]
     except IndexError:
         raise PrimitiveFailedError()
 
 def next_instance(space, list_of_objects, w_obj):
+    retval = None
     try:
-        retval = list_of_objects.pop()
-        # just in case, that one of the objects in the list changes its class
-        if retval.getclass(space).is_same_object(w_obj.getclass(space)):
-            return retval
-        else:
-            return next_instance(space, list_of_objects, w_obj)
+        idx = list_of_objects.index(w_obj)
+    except ValueError:
+        idx = -1
+    try:
+        retval = list_of_objects[idx + 1]
     except IndexError:
         raise PrimitiveFailedError()
+    # just in case, that one of the objects in the list changes its class
+    if retval.getclass(space).is_same_object(w_obj.getclass(space)):
+        return retval
+    else:
+        list_of_objects.pop(idx + 1)
+        return next_instance(space, list_of_objects, w_obj)
 
 @expose_primitive(NEXT_INSTANCE, unwrap_spec=[object])
 def func(interp, s_frame, w_obj):
     # This primitive is used to iterate through all instances of a class:
     # it returns the "next" instance after w_obj.
-    return next_instance(interp.space, s_frame.instances_array(), w_obj)
+    return next_instance(
+        interp.space,
+        get_instances_array(interp.space, s_frame, w_obj.getclass(interp.space)),
+        w_obj
+    )
 
 @expose_primitive(NEW_METHOD, unwrap_spec=[object, int, int])
 def func(interp, s_frame, w_class, bytecount, header):
diff --git a/spyvm/shadow.py b/spyvm/shadow.py
--- a/spyvm/shadow.py
+++ b/spyvm/shadow.py
@@ -452,7 +452,7 @@
     def __init__(self, space, w_self):
         self._s_sender = None
         AbstractRedirectingShadow.__init__(self, space, w_self)
-        self.instances_w = None
+        self.instances_w = {}
 
     @staticmethod
     def is_block_context(w_pointers, space):
@@ -709,12 +709,13 @@
             self._w_self_size = w_self.size()
             return w_self
 
-    def store_instances_array(self, list_w):
+    def store_instances_array(self, w_class, match_w):
         # used for primitives 77 & 78
-        self.instances_w = list_w
+        self.instances_w[w_class] = match_w
 
-    def instances_array(self):
-        return self.instances_w
+    @jit.elidable
+    def instances_array(self, w_class):
+        return self.instances_w.get(w_class, None)
 
     # ______________________________________________________________________
     # Debugging printout
diff --git a/spyvm/test/test_primitives.py b/spyvm/test/test_primitives.py
--- a/spyvm/test/test_primitives.py
+++ b/spyvm/test/test_primitives.py
@@ -652,6 +652,23 @@
     assert w_2.getclass(space) is space.w_Array
     assert w_1 is not w_2
 
+def test_primitive_next_instance_wo_some_instance_in_same_frame():
+    someInstances = map(space.wrap_list, [[2], [3]])
+    from test_interpreter import new_frame
+    w_frame, s_context = new_frame("<never called, but needed for method generation>",
+        space=space)
+
+    s_context.push(space.w_Array)
+    interp = interpreter.Interpreter(space)
+    w_1 = someInstances[0]
+    assert w_1.getclass(space) is space.w_Array
+
+    s_context.push(w_1)
+    prim_table[primitives.NEXT_INSTANCE](interp, s_context, 0)
+    w_2 = s_context.pop()
+    assert w_2.getclass(space) is space.w_Array
+    assert w_1 is not w_2
+
 def test_primitive_value_no_context_switch(monkeypatch):
     class Context_switched(Exception):
         pass


More information about the pypy-commit mailing list