[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