[pypy-commit] lang-smalltalk default: (tfel, lwassermann): added someInstance and nextInstance primitives

lwassermann noreply at buildbot.pypy.org
Thu Feb 28 18:37:04 CET 2013


Author: Lars Wassermann <lars.wassermann at gmail.com>
Branch: 
Changeset: r106:9aed68db55d8
Date: 2013-02-28 16:36 +0100
http://bitbucket.org/pypy/lang-smalltalk/changeset/9aed68db55d8/

Log:	(tfel, lwassermann): added someInstance and nextInstance primitives
	iterating over all instances works in
	test_bootstrappedimage>>#test_create_new_symbol

diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py
--- a/spyvm/interpreter.py
+++ b/spyvm/interpreter.py
@@ -90,12 +90,20 @@
             w_new_context = self.step(s_active_context)
             if w_new_context is not None:
                 s_active_context = w_new_context.as_context_get_shadow(self.space)
+                # m = s_active_context.w_method()
+                # try:
+                #     print m.literals[-1]._vars[-1], ">>", m._likely_methodname
+                # except IndexError, AttributeError:
+                #     print  "? >>", m._likely_methodname
 
     def perform(self, w_receiver, selector, *arguments_w):
-        if selector == "asSymbol":
-            w_selector = self.image.w_asSymbol
+        if isinstance(selector, str):
+            if selector == "asSymbol":
+                w_selector = self.image.w_asSymbol
+            else:
+                w_selector = self.perform(self.space.wrap_string(selector), "asSymbol")
         else:
-            w_selector = self.perform(self.space.wrap_string(selector), "asSymbol")
+            w_selector = selector
 
         w_method = model.W_CompiledMethod()
         w_method.setbytes([chr(124)]) #returnTopFromMethod
diff --git a/spyvm/model.py b/spyvm/model.py
--- a/spyvm/model.py
+++ b/spyvm/model.py
@@ -103,6 +103,12 @@
     def clone(self, space):
         raise NotImplementedError
 
+    def has_class(self):
+        """All Smalltalk objects should have classes. Unfortuantely for
+        bootstrapping the metaclass-cycle and during testing, that is not
+        true for some W_PointersObjects"""
+        return True
+
 class W_SmallInteger(W_Object):
     """Boxed integer value"""
     # TODO can we tell pypy that its never larger then 31-bit?
