[pypy-commit] lang-smalltalk 64bit-c2: Merged default

Hubert Hesse noreply at buildbot.pypy.org
Fri May 2 12:52:21 CEST 2014


Author: Hubert Hesse <hubert.hesse at student.hpi.uni-potsdam.de>
Branch: 64bit-c2
Changeset: r796:e6c406381c28
Date: 2014-04-24 14:41 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/e6c406381c28/

Log:	Merged default

diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -12,3 +12,5 @@
 versions
 coglinux
 *.orig
+spy-*.log
+SDL.dll
diff --git a/spyvm/model.py b/spyvm/model.py
--- a/spyvm/model.py
+++ b/spyvm/model.py
@@ -15,12 +15,14 @@
 that create W_PointersObjects of correct size with attached shadows.
 """
 import sys, weakref
-from spyvm import constants, error, system
+from spyvm import constants, error, version, system
+from spyvm.version import elidable_for_version
 
 from rpython.rlib import rrandom, objectmodel, jit, signature
 from rpython.rlib.rarithmetic import intmask, r_uint32, r_uint, r_int
+from rpython.rlib.debug import make_sure_not_resized
 from rpython.tool.pairtype import extendabletype
-from rpython.rlib.objectmodel import instantiate, compute_hash
+from rpython.rlib.objectmodel import instantiate, compute_hash, import_from_mixin
 from rpython.rtyper.lltypesystem import lltype, rffi
 from rsdl import RSDL, RSDL_helper
 
@@ -448,7 +450,7 @@
 
     def __str__(self):
         if isinstance(self, W_PointersObject) and self.has_shadow():
-            return self._shadow.getname()
+            return self._get_shadow().getname()
         else:
             name = None
             if self.has_class():
@@ -488,15 +490,20 @@
 
 class W_AbstractPointersObject(W_AbstractObjectWithClassReference):
     """Common object."""
-    _attrs_ = ['_shadow']
+    _attrs_ = ['shadow']
+    
+    def changed(self):
+        # This is invoked when an instance-variable is changed.
+        # Kept here in case it might be usefull in the future.
+        pass
 
-    _shadow = None # Default value
+    shadow = None # Default value
 
     @jit.unroll_safe
     def __init__(self, space, w_class, size):
         """Create new object with size = fixed + variable size."""
         W_AbstractObjectWithClassReference.__init__(self, space, w_class)
-        self._shadow = None # Default value
+        self.store_shadow(None)
 
     def fillin(self, space, g_self):
         from spyvm.fieldtypes import fieldtypes_of
@@ -514,12 +521,12 @@
 
     def fetch(self, space, n0):
         if self.has_shadow():
-            return self._shadow.fetch(n0)
+            return self._get_shadow().fetch(n0)
         return self._fetch(n0)
 
     def store(self, space, n0, w_value):
         if self.has_shadow():
-            return self._shadow.store(n0, w_value)
+            return self._get_shadow().store(n0, w_value)
         return self._store(n0, w_value)
 
     def varsize(self, space):
@@ -533,13 +540,17 @@
 
     def size(self):
         if self.has_shadow():
-            return self._shadow.size()
+            return self._get_shadow().size()
         return self.basic_size()
 
     def store_shadow(self, shadow):
-        assert self._shadow is None or self._shadow is shadow
-        self._shadow = shadow
+        assert self.shadow is None or self.shadow is shadow
+        self.shadow = shadow
+        self.changed()
 
+    def _get_shadow(self):
+        return self.shadow
+    
     @objectmodel.specialize.arg(2)
     def attach_shadow_of_class(self, space, TheClass):
         shadow = TheClass(space, self)
@@ -549,7 +560,7 @@
 
     @objectmodel.specialize.arg(2)
     def as_special_get_shadow(self, space, TheClass):
-        shadow = self._shadow
+        shadow = self._get_shadow()
         if not isinstance(shadow, TheClass):
             if shadow is not None:
                 raise DetachingShadowError(shadow, TheClass)
@@ -568,7 +579,7 @@
     # Should only be used during squeak-image loading.
     def as_class_get_penumbra(self, space):
         from spyvm.shadow import ClassShadow
-        s_class = self._shadow
+        s_class = self._get_shadow()
         if s_class is None:
             s_class = ClassShadow(space, self)
             self.store_shadow(s_class)
@@ -587,7 +598,7 @@
     def as_context_get_shadow(self, space):
         from spyvm.shadow import ContextPartShadow
         # XXX TODO should figure out itself if its method or block context
-        if self._shadow is None:
+        if self._get_shadow() is None:
             if ContextPartShadow.is_block_context(self, space):
                 return self.as_blockcontext_get_shadow(space)
             return self.as_methodcontext_get_shadow(space)
@@ -606,17 +617,19 @@
         return self.as_special_get_shadow(space, ObserveeShadow)
 
     def has_shadow(self):
-        return self._shadow is not None
+        return self._get_shadow() is not None
 
     def become(self, w_other):
         if not isinstance(w_other, W_AbstractPointersObject):
             return False
         # switching means also switching shadows
-        self._shadow, w_other._shadow = w_other._shadow, self._shadow
+        self.shadow, w_other.shadow = w_other.shadow, self.shadow
         # shadow links are in both directions -> also update shadows
-        if    self.has_shadow():    self._shadow._w_self = self
-        if w_other.has_shadow(): w_other._shadow._w_self = w_other
+        if    self.shadow is not None:    self.shadow._w_self = self
+        if w_other.shadow is not None: w_other.shadow._w_self = w_other
         W_AbstractObjectWithClassReference._become(self, w_other)
+        self.changed()
+        w_other.changed()
         return True
 
     @jit.elidable
@@ -633,24 +646,27 @@
         from spyvm.fieldtypes import fieldtypes_of_length
         """Create new object with size = fixed + variable size."""
         W_AbstractPointersObject.__init__(self, space, w_class, size)
-        vars = self._vars = [None] * size
+        vars = [None] * size
+        self.set_vars(vars)
         self.fieldtypes = fieldtypes_of_length(self.s_class, size)
         for i in range(size): # do it by hand for the JIT's sake
             vars[i] = w_nil
-
+    
+    def set_vars(self, new_vars):
+        self._vars = new_vars
+        make_sure_not_resized(self._vars)
+    
     def fillin(self, space, g_self):
         W_AbstractPointersObject.fillin(self, space, g_self)
         from spyvm.fieldtypes import fieldtypes_of
-        self._vars = g_self.get_pointers()
+        self.set_vars(g_self.get_pointers())
         self.fieldtypes = fieldtypes_of(self)
 
     def _fetch(self, n0):
-        # return self._vars[n0]
         fieldtypes = jit.promote(self.fieldtypes)
         return fieldtypes.fetch(self, n0)
 
     def _store(self, n0, w_value):
-        # self._vars[n0] = w_value
         fieldtypes = jit.promote(self.fieldtypes)
         return fieldtypes.store(self, n0, w_value)
 
@@ -671,7 +687,7 @@
     def clone(self, space):
         w_result = W_PointersObject(self.space, self.getclass(space),
                                     len(self._vars))
-        w_result._vars = [self.fetch(space, i) for i in range(len(self._vars))]
+        w_result.set_vars([self.fetch(space, i) for i in range(len(self._vars))])
         return w_result
 
     def fieldtype(self):
@@ -996,6 +1012,8 @@
     _attrs_ = ['pixelbuffer', '_realsize', '_real_depth_buffer', 'display', '_depth']
     _immutable_fields_ = ['_realsize', 'display', '_depth', '_real_depth_buffer']
 
+    pixelbuffer = None
+    
     @staticmethod
     def create(space, w_class, size, depth, display):
         if depth < 8:
@@ -1202,11 +1220,11 @@
         if len(self.literals) > 0:
             w_candidate = self.literals[-1]
             if isinstance(w_candidate, W_PointersObject):
-                c_shadow = w_candidate._shadow
+                c_shadow = w_candidate._get_shadow()
                 if c_shadow is None and w_candidate.size() >= 2:
                     w_class = w_candidate._fetch(1)
                     if isinstance(w_class, W_PointersObject):
-                        d_shadow = w_class._shadow
+                        d_shadow = w_class._get_shadow()
                         if isinstance(d_shadow, shadow.ClassShadow):
                             classname = d_shadow.getname()
                 elif isinstance(shadow, shadow.ClassShadow):
diff --git a/spyvm/objspace.py b/spyvm/objspace.py
--- a/spyvm/objspace.py
+++ b/spyvm/objspace.py
@@ -1,6 +1,6 @@
 import os
 
-from spyvm import constants, model, shadow, wrapper, system
+from spyvm import constants, model, shadow, wrapper, system, version
 from spyvm.error import UnwrappingError, WrappingError, PrimitiveFailedError
 from rpython.rlib import jit, rpath
 from rpython.rlib.objectmodel import instantiate, specialize
@@ -79,7 +79,7 @@
         w_Class = self.classtable["w_Class"]
         s_Metaclass = self.classtable["w_Metaclass"].as_class_get_penumbra(self)
         # XXX
-        proto_shadow = w_ProtoObjectClass._shadow
+        proto_shadow = w_ProtoObjectClass.shadow
         proto_shadow.store_w_superclass(w_Class)
         # at this point, all classes that still lack a w_class are themselves
         # metaclasses
@@ -335,7 +335,7 @@
     # XXX
     s = instantiate(shadow.ClassShadow)
     s.space = space
-    s.version = shadow.Version()
+    s.version = version.Version()
     s._w_self = w_class
     s.subclass_s = {}
     s._s_superclass = None
diff --git a/spyvm/shadow.py b/spyvm/shadow.py
--- a/spyvm/shadow.py
+++ b/spyvm/shadow.py
@@ -1,17 +1,10 @@
 import weakref
-from spyvm import model, constants, error, wrapper
+from spyvm import model, constants, error, wrapper, version
+from spyvm.version import elidable_for_version, constant_for_version
 from rpython.tool.pairtype import extendabletype
 from rpython.rlib import rarithmetic, jit
-
-def make_elidable_after_versioning(func):
-    @jit.elidable
-    def elidable_func(self, version, *args):
-        return func(self, *args)
-    def meth(self, *args):
-        jit.promote(self)
-        version = jit.promote(self.version)
-        return elidable_func(self, version, *args)
-    return meth
+from rpython.rlib.objectmodel import import_from_mixin
+from rpython.rlib.debug import make_sure_not_resized
 
 class AbstractShadow(object):
     """A shadow is an optional extra bit of information that
