[pypy-commit] lang-smalltalk storage: Renamed _likely_methodname to lookup_selector and w_compiledin to lookup_class.

anton_gulenko noreply at buildbot.pypy.org
Mon Apr 7 13:52:32 CEST 2014


Author: Anton Gulenko <anton.gulenko at googlemail.com>
Branch: storage
Changeset: r777:a35c94b4657f
Date: 2014-04-04 19:13 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/a35c94b4657f/

Log:	Renamed _likely_methodname to lookup_selector and w_compiledin to
	lookup_class. Added other field to CompiledMethod (compiledin_class)
	to explicitely handle the two sources of information [ a) the class
	where the CompiledMethod was looked up in and b) the last literal
	containing the compiledin-class, which is not available in older
	images ]. Reason for these refactorings was to get rid of a JIT
	warning saying that an elidable function might have random effects
	(the previous implementation of compiled_in()).

diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py
--- a/spyvm/interpreter.py
+++ b/spyvm/interpreter.py
@@ -345,9 +345,9 @@
                                   receiver, receiver.class_shadow(self.space))
 
     def _sendSuperSelector(self, w_selector, argcount, interp):
-        w_compiledin = self.w_method().compiled_in()
-        assert isinstance(w_compiledin, model.W_PointersObject)
-        s_compiledin = w_compiledin.as_class_get_shadow(self.space)
+        compiledin_class = self.w_method().compiled_in()
+        assert isinstance(compiledin_class, model.W_PointersObject)
+        s_compiledin = compiledin_class.as_class_get_shadow(self.space)
         return self._sendSelector(w_selector, argcount, interp, self.w_receiver(),
                                   s_compiledin.s_superclass())
 
diff --git a/spyvm/model.py b/spyvm/model.py
--- a/spyvm/model.py
+++ b/spyvm/model.py
@@ -1176,9 +1176,10 @@
                 # Main method content
                 "bytes", "literals", 
                 # Additional info about the method
-                "_likely_methodname", "w_compiledin" ]
+                "lookup_selector", "compiledin_class", "lookup_class" ]
 
-    _likely_methodname = "<unknown>"
+    lookup_selector = "<unknown>"
+    lookup_class = None
     import_from_mixin(version.VersionMixin)
     
     def __init__(self, space, bytecount=0, header=0):
@@ -1202,19 +1203,24 @@
         self._tempsize = tempsize
         self._primitive = _primitive
         self.islarge = islarge
-        self.w_compiledin = None
+        self.compiledin_class = None
         self.changed()
         
     def setliteral(self, index, w_lit):
         self.literals[index] = w_lit
         if index == len(self.literals):
-            self.w_compiledin = None
+            self.compiledin_class = None
         self.changed()
     
     def setliterals(self, literals):
         """NOT RPYTHON""" # Only for testing, not safe.
         self.literals = literals
-        self.w_compiledin = None
+        self.compiledin_class = None
+        self.changed()
+    
+    def set_lookup_class_and_name(self, w_class, selector):
+        self.lookup_class = w_class
+        self.lookup_selector = selector
         self.changed()
     
     def setbytes(self, bytes):
@@ -1226,11 +1232,6 @@
         self.bytes[index0] = character
         self.changed()
     
-    def set_compiled_in(self, w_compiledin):
-        if not self.w_compiledin:
-            self.w_compiledin = w_compiledin
-            self.changed()
-    
     # === Getters ===
         
     def getclass(self, space):
@@ -1278,36 +1279,32 @@
         assert pc >= 0 and pc < len(self.bytes)
         return self.bytes[pc]
     
+    def compiled_in(self):
+        # This method cannot be constant/elidable. Looking up the compiledin-class from
+        # the literals must be done lazily because we cannot analyze the literals
+        # properly during the fillin-phase.
+        
+        # Prefer the information stored in the CompiledMethod literal...
+        result = self.constant_lookup_class()
+        if not result:
+            # ...but fall back to our own information if nothing else available.
+            result = self.constant_compiledin_class()
+            if not result:
+                self.update_compiledin_class_from_literals()
+                result = self.constant_compiledin_class()
+        assert result is None or isinstance(result, W_PointersObject)
+        return result
+    
     @constant_for_version
-    def compiled_in(self):
-        w_compiledin = self.w_compiledin
-        if not w_compiledin:
-            # If the method has not been looked up from a methoddict yet, try to get the
-            # containing class from it's literals. This should be rare in practice.
-            w_compiledin = self.compiled_in_from_literals()
-            self.w_compiledin = w_compiledin
-        assert w_compiledin is None or isinstance(w_compiledin, W_PointersObject)
-        return w_compiledin
+    def constant_compiledin_class(self):
+        return self.compiledin_class
     
