[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