@@ -38,10 +31,13 @@
 class AbstractCachingShadow(AbstractShadow):
     _immutable_fields_ = ['version?']
     _attrs_ = ['version']
+    import_from_mixin(version.VersionMixin)
 
+    version = None
+    
     def __init__(self, space, w_self):
         AbstractShadow.__init__(self, space, w_self)
-        self.version = Version()
+        self.changed()
 
     def attach_shadow(self):
         self.w_self().store_shadow(self)
@@ -59,11 +55,6 @@
         AbstractShadow.store(self, n0, w_value)
         self.update()
 
-    def change(self):
-        self.version = Version()
-
-class Version:
-    pass
 # ____________________________________________________________
 
 POINTERS = 0
@@ -87,7 +78,7 @@
 
     _attrs_ = ["name", "_instance_size", "instance_varsized", "instance_kind",
                 "_s_methoddict", "_s_superclass", "subclass_s"]
-
+    
     def __init__(self, space, w_self):
         # fields added here should also be in objspace.py:56ff, 300ff
         self.name = ''
@@ -263,12 +254,12 @@
         " True if instances of this class have data stored as numerical bytes "
         return self.format == BYTES
 
-    @make_elidable_after_versioning
+    @constant_for_version
     def isvariable(self):
         " True if instances of this class have indexed inst variables "
         return self.instance_varsized
 
-    @make_elidable_after_versioning
+    @constant_for_version
     def instsize(self):
         " Number of named instance variables for each instance of this class "
         return self._instance_size
@@ -293,7 +284,7 @@
         del self.subclass_s[s_other]
 
     def changed(self):
-        self.superclass_changed(Version())
+        self.superclass_changed(version.Version())
 
     # this is done, because the class-hierarchy contains cycles
     def superclass_changed(self, version):
@@ -308,7 +299,7 @@
     def __repr__(self):
         return "<ClassShadow %s>" % (self.name or '?',)
 
-    @make_elidable_after_versioning
+    @constant_for_version
     def lookup(self, w_selector):
         look_in_shadow = self
         while look_in_shadow is not None:
@@ -646,6 +637,7 @@
         stacksize = self.stackend() - self.stackstart()
         tempsize = self.tempsize()
         self._temps_and_stack = [None] * (stacksize + tempsize)
+        make_sure_not_resized(self._temps_and_stack)
         for i in range(tempsize):
             self._temps_and_stack[i] = self.space.w_nil
         self._stack_ptr = rarithmetic.r_uint(tempsize) # we point after the last element
@@ -1033,6 +1025,7 @@
               "argsize", "islarge",
               "w_compiledin", "version"]
     _immutable_fields_ = ["version?", "_w_self"]
+    import_from_mixin(version.VersionMixin)
 
     def __init__(self, w_compiledmethod):
         self._w_self = w_compiledmethod
@@ -1041,11 +1034,11 @@
     def w_self(self):
         return self._w_self
 
-    @make_elidable_after_versioning
+    @constant_for_version
     def getliteral(self, index):
         return self.literals[index]
 
-    @make_elidable_after_versioning
+    @constant_for_version
     def compute_frame_size(self):
         # From blue book: normal mc have place for 12 temps+maxstack
         # mc for methods with islarge flag turned on 32
@@ -1058,7 +1051,7 @@
 
     def update(self):
         w_compiledmethod = self._w_self
-        self.version = Version()
+        self.changed()
         self.bytecode = "".join(w_compiledmethod.bytes)
         self.bytecodeoffset = w_compiledmethod.bytecodeoffset()
         self.literalsize = w_compiledmethod.getliteralsize()
@@ -1081,11 +1074,11 @@
                 association = wrapper.AssociationWrapper(None, w_association)
                 self.w_compiledin = association.value()
 
-    @make_elidable_after_versioning
+    @constant_for_version
     def tempsize(self):
         return self._tempsize
 
-    @make_elidable_after_versioning
+    @constant_for_version
     def primitive(self):
         return self._primitive
 
@@ -1095,26 +1088,20 @@
                 space, self, receiver, arguments, sender)
         return s_new
 
-    @make_elidable_after_versioning
+    @constant_for_version
     def getbytecode(self, pc):
         return self.bytecode[pc]
 
 class CachedObjectShadow(AbstractCachingShadow):
 
+    @elidable_for_version
     def fetch(self, n0):
-        jit.promote(self)
-        version = self.version
-        jit.promote(version)
-        return self.safe_fetch(n0, version)
-
-    @jit.elidable
-    def safe_fetch(self, n0, version):
-        assert version is self.version
         return self._w_self._fetch(n0)
 
     def store(self, n0, w_value):
-        self.version = Version()
-        return self._w_self._store(n0, w_value)
+        res = self._w_self._store(n0, w_value)
+        self.changed()
+        return res
 
     def update(self): pass
 
diff --git a/spyvm/squeakimage.py b/spyvm/squeakimage.py
--- a/spyvm/squeakimage.py
+++ b/spyvm/squeakimage.py
@@ -308,7 +308,7 @@
         for chunk in self.chunks.itervalues():
             casted = chunk.g_object.w_object
             if isinstance(casted, model.W_PointersObject) and casted.has_shadow():
-                casted._shadow.update()
+                casted.shadow.update()
 
     def init_compactclassesarray(self):
         """ from the blue book (CompiledMethod Symbol Array PseudoContext LargePositiveInteger nil MethodDictionary Association Point Rectangle nil TranslatedMethod BlockContext MethodContext nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil ) """
diff --git a/spyvm/test/jittest/base.py b/spyvm/test/jittest/base.py
--- a/spyvm/test/jittest/base.py
+++ b/spyvm/test/jittest/base.py
@@ -2,8 +2,8 @@
 import os
 
 # TODO:
-from pypy.tool.jitlogparser.parser import SimpleParser, Op
-from pypy.tool.jitlogparser.storage import LoopStorage
+from rpython.tool.jitlogparser.parser import SimpleParser, Op
+from rpython.tool.jitlogparser.storage import LoopStorage
 
 from rpython.jit.metainterp.resoperation import opname
 from rpython.jit.tool import oparser