-    @jit.dont_look_inside # Tracing into this function is useless.
-    def compiled_in_from_literals(self):
-        w_compiledin = None
-        literals = self.literals
-        if literals and len(literals) > 0:
-            # (Blue book, p 607) Last of the literals is either the containing class 
-            # or an association with compiledin as a class
-            w_candidate = literals[-1]
-            if isinstance(w_candidate, W_PointersObject) and w_candidate.has_space():
-                space = w_candidate.space() # Not pretty to steal the space from another object.
-                if w_candidate.is_class(space):
-                    w_compiledin = w_candidate
-                elif w_candidate.size() >= 2:
-                    from spyvm import wrapper
-                    association = wrapper.AssociationWrapper(space, w_candidate)
-                    w_candidate = association.value()
-                    if w_candidate.is_class(space):
-                        w_compiledin = w_candidate
-        return w_compiledin
+    @constant_for_version
+    def constant_lookup_class(self):
+        return self.lookup_class
+    
+    def safe_compiled_in(self):
+        return self.constant_compiledin_class() or self.constant_lookup_class()
     
     # === Object Access ===
     
@@ -1353,6 +1350,27 @@
     
     # === Misc ===
     
+    def update_compiledin_class_from_literals(self):
+        # (Blue book, p 607) Last of the literals is either the containing class 
+        # or an association with compiledin as a class
+        literals = self.literals
+        if literals and len(literals) > 0:
+            w_literal = literals[-1]
+            if isinstance(w_literal, W_PointersObject) and w_literal.has_space():
+                space = w_literal.space() # Not pretty to steal the space from another object.
+                compiledin_class = None
+                if w_literal.is_class(space):
+                    compiledin_class = w_literal
+                elif w_literal.size() >= 2:
+                    from spyvm import wrapper
+                    association = wrapper.AssociationWrapper(space, w_literal)
+                    w_literal = association.value()
+                    if w_literal.is_class(space):
+                        compiledin_class = w_literal
+                if compiledin_class:
+                    self.compiledin_class = w_literal
+                    self.changed()
+    
     def _become(self, w_other):
         assert isinstance(w_other, W_CompiledMethod)
         self.argsize, w_other.argsize = w_other.argsize, self.argsize
@@ -1363,8 +1381,8 @@
         self.header, w_other.header = w_other.header, self.header
         self.literalsize, w_other.literalsize = w_other.literalsize, self.literalsize
         self.islarge, w_other.islarge = w_other.islarge, self.islarge
-        self._likely_methodname, w_other._likely_methodname = w_other._likely_methodname, self._likely_methodname
-        self.w_compiledin, w_other.w_compiledin = w_other.w_compiledin, self.w_compiledin
+        self.lookup_selector, w_other.lookup_selector = w_other.lookup_selector, self.lookup_selector
+        self.compiledin_class, w_other.compiledin_class = w_other.compiledin_class, self.compiledin_class
         W_AbstractObjectWithIdentityHash._become(self, w_other)
         self.changed()
         w_other.changed()
@@ -1373,6 +1391,8 @@
         copy = W_CompiledMethod(space, 0, self.getheader())
         copy.bytes = list(self.bytes)
         copy.literals = list(self.literals)
+        copy.compiledin_class = self.compiledin_class
+        copy.lookup_selector = self.lookup_selector
         copy.changed()
         return copy
 
@@ -1424,20 +1444,20 @@
         return "? (no compiledin-info)"
     
     def get_identifier_string(self):
-        return "%s >> #%s" % (self.guess_containing_classname(), self._likely_methodname)
+        return "%s >> #%s" % (self.guess_containing_classname(), self.lookup_selector)
 
     def safe_identifier_string(self):
         if not we_are_translated():
             return self.get_identifier_string()
         # This has the same functionality as get_identifier_string, but without calling any
         # methods in order to avoid side effects that prevent translation.
-        w_class = self.w_compiledin
+        w_class = self.safe_compiled_in()
         if isinstance(w_class, W_PointersObject):
             from spyvm.shadow import ClassShadow
             s_class = w_class.shadow
             if isinstance(s_class, ClassShadow):
-                return "%s >> #%s" % (s_class.getname(), self._likely_methodname)
-        return "#%s" % self._likely_methodname
+                return "%s >> #%s" % (s_class.getname(), self.lookup_selector)
+        return "#%s" % self.lookup_selector
 
 class DetachingShadowError(Exception):
     def __init__(self, old_shadow, new_shadow_class):
diff --git a/spyvm/primitives.py b/spyvm/primitives.py
--- a/spyvm/primitives.py
+++ b/spyvm/primitives.py
@@ -372,7 +372,7 @@
 @expose_primitive(FAIL)
 def func(interp, s_frame, argcount):
     from spyvm.error import Exit
-    if s_frame.w_method()._likely_methodname == 'doesNotUnderstand:':
+    if s_frame.w_method().lookup_selector == 'doesNotUnderstand:':
         print ''
         print s_frame.print_stack()
         w_message = s_frame.peek(0)
diff --git a/spyvm/shadow.py b/spyvm/shadow.py
--- a/spyvm/shadow.py
+++ b/spyvm/shadow.py
@@ -382,9 +382,13 @@
             if methoddict is s_new_methoddict:
                 return
             if methoddict: methoddict.s_class = None
