Author: Anton Gulenko <anton.gule...@googlemail.com> Branch: storage Changeset: r706:9ef7a4c22818 Date: 2014-03-27 11:52 +0100 http://bitbucket.org/pypy/lang-smalltalk/changeset/9ef7a4c22818/
Log: Made _w_self and space fields of Shadows immutable. Added some additional __repr__ info to shadows. Fixed finding name of Metaclasses. Added some tests for that. Made printing of classes/metaclasses more consistent with Smalltalk's asString. diff --git a/spyvm/model.py b/spyvm/model.py --- a/spyvm/model.py +++ b/spyvm/model.py @@ -469,10 +469,6 @@ def repr_content(self): return 'len=%d %s' % (self.size(), self.str_content()) - def space(self): - assert self.shadow, "Cannot access space without a shadow!" - return self.shadow.space - def fillin(self, space, g_self): W_AbstractObjectWithIdentityHash.fillin(self, space, g_self) self.w_class = g_self.get_class() @@ -482,15 +478,12 @@ def guess_classname(self): if self.has_class(): - from shadow import ClassShadow - if isinstance(self.w_class.shadow, ClassShadow): - return self.w_class.shadow.name or "???" - else: - # If the shadow of w_class is not yet converted to a ClassShadow, - # we cannot get the classname, unfortunately. No space available. - return "?" + class_shadow = self.class_shadow(self.w_class.space()) + # Three question marks, because it would be highly irregular to have + # an initialized ClassShadow without an initialized name field. + return class_shadow.name or "???" else: - return "??" + return "? (no class)" def invariant(self): from spyvm import shadow @@ -572,6 +565,10 @@ self.initialize_storage(space, len(pointers)) self.store_all(space, pointers) + def space(self): + assert self.shadow, "Cannot access space without a shadow!" + return self.shadow.space + def __str__(self): if self.has_shadow() and self.shadow.provides_getname: return self._get_shadow().getname() @@ -774,8 +771,8 @@ def size(self): return self._size - def __str__(self): - return self.as_string() + def str_content(self): + return "'%s'" % self.as_string() def as_string(self): if self.bytes is not None: diff --git a/spyvm/objspace.py b/spyvm/objspace.py --- a/spyvm/objspace.py +++ b/spyvm/objspace.py @@ -46,6 +46,8 @@ name = "w_" + name if not name in self.objtable or not self.objtable[name]: self.objtable[name] = specials[idx] + # XXX this is kind of hacky, but I don't know where else to get Metaclass + self.classtable["w_Metaclass"] = self.w_SmallInteger.w_class.w_class def executable_path(self): return self._executable_path[0] diff --git a/spyvm/shadow.py b/spyvm/shadow.py --- a/spyvm/shadow.py +++ b/spyvm/shadow.py @@ -11,7 +11,9 @@ can be attached at run-time to any Smalltalk object. """ _attrs_ = ['_w_self', 'space'] + _immutable_fields_ = ['_w_self', 'space'] provides_getname = False + repr_classname = "AbstractShadow" def __init__(self, space, w_self): self.space = space @@ -19,7 +21,12 @@ def w_self(self): return self._w_self def getname(self): - return repr(self) + raise NotImplementedError("Abstract class") + def __repr__(self): + if self.provides_getname: + return "<%s %s>" % (self.repr_classname, self.getname()) + else: + return "<%s>" % self.repr_classname def fetch(self, n0): raise NotImplementedError("Abstract class") @@ -41,6 +48,7 @@ class ListStorageShadow(AbstractShadow): _attrs_ = ['storage'] + repr_classname = "ListStorageShadow" def __init__(self, space, w_self, size): AbstractShadow.__init__(self, space, w_self) @@ -61,6 +69,7 @@ class WeakListStorageShadow(AbstractShadow): _attrs_ = ['storage'] + repr_classname = "WeakListStorageShadow" def __init__(self, space, w_self, size): AbstractShadow.__init__(self, space, w_self) @@ -78,6 +87,7 @@ class AbstractCachingShadow(ListStorageShadow): _immutable_fields_ = ['version?'] _attrs_ = ['version'] + repr_classname = "AbstractCachingShadow" import_from_mixin(version.VersionMixin) version = None @@ -108,13 +118,12 @@ _attrs_ = ["name", "_instance_size", "instance_varsized", "instance_kind", "_s_methoddict", "_s_superclass", "subclass_s"] - name = None + name = '??' + _s_superclass = None provides_getname = True + repr_classname = "ClassShadow" def __init__(self, space, w_self): - # fields added here should also be in objspace.py:56ff, 300ff - self.name = '?' - self._s_superclass = None self.subclass_s = {} AbstractCachingShadow.__init__(self, space, w_self) @@ -168,23 +177,19 @@ self.instance_kind = COMPILED_METHOD else: raise ClassShadowError("unknown format %d" % (format,)) - elif n0 == constants.CLASS_NAME_INDEX: - self.store_w_name(w_val) - elif n0 == self.size() - 1: - # In case of Metaclasses, the "instance" class is stored in the last field. - # TODO - only do this if we are sure this is a Metaclass. Check out space.w_Metaclass. - if isinstance(w_val, model.W_PointersObject): - cl_shadow = w_val.shadow - if isinstance(cl_shadow, ClassShadow): - # If we're lucky, it's already a class shadow and we can reuse the stored information - if cl_shadow.name: - self.name = "%s class" % cl_shadow.name - elif w_val.size() >= constants.CLASS_NAME_INDEX: - # If not, we have to extract the class name - w_classname = w_val.fetch(self.space, constants.CLASS_NAME_INDEX) - self.store_w_name(w_classname) else: - return + if self._w_self.w_class == self.space.classtable["w_Metaclass"]: + # In case of Metaclasses, the "instance" class is stored in the last field. + if n0 == self.size() - 1 and isinstance(w_val, model.W_PointersObject): + cl_shadow = w_val.as_class_get_shadow(self.space) + self.name = "%s class" % cl_shadow.getname() + else: + return + elif n0 == constants.CLASS_NAME_INDEX: + # In case of regular classes, the name is stored here. + self.store_w_name(w_val) + else: + return # Some of the special info has changed -> Switch version. self.changed() @@ -255,7 +260,7 @@ return self._s_superclass def getname(self): - return "%s class" % (self.name or '?',) + return self.name or '?' # _______________________________________________________________ # Methods for querying the format word, taken from the blue book: @@ -290,9 +295,6 @@ # _______________________________________________________________ # Other Methods - def __repr__(self): - return "<ClassShadow %s>" % (self.name or '?',) - @constant_for_version def lookup(self, w_selector): look_in_shadow = self @@ -348,7 +350,8 @@ _immutable_fields_ = ['invalid?', 's_class'] _attrs_ = ['methoddict', 'invalid', 's_class'] - + repr_classname = "MethodDictionaryShadow" + def __init__(self, space, w_self): self.invalid = True self.s_class = None @@ -415,7 +418,8 @@ class AbstractRedirectingShadow(AbstractShadow): _attrs_ = ['_w_self_size'] - + repr_classname = "AbstractRedirectingShadow" + def __init__(self, space, w_self): AbstractShadow.__init__(self, space, w_self) if w_self is not None: @@ -431,7 +435,8 @@ __metaclass__ = extendabletype _attrs_ = ['_s_sender', '_pc', '_temps_and_stack', '_stack_ptr', 'instances_w'] - + repr_classname = "ContextPartShadow" + _virtualizable_ = [ "_s_sender", "_pc", "_temps_and_stack[*]", "_stack_ptr", @@ -754,7 +759,8 @@ class BlockContextShadow(ContextPartShadow): _attrs_ = ['_w_home', '_initialip', '_eargc'] - + repr_classname = "BlockContextShadow" + def __init__(self, space, w_self=None, w_home=None, argcnt=0, initialip=0): self = jit.hint(self, access_directly=True, fresh_virtualizable=True) creating_w_self = w_self is None @@ -857,7 +863,8 @@ class MethodContextShadow(ContextPartShadow): _attrs_ = ['w_closure_or_nil', '_w_receiver', '_w_method'] - + repr_classname = "MethodContextShadow" + @jit.unroll_safe def __init__(self, space, w_self=None, s_method=None, w_receiver=None, arguments=None, s_sender=None, closure=None, pc=0): @@ -1020,7 +1027,8 @@ "w_compiledin", "version"] _immutable_fields_ = ["version?", "_w_self"] import_from_mixin(version.VersionMixin) - + repr_classname = "CompiledMethodShadow" + def __init__(self, w_compiledmethod, space): self._w_self = w_compiledmethod self.space = space @@ -1087,6 +1095,7 @@ return self.bytecode[pc] class CachedObjectShadow(AbstractCachingShadow): + repr_classname = "CachedObjectShadow" @elidable_for_version def fetch(self, n0): @@ -1098,6 +1107,7 @@ class ObserveeShadow(ListStorageShadow): _attrs_ = ['dependent'] + repr_classname = "ObserveeShadow" def __init__(self, space, w_self): ListStorageShadow.__init__(self, space, w_self, 0) self.dependent = None diff --git a/spyvm/test/test_miniimage.py b/spyvm/test/test_miniimage.py --- a/spyvm/test/test_miniimage.py +++ b/spyvm/test/test_miniimage.py @@ -69,32 +69,48 @@ assert isinstance(w_float_class_name, model.W_BytesObject) assert w_float_class_name.bytes == list("Float") -def test_str_w_object(): +# TODO - many of these test would belong in test_model.py + +def test_str_float(): + assert str(space.wrap_float(3.0)) == "a Float(3.000000)" + +def test_str_string(): + assert str(space.wrap_string('hello')) == "a String('hello')" + +def test_str_float(): + assert str(space.wrap_float(3.0)) == "a Float(3.000000)" + +def test_str_class_object(): w_float_class = get_float_class() w_float_class.as_class_get_shadow(space) - assert str(w_float_class) == "Float class" + assert str(w_float_class) == "Float" + w_float_class.class_shadow(space) - #assert str(w_float_class.getclass(space)) == "a Metaclass" #yes, with article + assert str(w_float_class.getclass(space)) == "Float class" + w_float_class.getclass(space).class_shadow(space) - #assert str(w_float_class.getclass(space).getclass(space)) == "Metaclass class" + assert str(w_float_class.getclass(space).getclass(space)) == "Metaclass" + + w_float_class.getclass(space).getclass(space).class_shadow(space) + assert str(w_float_class.getclass(space).getclass(space).getclass(space)) == "Metaclass class" def test_nil_true_false(): image = get_image() w = image.special(constants.SO_NIL) w.class_shadow(space) - assert str(w) == "a UndefinedObject" #yes, with article + assert str(w) == "a UndefinedObject" w = image.special(constants.SO_FALSE) w.class_shadow(space) - assert str(w) == "a False" #yes, with article + assert str(w) == "a False" w = image.special(constants.SO_TRUE) w.class_shadow(space) - assert str(w) == "a True" #yes, with article + assert str(w) == "a True" def test_scheduler(): image = get_image() w = image.special(constants.SO_SCHEDULERASSOCIATIONPOINTER) w0 = w.fetch(space, 0) - assert str(w0) == "Processor" + assert str(w0) == "a Symbol('Processor')" w0 = w.fetch(space, 1) w0.class_shadow(space) assert str(w0) == "a ProcessorScheduler" @@ -106,15 +122,15 @@ assert str(obj) == expected_name image = get_image() # w = image.special(constants.SO_BITMAP_CLASS) - # assert str(w) == "Bitmap class" - test_classname(constants.SO_SMALLINTEGER_CLASS, "SmallInteger class") - test_classname(constants.SO_ARRAY_CLASS, "Array class") - test_classname(constants.SO_FLOAT_CLASS, "Float class") - test_classname(constants.SO_METHODCONTEXT_CLASS, "MethodContext class") - test_classname(constants.SO_BLOCKCONTEXT_CLASS, "BlockContext class") - test_classname(constants.SO_POINT_CLASS, "Point class") - test_classname(constants.SO_LARGEPOSITIVEINTEGER_CLASS, "LargePositiveInteger class") - test_classname(constants.SO_MESSAGE_CLASS, "Message class") + # assert str(w) == "Bitmap" + test_classname(constants.SO_SMALLINTEGER_CLASS, "SmallInteger") + test_classname(constants.SO_ARRAY_CLASS, "Array") + test_classname(constants.SO_FLOAT_CLASS, "Float") + test_classname(constants.SO_METHODCONTEXT_CLASS, "MethodContext") + test_classname(constants.SO_BLOCKCONTEXT_CLASS, "BlockContext") + test_classname(constants.SO_POINT_CLASS, "Point") + test_classname(constants.SO_LARGEPOSITIVEINTEGER_CLASS, "LargePositiveInteger") + test_classname(constants.SO_MESSAGE_CLASS, "Message") # to be continued @@ -141,8 +157,8 @@ def test_special_objects0(): image = get_image() w = image.special(constants.SO_DOES_NOT_UNDERSTAND) - assert str(w) == "doesNotUnderstand:" - assert str(w.getclass(space)) == "Symbol class" # for some strange reason not a symbol + assert str(w) == "a Symbol('doesNotUnderstand:')" + assert str(w.getclass(space)) == "Symbol" # for some strange reason not a symbol """ @@ -328,7 +344,7 @@ assert w_message_cls is interp.space.classtable["w_Message"] assert isinstance(w_message_cls, model.W_PointersObject) s_message_cls = w_message_cls.as_class_get_shadow(interp.space) - assert s_message_cls.getname() == "Message class" + assert s_message_cls.getname() == "Message" w_message = s_message_cls.new() assert isinstance(w_message, model.W_PointersObject) diff --git a/targetimageloadingsmalltalk.py b/targetimageloadingsmalltalk.py --- a/targetimageloadingsmalltalk.py +++ b/targetimageloadingsmalltalk.py @@ -10,6 +10,9 @@ from spyvm.tool.analyseimage import create_image from spyvm.interpreter_proxy import VirtualMachine +def print_result(w_result): + # This will also print contents of strings/symbols/numbers + print w_result.as_repr_string().replace('\r', '\n') def _run_benchmark(interp, number, benchmark, arg): from spyvm.plugins.vmdebugging import stop_ui_process @@ -46,8 +49,7 @@ w_result = _run_image(interp) t2 = time.time() if w_result: - if isinstance(w_result, model.W_BytesObject): - print w_result.as_string().replace('\r', '\n') + print_result(w_result) print "took %s seconds" % (t2 - t1) return 0 return -1 @@ -90,10 +92,7 @@ print e.msg return 1 if w_result: - if isinstance(w_result, model.W_BytesObject): - print w_result.as_string().replace('\r', '\n') - else: - print w_result.as_repr_string().replace('\r', '\n') + print_result(w_result) return 0 else: return _run_benchmark(interp, 0, selector, "") _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit