[pypy-commit] lang-smalltalk default: added type hints for instance variables of non-varsized pointers objects
lwassermann
noreply at buildbot.pypy.org
Fri Apr 12 00:12:36 CEST 2013
Author: Lars Wassermann <lars.wassermann at gmail.com>
Branch:
Changeset: r257:720555f9465b
Date: 2013-04-11 20:36 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/720555f9465b/
Log: added type hints for instance variables of non-varsized pointers
objects
diff --git a/spyvm/fieldtypes.py b/spyvm/fieldtypes.py
new file mode 100644
--- /dev/null
+++ b/spyvm/fieldtypes.py
@@ -0,0 +1,133 @@
+from spyvm import model, shadow
+
+from rpython.rlib import jit, signature
+
+LPI = object()
+int
+float
+
+object
+
+maps = dict()
+
+class VarSizedFieldTypes():
+ _immutable_fields_ = []
+ _attrs_ = []
+ _settled_ = True
+
+ @staticmethod
+ def of_length(s_class, n):
+ return nilTyper
+
+ def __init__(self):
+ pass
+
+ def fetch(self, w_obj, n0):
+ return w_obj._vars[n0]
+
+ def store(self, w_obj, n0, w_val):
+ w_obj._vars[n0] = w_val
+
+class FieldTypes(VarSizedFieldTypes):
+ _immutable_fields_ = ['types']
+ _attrs_ = ['types', 'parent', 'siblings', 'diff']
+ _settled_ = True
+
+ def __init__(self, types, parent=None, change=(-1, object)):
+ self.types = types
+ self.parent = parent
+ if parent is not None:
+ assert change != (-1, object)
+ self.diff = change
+
+ self.siblings = dict()
+
+ def fetch(self, w_object, n0):
+ w_result = w_object._vars[n0]
+ types = self.types
+ if types[n0] is int:
+ jit.record_known_class(w_result, model.W_SmallInteger)
+ elif types[n0] is LPI:
+ jit.record_known_class(w_result, model.W_LargePositiveInteger1Word)
+ elif types[n0] is float:
+ jit.record_known_class(w_result, model.W_Float)
+ return w_result
+
+ def store(self, w_object, n0, w_value):
+ types = self.types
+ changed_type = w_value.fieldtype()
+ if types[n0] is not changed_type:
+ w_object.fieldtypes = self.sibling(n0, changed_type)
+ w_object._vars[n0] = w_value
+
+
+ def sibling(self, n0, changed_type):
+ assert self.types[n0] is not changed_type
+ change = (n0, changed_type)
+ parent = self.parent
+ siblings = self.siblings
+ if change in siblings:
+ return siblings[change]
+ elif parent is None:
+ return self.descent([change])
+ else:
+ new_fieldtype = parent.ascent([change, self.diff])
+ assert new_fieldtype.types == self.types[0:n0] + [changed_type] + self.types[n0+1:]
+ siblings[change] = new_fieldtype
+ return new_fieldtype
+
+ def ascent(self, changes):
+ parent = self.parent
+ if parent is None:
+ return self.descent(sorted(changes))
+ else:
+ change = self.diff
+ if changes[0][0] != change[0]:
+ changes.append(change)
+ return parent.ascent(changes)
+
+ def descent(self, changes):
+ if changes == []:
+ return self
+
+ change = changes[0]
+ siblings = self.siblings
+ if change in siblings:
+ return siblings[change].descent(changes[1:])
+ else:
+ new_types = list(self.types)
+ new_types[change[0]] = change[1]
+ new_fieldtype = FieldTypes(new_types, self, change)
+ siblings[change] = new_fieldtype
+ return new_fieldtype.descent(changes[1:])
+
+
+ @staticmethod
+ def of_length(n):
+ if n not in maps:
+ maps[n] = FieldTypes([object] * n)
+ return maps[n]
+
+
+nilTyper = VarSizedFieldTypes()
+def fieldtypes_of_length(s_class, size):
+ if s_class is None or s_class.isvariable():
+ return nilTyper
+ else:
+ return FieldTypes.of_length(size)
+
+def fieldtypes_of(w_obj):
+ try:
+ if w_obj.s_class.isvariable():
+ return nilTyper
+ else:
+ vars = w_obj._vars
+ size = len(vars)
+ typer = FieldTypes.of_length(size)
+ for i, w_val in enumerate(vars):
+ changed_type = w_val.fieldtype()
+ if changed_type is not object:
+ typer = typer.sibling(i, changed_type)
+ return typer
+ except AttributeError:
+ return nilTyper
\ No newline at end of file
diff --git a/spyvm/model.py b/spyvm/model.py
--- a/spyvm/model.py
+++ b/spyvm/model.py
@@ -130,6 +130,9 @@
def unwrap_uint(self, space):
raise error.UnwrappingError("Got unexpected class in unwrap_uint")
+ def fieldtype(self):
+ return object
+
class W_SmallInteger(W_Object):
"""Boxed integer value"""
# TODO can we tell pypy that its never larger then 31-bit?
@@ -200,6 +203,9 @@
def clone(self, space):
return self
+ def fieldtype(self):
+ return int
+
class W_AbstractObjectWithIdentityHash(W_Object):
"""Object with explicit hash (ie all except small
ints and floats)."""
@@ -303,6 +309,10 @@
def invariant(self):
return isinstance(self.value, int)
+ def fieldtype(self):
+ from spyvm.fieldtype import LPI
+ return LPI
+
class W_Float(W_AbstractObjectWithIdentityHash):
"""Boxed float value."""
_attrs_ = ['value']
@@ -388,6 +398,9 @@
def size(self):
return 2
+ def fieldtype(self):
+ return float
+
@signature.finishsigs
class W_AbstractObjectWithClassReference(W_AbstractObjectWithIdentityHash):
"""Objects with arbitrary class (ie not CompiledMethod, SmallInteger or
@@ -447,24 +460,30 @@
class W_PointersObject(W_AbstractObjectWithClassReference):
"""Common object."""
- _attrs_ = ['_shadow', '_vars']
+ _attrs_ = ['_shadow', '_vars', 'fieldtypes']
_shadow = None # Default value
@jit.unroll_safe
def __init__(self, space, w_class, size):
+ from spyvm.fieldtypes import fieldtypes_of_length
"""Create new object with size = fixed + variable size."""
W_AbstractObjectWithClassReference.__init__(self, space, w_class)
+
vars = self._vars = [None] * size
+ 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
self._shadow = None # Default value
def fillin(self, space, g_self):
+ from spyvm.fieldtypes import fieldtypes_of
self._vars = g_self.get_pointers()
self.s_class = g_self.get_class().as_class_get_penumbra(space)
self.hash = g_self.get_hash()
self.space = space
+ self.fieldtypes = fieldtypes_of(self)
def at0(self, space, index0):
# To test, at0 = in varsize part
@@ -480,7 +499,9 @@
return self._fetch(n0)
def _fetch(self, n0):
- return self._vars[n0]
+ # return self._vars[n0]
+ fieldtypes = jit.promote(self.fieldtypes)
+ return fieldtypes.fetch(self, n0)
def store(self, space, n0, w_value):
if self.has_shadow():
@@ -488,8 +509,9 @@
return self._store(n0, w_value)
def _store(self, n0, w_value):
- self._vars[n0] = w_value
-
+ # self._vars[n0] = w_value
+ fieldtypes = jit.promote(self.fieldtypes)
+ return fieldtypes.store(self, n0, w_value)
def varsize(self, space):
return self.size() - self.instsize(space)
@@ -597,7 +619,8 @@
return True
def clone(self, space):
- w_result = W_PointersObject(self.space, self.getclass(space), len(self._vars))
+ 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))]
return w_result
@@ -607,6 +630,10 @@
className='W_PointersObject',
additionalInformation='len=%d' % self.size())
+ def fieldtype(self):
+ # from spyvm.fieldtype import
+ return object
+
class W_BytesObject(W_AbstractObjectWithClassReference):
_attrs_ = ['bytes']
diff --git a/spyvm/shadow.py b/spyvm/shadow.py
--- a/spyvm/shadow.py
+++ b/spyvm/shadow.py
@@ -201,7 +201,8 @@
def new(self, extrasize=0):
w_cls = self.w_self()
if self.instance_kind == POINTERS:
- w_new = model.W_PointersObject(self.space, w_cls, self.instsize()+extrasize)
+ size = self.instsize() + extrasize
+ w_new = model.W_PointersObject(self.space, w_cls, size)
elif self.instance_kind == WORDS:
w_new = model.W_WordsObject(self.space, w_cls, extrasize)
elif self.instance_kind == BYTES:
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
@@ -2,7 +2,10 @@
from spyvm import model, interpreter, primitives, shadow
from spyvm import objspace, wrapper, constants
-mockclass = objspace.bootstrap_class
+def mockclass(space, instsize, w_superclass=None, w_metaclass=None,
+ name='?', format=shadow.POINTERS, varsized=True):
+ return objspace.bootstrap_class(space, instsize, w_superclass, w_metaclass,
+ name, format, varsized)
space = objspace.ObjSpace()
interp = interpreter.Interpreter(space)
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
@@ -92,9 +92,9 @@
w_object.store(space, constants.MTHDCTX_METHOD, method)
# XXX
w_object.store(space, constants.MTHDCTX_CLOSURE_OR_NIL, space.w_nil)
- w_object.store(space, constants.MTHDCTX_RECEIVER, 'receiver')
+ w_object.store(space, constants.MTHDCTX_RECEIVER, space.wrap_string('receiver'))
- w_object.store(space, constants.MTHDCTX_TEMP_FRAME_START, 'el')
+ w_object.store(space, constants.MTHDCTX_TEMP_FRAME_START, space.wrap_string('el'))
return w_object
def blockcontext(w_sender=space.w_nil, pc=1, stackpointer=1, stacksize=5,
@@ -106,7 +106,7 @@
w_object.store(space, constants.BLKCTX_BLOCK_ARGUMENT_COUNT_INDEX, space.wrap_int(54))
w_object.store(space, constants.BLKCTX_INITIAL_IP_INDEX, space.wrap_int(17))
w_object.store(space, constants.BLKCTX_HOME_INDEX, home)
- w_object.store(space, constants.BLKCTX_STACK_START, 'el')
+ w_object.store(space, constants.BLKCTX_STACK_START, space.wrap_string('el'))
return w_object
def test_context():
@@ -121,24 +121,24 @@
assert s_object2.w_self() == w_object2
assert s_object.s_sender() == None
assert s_object2.s_sender() == s_object
- assert s_object.w_receiver() == 'receiver'
+ assert s_object.w_receiver().as_string() == 'receiver'
s_object2.settemp(0, 'a')
s_object2.settemp(1, 'b')
assert s_object2.gettemp(1) == 'b'
assert s_object2.gettemp(0) == 'a'
assert s_object.w_method() == w_m
idx = s_object.stackstart()
- w_object.store(space, idx, 'f')
- w_object.store(space, idx + 1, 'g')
- w_object.store(space, idx + 2, 'h')
- assert s_object.stack() == ['f', 'g', 'h' ]
- assert s_object.top() == 'h'
+ w_object.store(space, idx, space.wrap_string('f'))
+ w_object.store(space, idx + 1, space.wrap_string('g'))
+ w_object.store(space, idx + 2, space.wrap_string('h'))
+ assert map(lambda x: x.as_string(), s_object.stack()) == ['f', 'g', 'h' ]
+ assert s_object.top().as_string() == 'h'
s_object.push('i')
assert s_object.top() == 'i'
- assert s_object.peek(1) == 'h'
+ assert s_object.peek(1).as_string() == 'h'
assert s_object.pop() == 'i'
- assert s_object.pop_and_return_n(2) == ['g', 'h']
- assert s_object.pop() == 'f'
+ assert map(lambda x: x.as_string(), s_object.pop_and_return_n(2)) == ['g', 'h']
+ assert s_object.pop().as_string() == 'f'
assert s_object.external_stackpointer() == s_object.stackstart()
def test_methodcontext():
More information about the pypy-commit
mailing list