-            self._s_methoddict = s_new_methoddict
-            self._s_methoddict.s_class = self
-            
+            self.store_s_methoddict(s_new_methoddict)
+    
+    def store_s_methoddict(self, s_methoddict):
+        s_methoddict.s_class = self
+        s_methoddict.sync_method_cache()
+        self._s_methoddict = s_methoddict
+    
     def attach_s_class(self, s_other):
         self.subclass_s[s_other] = None
 
@@ -480,7 +484,6 @@
         while look_in_shadow is not None:
             w_method = look_in_shadow.s_methoddict().find_selector(w_selector)
             if w_method is not None:
-                w_method.set_compiled_in(look_in_shadow.w_self())
                 return w_method
             look_in_shadow = look_in_shadow._s_superclass
         raise MethodNotFound(self, w_selector)
@@ -513,8 +516,7 @@
         if self._s_methoddict is None:
             w_methoddict = model.W_PointersObject(self.space, None, 2)
             w_methoddict.store(self.space, 1, model.W_PointersObject(self.space, None, 0))
-            self._s_methoddict = w_methoddict.as_methoddict_get_shadow(self.space)
-            self.s_methoddict().sync_method_cache()
+            self.store_s_methoddict(w_methoddict.as_methoddict_get_shadow(self.space))
         self.s_methoddict().invalid = False
 
     def installmethod(self, w_selector, w_method):
@@ -523,7 +525,7 @@
         self.initialize_methoddict()
         self.s_methoddict().methoddict[w_selector] = w_method
         if isinstance(w_method, model.W_CompiledMethod):
-            w_method.w_compiledin = self.w_self()
+            w_method.compiledin_class = self.w_self()
 
 class MethodDictionaryShadow(ListStorageShadow):
 
@@ -537,9 +539,6 @@
         self.methoddict = {}
         ListStorageShadow.__init__(self, space, w_self, 0)
 
-    def attach_shadow(self):
-        self.sync_method_cache()
-        
     def update(self):
         self.sync_method_cache()
         
@@ -558,12 +557,6 @@
         ListStorageShadow.store(self, n0, w_value)
         self.invalid = True
 
-    def _as_md_entry(self, w_selector):
-        if isinstance(w_selector, model.W_BytesObject):
-            return w_selector.as_string()
-        else:
-            return "%r" % w_selector # use the pointer for this
-
     def sync_method_cache(self):
         if self.size() == 0:
             return
@@ -576,7 +569,10 @@
         for i in range(size):
             w_selector = self.w_self().fetch(self.space, constants.METHODDICT_NAMES_INDEX+i)
             if not w_selector.is_nil(self.space):
-                if not isinstance(w_selector, model.W_BytesObject):
+                if isinstance(w_selector, model.W_BytesObject):
+                    selector = w_selector.as_string()
+                else:
+                    selector = "? (non-byteobject selector)"
                     pass
                     # TODO: Check if there's more assumptions about this.
                     #       Putting any key in the methodDict and running with
@@ -588,9 +584,8 @@
                                        "CompiledMethods only, for now. "
                                        "If the value observed is nil, our "
                                        "invalidating mechanism may be broken.")
-                selector = self._as_md_entry(w_selector)
                 self.methoddict[w_selector] = w_compiledmethod
-                w_compiledmethod._likely_methodname = selector
+                w_compiledmethod.set_lookup_class_and_name(self.s_class.w_self(), selector)
         if self.s_class:
             self.s_class.changed()
         self.invalid = False
diff --git a/spyvm/test/test_model.py b/spyvm/test/test_model.py
--- a/spyvm/test/test_model.py
+++ b/spyvm/test/test_model.py
@@ -93,8 +93,6 @@
     class mockmethod(object):
         def __init__(self, val):
             self.val = val
-        def set_compiled_in(self, w):
-            pass
     w_class = bootstrap_class(0)
     shadow = w_class.as_class_get_shadow(space)
     shadow.installmethod(w_foo, mockmethod(1))
@@ -112,7 +110,7 @@
     assert subshadow.lookup(w_bar).val == 2
     py.test.raises(MethodNotFound, subshadow.lookup, "zork")
 
-def test_w_compiledin():
+def test_compiledin_class():
     w_super = bootstrap_class(0)
     w_class = bootstrap_class(0, w_superclass=w_super)
     supershadow = w_super.as_class_get_shadow(space)
@@ -124,7 +122,7 @@
 def new_object(size=0):
     return model.W_PointersObject(space, None, size)
 
-def test_w_compiledin_assoc():
+def test_compiledin_class_assoc():
     val = bootstrap_class(0)
     assoc = new_object(2)
     assoc.store(space, 0, new_object())
@@ -133,9 +131,9 @@
     meth.setliterals([new_object(), new_object(), assoc ])
     assert meth.compiled_in() == val
     
-def test_w_compiledin_missing():
+def test_compiledin_class_missing():
     meth = model.W_CompiledMethod(space, 0)
-    meth.w_compiledin = None
+    meth.compiledin_class = None
     meth.setliterals([new_object(), new_object() ])
     assert meth.compiled_in() == None
     


More information about the pypy-commit mailing list