[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