diff --git a/spyvm/test/jittest/test_basic.py b/spyvm/test/jittest/test_basic.py
--- a/spyvm/test/jittest/test_basic.py
+++ b/spyvm/test/jittest/test_basic.py
@@ -368,6 +368,123 @@
         jump(p0, p3, p8, i557, p538, i562, p18, i545, p38, p40, p42, p44, p46, p48, p50, p52, p54, p56, p58, p60, p62, p64, p66, p68, p70, p72, p74, p76, p78, p80, p82, p84, p86, p88, p90, p92, p94, p96, p98, p100, p102, p104, p106, p108, p110, p112, p114, p116, p118, p120, p122, p124, p126, p128, p130, p132, p134, 1, p148, p717, i158, p156, p718, i165, p163, p146, i715, i179, p178, p719, i197, p188, p213, i221, p220, p228, p140, p242, i250, i252, i282, i293, i328, i315, i349, i510, p509, p538, p521, descr=TargetToken(169555520))]
         """)
 
+     # TODO: there shouldnt be allocations in this
+    def test_range_asOrderedCollection(self, spy, tmpdir):
+        traces = self.run(spy, tmpdir,
+        """
+        (1 to: 10000) asOrderedCollection.
+        """)
+        self.assert_matches(traces[0].loop, """
+ guard_not_invalidated(descr=<Guard0x2b713d0>),
+ p173 = getarrayitem_gc(p53, 1, descr=<ArrayP 4>),
+ i174 = getfield_gc_pure(p173, descr=<FieldS spyvm.model.W_SmallInteger.inst_value 8>),
+ i175 = int_ge(i174, i167),
+ guard_true(i175, descr=<Guard0x2b81490>),
+ cond_call(i75, 4712800, p67, descr=<Callv 0 r EF=2 OS=121>),
+ cond_call(i103, 4712800, p91, descr=<Callv 0 r EF=2 OS=121>),
+ cond_call(i103, 4712800, p91, descr=<Callv 0 r EF=2 OS=121>),
+ p176 = getarrayitem_gc(p105, 0, descr=<ArrayP 4>),
+ cond_call(i103, 4712800, p91, descr=<Callv 0 r EF=2 OS=121>),
+ p178 = new_with_vtable(ConstClass(W_SmallInteger)),
+ setfield_gc(p178, i167, descr=<FieldS spyvm.model.W_SmallInteger.inst_value 8>),
+ setarrayitem_gc(p105, 1, p178, descr=<ArrayP 4>),
+ setarrayitem_gc(p79, 0, p176, descr=<ArrayP 4>),
+ setfield_gc(p67, 2, descr=<FieldU spyvm.shadow.ContextPartShadow.inst__stack_ptr 32>),
+ setfield_gc(p67, 15, descr=<FieldS spyvm.shadow.ContextPartShadow.inst__pc 24>),
+ setfield_gc(p67, p0, descr=<FieldP spyvm.shadow.ContextPartShadow.inst__s_sender 28>),
+ setfield_gc(ConstPtr(ptr81), i88, descr=<FieldS spyvm.interpreter.Interpreter.inst_remaining_stack_depth 40>),
+ setarrayitem_gc(p79, 1, p178, descr=<ArrayP 4>),
+ guard_class(p176, 6040288, descr=<Guard0x2b81410>),
+ p179 = getfield_gc(p176, descr=<FieldP spyvm.model.W_AbstractObjectWithClassReference.inst_s_class 12>),
+ guard_value(p179, ConstPtr(ptr117), descr=<Guard0x2b81390>),
+ p180 = getfield_gc(p176, descr=<FieldP spyvm.model.W_AbstractPointersObject.inst__shadow 20>),
+ setarrayitem_gc(p79, 0, ConstPtr(null), descr=<ArrayP 4>),
+ setfield_gc(p67, 0, descr=<FieldU spyvm.shadow.ContextPartShadow.inst__stack_ptr 32>),
+ setfield_gc(ConstPtr(ptr81), i129, descr=<FieldS spyvm.interpreter.Interpreter.inst_remaining_stack_depth 40>),
+ setarrayitem_gc(p79, 1, ConstPtr(null), descr=<ArrayP 4>),
+ guard_isnull(p180, descr=<Guard0x2b81310>),
+ p183 = getfield_gc(p176, descr=<FieldP spyvm.model.W_PointersObject.inst_fieldtypes 28>),
+ guard_value(p183, ConstPtr(ptr133), descr=<Guard0x2b81290>),
+ p184 = getfield_gc(p176, descr=<FieldP spyvm.model.W_PointersObject.inst__vars 24>),
+ p185 = getarrayitem_gc(p184, 2, descr=<ArrayP 4>),
+ p186 = getarrayitem_gc(p184, 0, descr=<ArrayP 4>),
+ guard_class(p186, 6040288, descr=<Guard0x2b81210>),
+ p187 = getfield_gc(p186, descr=<FieldP spyvm.model.W_AbstractObjectWithClassReference.inst_s_class 12>),
+ guard_value(p187, ConstPtr(ptr144), descr=<Guard0x2b81190>),
+ p188 = getfield_gc(p186, descr=<FieldP spyvm.model.W_AbstractPointersObject.inst__shadow 20>),
+ guard_isnull(p188, descr=<Guard0x2b81110>),
+ p189 = getfield_gc(p186, descr=<FieldP spyvm.model.W_PointersObject.inst__vars 24>),
+ i190 = arraylen_gc(p189, descr=<ArrayP 4>),
+ i191 = getfield_gc_pure(p185, descr=<FieldS spyvm.model.W_SmallInteger.inst_value 8>),
+ i192 = int_eq(i191, i190),
+ guard_false(i192, descr=<Guard0x2b81090>),
+ i193 = int_add_ovf(i191, 1),
+ guard_no_overflow(descr=<Guard0x2b81010>),
+ i194 = int_ge(i191, 0),
+ guard_true(i194, descr=<Guard0x2b71f50>),
+ i195 = int_lt(i191, i190),
+ guard_true(i195, descr=<Guard0x2b71ed0>),
+ p196 = getfield_gc(p186, descr=<FieldP spyvm.model.W_PointersObject.inst_fieldtypes 28>),
+ guard_value(p196, ConstPtr(ptr156), descr=<Guard0x2b71e50>),
+ p197 = new_with_vtable(ConstClass(W_SmallInteger)),
+ setfield_gc(p197, i193, descr=<FieldS spyvm.model.W_SmallInteger.inst_value 8>),
+ setarrayitem_gc(p184, 2, p197, descr=<ArrayP 4>),
+ setarrayitem_gc(p189, i191, p178, descr=<ArrayP 4>),
+ p198 = getarrayitem_gc(p53, 2, descr=<ArrayP 4>),
+ i199 = getfield_gc_pure(p198, descr=<FieldS spyvm.model.W_SmallInteger.inst_value 8>),
+ setarrayitem_gc(p79, 0, ConstPtr(null), descr=<ArrayP 4>),
+ setfield_gc(p67, -1, descr=<FieldS spyvm.shadow.ContextPartShadow.inst__pc 24>),
+ setfield_gc(p67, ConstPtr(null), descr=<FieldP spyvm.shadow.ContextPartShadow.inst__s_sender 28>),
+ setfield_gc(ConstPtr(ptr81), i84, descr=<FieldS spyvm.interpreter.Interpreter.inst_remaining_stack_depth 40>),
+ i200 = int_add_ovf(i167, i199),
+ guard_no_overflow(descr=<Guard0x2b71dd0>),
+ i201 = int_sub(i170, 8),
+ setfield_gc(ConstPtr(ptr81), i201, descr=<FieldS spyvm.interpreter.Interpreter.inst_interrupt_check_counter 24>),
+ i202 = int_le(i201, 0),
+ guard_false(i202, descr=<Guard0x2b71d50>),
+ i203 = arraylen_gc(p53, descr=<ArrayP 4>),
+ i204 = arraylen_gc(p79, descr=<ArrayP 4>),
+ i205 = arraylen_gc(p105, descr=<ArrayP 4>),
+ jump(p0, p3, p6, i200, p14, p16, p18, p20, p22, p24, p26, p28, p30, p32, p34, p36, p38, p40, p42, p53, i75, p67, i103, p91, p105, p79, i88, i90, i129, i84, i201, descr=TargetToken(45055856))]
+        """)
+        
+    def test_indexOf(self, spy, tmpdir):
+        traces = self.run(spy, tmpdir,
+        """
+        (1 to: 10000000) asOrderedCollection indexOf: 9999999.
+        """)
+        # First loop: asOrderedCollection, second loop: makeRoomAtLast
+        self.assert_matches(traces[2].loop, """
+ guard_not_invalidated(descr=<Guard0x2bac7d0>),
+ i127 = int_le(i121, i61),
+ guard_true(i127, descr=<Guard0x2bac790>),
+ setfield_gc(ConstPtr(ptr74), i81, descr=<FieldS spyvm.interpreter.Interpreter.inst_remaining_stack_depth 40>),
+ i128 = int_add_ovf(i121, i91),
+ guard_no_overflow(descr=<Guard0x2bac750>),
+ i129 = int_sub(i128, 1),
+ i130 = int_gt(i129, i97),
+ guard_false(i130, descr=<Guard0x2bac710>),
+ i131 = int_sub(i129, 1),
+ i132 = int_ge(i131, 0),
+ guard_true(i132, descr=<Guard0x2bac6d0>),
+ i133 = int_lt(i131, i110),
+ guard_true(i133, descr=<Guard0x2bac690>),
+ p134 = getarrayitem_gc(p109, i131, descr=<ArrayP 4>),
+ setfield_gc(ConstPtr(ptr74), i77, descr=<FieldS spyvm.interpreter.Interpreter.inst_remaining_stack_depth 40>),
+ guard_nonnull_class(p134, ConstClass(W_SmallInteger), descr=<Guard0x2bac650>),
+ i135 = getfield_gc_pure(p134, descr=<FieldS spyvm.model.W_SmallInteger.inst_value 8>),
+ i136 = int_eq(i135, i118),
+ guard_false(i136, descr=<Guard0x2bac610>),
+ i137 = int_add_ovf(i121, 1),
+ guard_no_overflow(descr=<Guard0x2bac5d0>),
+ i138 = int_sub(i124, 6),
+ setfield_gc(ConstPtr(ptr74), i138, descr=<FieldS spyvm.interpreter.Interpreter.inst_interrupt_check_counter 24>),
+ i139 = int_le(i138, 0),
+ guard_false(i139, descr=<Guard0x2bac590>),
+ i140 = arraylen_gc(p88, descr=<ArrayP 4>),
+ jump(p0, p3, p6, p8, p10, i137, p14, p20, p22, p24, p26, p28, p30, p32, p34, p36, p38, p40, p42, p44, p46, p48, p50, p52, i61, i81, i91, p63, p90, i67, i97, p96, p100, i110, p109, i77, i118, i138, p88, descr=TargetToken(45201344))]
+        """)
+        
     @py.test.mark.skipif("'just dozens of long traces'")
     def test_bitblt_draw_windows(self, spy, tmpdir):
         # This used to have a call to array comparison in it
diff --git a/spyvm/test/test_interpreter.py b/spyvm/test/test_interpreter.py
--- a/spyvm/test/test_interpreter.py
+++ b/spyvm/test/test_interpreter.py
@@ -57,12 +57,12 @@
             assert space.get_special_selector(methname) is symbol
         s_class.installmethod(symbol, prim_meth)
 
-        assert space.w_nil._shadow is None
+        assert space.w_nil.shadow is None
     try:
         func(active_context) if active_context else func()
     finally:
         # Uninstall those methods:
-        assert space.w_nil._shadow is None
+        assert space.w_nil.shadow is None
         for (w_class, _, _, methname) in methods:
             s_class = w_class.as_class_get_shadow(space)
             s_class.update()
diff --git a/spyvm/test/test_largeinteger.py b/spyvm/test/test_largeinteger.py
--- a/spyvm/test/test_largeinteger.py
+++ b/spyvm/test/test_largeinteger.py
@@ -30,8 +30,7 @@
     initialize_class(w("string").getclass(tools.space))
 
 def perform_primitive(rcvr, w_selector, *args):
-
-    code = rcvr.getclass(space)._shadow.lookup(w_selector).primitive()
+    code = rcvr.getclass(space).shadow.lookup(w_selector).primitive()
     assert code
     func = primitives.prim_holder.prim_table[code]
     s_frame = MockFrame([rcvr] + list(args)).as_context_get_shadow(space)
@@ -52,7 +51,7 @@
     try:
         w_selector = space.get_special_selector(selector)
     except Exception:
-        w_selector = find_symbol_in_methoddict_of(selector, w(intmask(candidates[0])).getclass(space)._shadow)
+        w_selector = find_symbol_in_methoddict_of(selector, w(intmask(candidates[0])).getclass(space).shadow)
 
     interp.trace=trace
     for i, v in enumerate(candidates):
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
@@ -407,7 +407,7 @@
     w_o = space.wrap_list([1, 2, 3])
     w_methoddict = w_o.shadow_of_my_class(space)._s_superclass._s_superclass.w_methoddict()
     w_methoddict.as_methoddict_get_shadow(space).sync_cache()
-    selectors_w = w_methoddict._shadow.methoddict.keys()
+    selectors_w = w_methoddict.shadow.methoddict.keys()
     w_sel = None
     for sel in selectors_w:
         if sel.as_string() == 'size':
diff --git a/spyvm/test/test_objectspace.py b/spyvm/test/test_objectspace.py
--- a/spyvm/test/test_objectspace.py
+++ b/spyvm/test/test_objectspace.py
@@ -8,7 +8,7 @@
     # Heuristic to detect if this is a metaclass. Don't use apart
     # from in this test file, because classtable['w_Metaclass'] is
     # bogus after loading an image.
-    return w_cls.s_class is space.classtable['w_Metaclass']._shadow
+    return w_cls.s_class is space.classtable['w_Metaclass'].shadow
 
 def test_every_class_is_an_instance_of_a_metaclass():
     for (nm, w_cls) in space.classtable.items():
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
@@ -23,8 +23,8 @@
         self.s_class = space.w_MethodContext.as_class_get_shadow(space)
 
     def as_blockcontext_get_shadow(self):
-        self._shadow = shadow.BlockContextShadow(space, self)
-        return self._shadow
+        self.shadow = shadow.BlockContextShadow(space, self)
+        return self.shadow
 
 def wrap(x):
     if isinstance(x, int): return space.wrap_int(x)
@@ -806,13 +806,13 @@
         interp.image = Image()
 
     try:
-        monkeypatch.setattr(w_frame._shadow, "_sendSelfSelector", perform_mock)
+        monkeypatch.setattr(w_frame.shadow, "_sendSelfSelector", perform_mock)
         monkeypatch.setattr(bitblt.BitBltShadow, "sync_cache", sync_cache_mock)
         with py.test.raises(CallCopyBitsSimulation):
             prim_table[primitives.BITBLT_COPY_BITS](interp, w_frame.as_context_get_shadow(space), argument_count-1)
     finally:
         monkeypatch.undo()
-    assert w_frame._shadow.pop() is mock_bitblt # the receiver
+    assert w_frame.shadow.pop() is mock_bitblt # the receiver
 
 # Note:
 #   primitives.NEXT is unimplemented as it is a performance optimization
diff --git a/spyvm/test/test_shadow.py b/spyvm/test/test_shadow.py
--- a/spyvm/test/test_shadow.py
+++ b/spyvm/test/test_shadow.py
@@ -171,11 +171,11 @@
     w_object = blockcontext(pc=13)
     old_vars = w_object._vars
     s_object = w_object.as_blockcontext_get_shadow(space)
-    s_object._shadow = None
+    s_object.shadow = None
     s_newobject = w_object.as_blockcontext_get_shadow(space)
     assert ([s_newobject.fetch(i) for i in range(s_newobject.size())] ==
             [s_object.fetch(i) for i in range(s_newobject.size())])
-    assert w_object._shadow is s_newobject
+    assert w_object.shadow is s_newobject
 
 def test_compiledmethodshadow():
     from test_model import joinbits
@@ -222,7 +222,7 @@
     assert o.notified
     assert w_o.fetch(space, 0) == 1
     try:
-        w_o._shadow.notify(Observer())
+        w_o.shadow.notify(Observer())
     except RuntimeError:
         pass
     else:
diff --git a/spyvm/version.py b/spyvm/version.py
new file mode 100644
--- /dev/null
+++ b/spyvm/version.py
@@ -0,0 +1,40 @@
+from rpython.rlib import jit
+
+# This declares the decorated function as "pure" while the self-object
+# has an unchanged version. Neither self nor self.version are promoted to constants.
+def elidable_for_version(func):
+    @jit.elidable
+    def elidable_func(self, version, *args):
+        return func(self, *args)
+    def meth(self, *args):
+        return elidable_func(self, self.version, *args)
+    elidable_func.func_name = "elidable_" + func.func_name
+    meth.func_name = "elidable_meth_" + func.func_name
+    return meth
+
+# In addition to marking the decorated function as "pure", both the receiver
+# and the version of the receiver are promoted to constants. This should only
+# be used in situations where the receiver is very unlikely to change in the same
+# context of the interpreted program (like classes or compiled methods).
+def constant_for_version(func):
+    @jit.elidable
+    def elidable_func(self, version, *args):
+        return func(self, *args)
+    def meth(self, *args):
+        self = jit.promote(self)
+        version = jit.promote(self.version)
+        return elidable_func(self, version, *args)
+    return meth
+
+class Version(object):
+    pass
+
+class VersionMixin(object):
+    # Concrete class must define a pseudo immutable field like the following:
+    # _attrs_ = ['version']
+    # _immutable_fields_ = ['version?']
+    
+    version = Version()
+    
+    def changed(self):
+        self.version = Version()


More information about the pypy-commit mailing list