@@ -210,7 +216,7 @@
     Float)."""
 
     def __init__(self, w_class):
-        if w_class is not None:     # it's None only for testing
+        if w_class is not None:     # it's None only for testing and space generation
             assert isinstance(w_class, W_PointersObject)
         self.w_class = w_class
 
@@ -237,6 +243,9 @@
     def _become(self, w_other):
         self.w_class, w_other.w_class = w_other.w_class, self.w_class
         W_AbstractObjectWithIdentityHash._become(self, w_other)
+
+    def has_class(self):
+        return self.w_class is not None
         
 
 class W_PointersObject(W_AbstractObjectWithClassReference):
diff --git a/spyvm/primitives.py b/spyvm/primitives.py
--- a/spyvm/primitives.py
+++ b/spyvm/primitives.py
@@ -445,13 +445,41 @@
     # 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?
-    raise PrimitiveNotYetWrittenError()
+    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))
+
+    while pending:
+        gcref = pending.pop()
+        if rgc.get_gcflag_extra(gcref):
+            rgc.toggle_gcflag_extra(gcref)
+            pending.extend(rgc.get_rpy_referents(gcref))
+
+    s_frame.store_instances_array(match_w)
+    try:
+        return match_w.pop()
+    except IndexError:
+        raise PrimitiveFailedError()
 
 @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.
-    raise PrimitiveNotYetWrittenError()
+    try:
+        return s_frame.instances_array().pop()
+    except IndexError:
+        raise PrimitiveFailedError()
 
 @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
@@ -529,6 +529,13 @@
     def tempsize(self):
         raise NotImplementedError()
 
+    def store_instances_array(self, list_w):
+        # used for primitives 77 & 78
+        self.instances_w = list_w
+
+    def instances_array(self):
+        return self.instances_w
+
 class BlockContextShadow(ContextPartShadow):
 
     @staticmethod
diff --git a/spyvm/test/test_bootstrappedimage.py b/spyvm/test/test_bootstrappedimage.py
--- a/spyvm/test/test_bootstrappedimage.py
+++ b/spyvm/test/test_bootstrappedimage.py
@@ -1,22 +1,38 @@
 import py
 from spyvm import squeakimage, model, constants
 from spyvm import interpreter, shadow, objspace
-from spyvm.test import test_miniimage as testhelper
+from spyvm.test import test_miniimage as tools
 from spyvm.test.test_miniimage import perform, w
 
-testhelper.setup_module(testhelper, filename='bootstrapped.image')
+tools.setup_module(tools, filename='bootstrapped.image')
+
+def find_symbol_in_methoddict_of(string, s_class):
+    methoddict_w = s_class.s_methoddict().methoddict
+    for each in methoddict_w.keys():
+        if each.as_string() == string:
+            return each
+
+def initialize_class(w_class):
+    initialize_symbol = find_symbol_in_methoddict_of("initialize", 
+                        w_class.shadow_of_my_class(tools.space))
+    perform(w_class, initialize_symbol)
+
 
 def test_symbol_asSymbol():
-    w_result = perform(testhelper.image.w_asSymbol, "asSymbol")
-    assert w_result is testhelper.image.w_asSymbol
+    w_result = perform(tools.image.w_asSymbol, "asSymbol")
+    assert w_result is tools.image.w_asSymbol
 
 def test_create_new_symbol():
-    w_result = perform(w("someString"), "asSymbol")
+    string = w("someString")
+    # initialize String class
+    initialize_class(string.getclass(tools.space))
+
+    w_result = perform(string, "asSymbol")
     assert w_result is not None
     assert w_result.as_string() == "someString"
 
 def test_retrieve_symbol():
-    py.test.skip("This implementation is based on a working allInstancesDo -> implement primitive 77 and such")
+    py.test.skip("unknown stack error")
     """asSymbol
     "This is the only place that new Symbols are created. A Symbol is created 
     if and only if there is not already a Symbol with its contents in existance."
@@ -25,10 +41,10 @@
             self = sym
                 ifTrue: [ ^ sym ] ].
     ^ (Symbol basicNew: self size) initFrom: self"""
+    initialize_class(w("ab").getclass(tools.space))
     w_result = perform(w("someString"), "asSymbol")
     w_anotherSymbol = perform(w("someString"), "asSymbol")
     assert w_result is w_anotherSymbol
 
-
 def test_all_pointers_are_valid():
-    testhelper.test_all_pointers_are_valid()
\ No newline at end of file
+    tools.test_all_pointers_are_valid()
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
@@ -18,6 +18,7 @@
         s_self.reset_stack()
         s_self.push_all(stack)
         s_self.store_expected_argument_count(0)
+        self.w_class = space.w_MethodContext
     
     def as_blockcontext_get_shadow(self):
         self._shadow = shadow.BlockContextShadow(space, self)
@@ -509,6 +510,29 @@
     assert s_new_context.gettemp(1) == "second arg"
     assert s_new_context.gettemp(2) == "some value"
 
+def test_primitive_some_instance():
+    someInstance = map(space.wrap_list, [[1], [2]])
+    w_r = prim(primitives.SOME_INSTANCE, [space.w_Array])
+    assert w_r.getclass(space) is space.w_Array
+
+def test_primitive_next_instance():
+    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)
+    prim_table[primitives.SOME_INSTANCE](interp, s_context, 0)
+    w_1 = s_context.pop()
+    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
+
 # Note:
 #   primitives.NEXT is unimplemented as it is a performance optimization
 #   primitives.NEXT_PUT is unimplemented as it is a performance optimization


More information about the pypy-commit mailing list