[pypy-svn] pypy refactor-rerase: (cfbolz, arigo)
arigo
commits-noreply at bitbucket.org
Fri Feb 25 15:42:56 CET 2011
Author: Armin Rigo <arigo at tunes.org>
Branch: refactor-rerase
Changeset: r42283:2aae7e82f9d8
Date: 2011-02-25 15:40 +0100
http://bitbucket.org/pypy/pypy/changeset/2aae7e82f9d8/
Log: (cfbolz, arigo)
We only support the pair mechanism. Make it rtype.
diff --git a/pypy/rlib/rerased.py b/pypy/rlib/rerased.py
--- a/pypy/rlib/rerased.py
+++ b/pypy/rlib/rerased.py
@@ -1,6 +1,18 @@
""" Contains a mechanism for turning any class instance and any integer into a
pointer-like thing. Gives full control over pointer tagging, i.e. there won't
-be tag checks everywhere in the C code. """
+be tag checks everywhere in the C code.
+
+Usage: erasestuff, unerasestuff = new_erasing_pair('stuff')
+
+An erasestuff(x) object contains a reference to 'x'. Nothing can be done with
+this object, except calling unerasestuff(), which returns 'x' again. The point
+is that all erased objects can be mixed together, whether they are instances,
+lists, strings, etc. As a special case, an erased object can also be an
+integer fitting into 31/63 bits, with erase_int() and unerase_int().
+
+Warning: some care is needed to make sure that you call the unerase function
+corresponding to the original creator's erase function. Otherwise, segfault.
+"""
import sys
from pypy.annotation import model as annmodel
@@ -15,49 +27,59 @@
-def erase(x):
- """Creates an 'erased' object that contains a reference to 'x'. Nothing can
- be done with this object, except calling unerase(y, <type>) on it.
- x needs to be either an instance or an integer fitting into 31/63 bits."""
- if isinstance(x, int):
- res = 2 * x + 1
- if res > sys.maxint or res < -sys.maxint - 1:
- raise OverflowError
- assert not isinstance(x, list)
- return Erased(x)
+def erase_int(x):
+ assert isinstance(x, int)
+ res = 2 * x + 1
+ if res > sys.maxint or res < -sys.maxint - 1:
+ raise OverflowError
+ return Erased(x, _identity_for_ints)
-def erase_fixedsizelist(l, type):
- assert isinstance(l, list)
- result = Erased(l)
- result._list_item_type = type
- return result
-
-def unerase(y, type):
- """Turn an erased object back into an object of type 'type'."""
- if y._x is None:
- return None
- assert isinstance(y._x, type)
+def unerase_int(y):
+ assert y._identity is _identity_for_ints
+ assert isinstance(y._x, int)
return y._x
-def unerase_fixedsizelist(y, type):
- if y._x is None:
- return None
- assert isinstance(y._x, list)
- if y._x:
- assert isinstance(y._x[0], type)
- return y._x
-
-def is_integer(e):
- """Gives information whether the erased argument is a tagged integer or not."""
- return isinstance(e._x, int)
-
class ErasingPairIdentity(object):
+
def __init__(self, name):
self.name = name
+
def __repr__(self):
return 'ErasingPairIdentity(%r)' % self.name
+ def _getdict(self, bk):
+ try:
+ dict = bk._erasing_pairs_tunnel
+ except AttributeError:
+ dict = bk._erasing_pairs_tunnel = {}
+ return dict
+
+ def enter_tunnel(self, bookkeeper, s_obj):
+ dict = self._getdict(bookkeeper)
+ s_previousobj, reflowpositions = dict.setdefault(
+ self, (annmodel.s_ImpossibleValue, {}))
+ s_obj = annmodel.unionof(s_previousobj, s_obj)
+ if s_obj != s_previousobj:
+ dict[self] = (s_obj, reflowpositions)
+ for position in reflowpositions:
+ bookkeeper.annotator.reflowfromposition(position)
+
+ def leave_tunnel(self, bookkeeper):
+ dict = self._getdict(bookkeeper)
+ s_obj, reflowpositions = dict.setdefault(
+ self, (annmodel.s_ImpossibleValue, {}))
+ reflowpositions[bookkeeper.position_key] = True
+ return s_obj
+
+ def get_input_annotation(self, bookkeeper):
+ dict = self._getdict(bookkeeper)
+ s_obj, _ = dict[self]
+ return s_obj
+
+_identity_for_ints = ErasingPairIdentity("int")
+
+
def new_erasing_pair(name):
identity = ErasingPairIdentity(name)
@@ -68,45 +90,29 @@
assert y._identity is identity
return y._x
- def _getdict(bk):
- try:
- dict = bk._erasing_pairs_tunnel
- except AttributeError:
- dict = bk._erasing_pairs_tunnel = {}
- return dict
-
class Entry(ExtRegistryEntry):
_about_ = erase
def compute_result_annotation(self, s_obj):
- bk = self.bookkeeper
- dict = _getdict(bk)
- s_previousobj, reflowpositions = dict.setdefault(
- identity, (annmodel.s_ImpossibleValue, {}))
- s_obj = annmodel.unionof(s_previousobj, s_obj)
- if s_obj != s_previousobj:
- dict[identity] = (s_obj, reflowpositions)
- for position in reflowpositions:
- bk.annotator.reflowfromposition(position)
+ identity.enter_tunnel(self.bookkeeper, s_obj)
return SomeErased()
def specialize_call(self, hop):
- return hop.r_result.specialize_call(hop)
+ bk = hop.rtyper.annotator.bookkeeper
+ s_obj = identity.get_input_annotation(bk)
+ return hop.r_result.rtype_erase(hop, s_obj)
class Entry(ExtRegistryEntry):
_about_ = unerase
def compute_result_annotation(self, s_obj):
assert SomeErased().contains(s_obj)
- bk = self.bookkeeper
- dict = _getdict(bk)
- s_obj, reflowpositions = dict.setdefault(
- identity, (annmodel.s_ImpossibleValue, []))
- reflowpositions[bk.position_key] = True
- return s_obj
+ return identity.leave_tunnel(self.bookkeeper)
def specialize_call(self, hop):
- v, t = hop.inputargs(hop.args_r[0], lltype.Void)
+ if hop.r_result.lowleveltype is lltype.Void:
+ return hop.inputconst(lltype.Void, None)
+ [v] = hop.inputargs(hop.args_r[0])
return hop.genop('cast_opaque_ptr', [v], resulttype = hop.r_result)
return erase, unerase
@@ -115,103 +121,55 @@
# ---------- implementation-specific ----------
class Erased(object):
- _list_item_type = None
- def __init__(self, x, identity=None):
+ def __init__(self, x, identity):
self._x = x
self._identity = identity
def __repr__(self):
return "Erased(%r, %r)" % (self._x, self._identity)
class Entry(ExtRegistryEntry):
- _about_ = erase
+ _about_ = erase_int
def compute_result_annotation(self, s_obj):
+ assert annmodel.SomeInteger().contains(s_obj)
return SomeErased()
def specialize_call(self, hop):
- return hop.r_result.specialize_call(hop)
+ return hop.r_result.rtype_erase_int(hop)
class Entry(ExtRegistryEntry):
- _about_ = erase_fixedsizelist
+ _about_ = unerase_int
- def compute_result_annotation(self, s_arg, s_type):
- # s_type ignored: only for prebuilt erased lists
- assert isinstance(s_arg, annmodel.SomeList)
- s_arg.listdef.never_resize()
- return SomeErased()
+ def compute_result_annotation(self, s_obj):
+ assert SomeErased().contains(s_obj)
+ return annmodel.SomeInteger()
def specialize_call(self, hop):
- return hop.r_result.specialize_call(hop)
+ [v] = hop.inputargs(hop.args_r[0])
+ assert isinstance(hop.s_result, annmodel.SomeInteger)
+ return hop.gendirectcall(ll_unerase_int, v)
-class Entry(ExtRegistryEntry):
- _about_ = unerase
-
- def compute_result_annotation(self, s_obj, s_type):
- assert s_type.is_constant()
- if s_type.const is int:
- return annmodel.SomeInteger()
- assert isinstance(s_type, annmodel.SomePBC)
- assert len(s_type.descriptions) == 1
- clsdef = s_type.any_description().getuniqueclassdef()
- return annmodel.SomeInstance(clsdef)
-
- def specialize_call(self, hop):
- v, t = hop.inputargs(hop.args_r[0], lltype.Void)
- if isinstance(hop.s_result, annmodel.SomeInteger):
- c_one = hop.inputconst(lltype.Signed, 1)
- vi = hop.genop('cast_ptr_to_int', [v], resulttype=lltype.Signed)
- return hop.genop('int_rshift', [vi, c_one], resulttype=lltype.Signed)
- return hop.genop('cast_opaque_ptr', [v], resulttype = hop.r_result)
-
-class Entry(ExtRegistryEntry):
- _about_ = unerase_fixedsizelist
-
- def compute_result_annotation(self, s_obj, s_type):
- assert isinstance(s_type, annmodel.SomePBC)
- assert len(s_type.descriptions) == 1
- clsdef = s_type.any_description().getuniqueclassdef()
- s_item = annmodel.SomeInstance(clsdef)
- return self.bookkeeper.newlist(s_item)
-
- def specialize_call(self, hop):
- v, t = hop.inputargs(hop.args_r[0], lltype.Void)
- return hop.genop('cast_opaque_ptr', [v], resulttype = hop.r_result)
-
-
-class Entry(ExtRegistryEntry):
- _about_ = is_integer
-
- def compute_result_annotation(self, s_obj):
- return annmodel.SomeBool()
-
- def specialize_call(self, hop):
- v, = hop.inputargs(hop.args_r[0])
- c_one = hop.inputconst(lltype.Signed, 1)
- vi = hop.genop('cast_ptr_to_int', [v], resulttype=lltype.Signed)
- vb = hop.genop('int_and', [vi, c_one], resulttype=lltype.Signed)
- return hop.genop('int_is_true', [vb], resulttype=lltype.Bool)
+def ll_unerase_int(gcref):
+ from pypy.rpython.lltypesystem.lloperation import llop
+ from pypy.rlib.debug import ll_assert
+ x = llop.cast_ptr_to_int(lltype.Signed, gcref)
+ ll_assert((x&1) != 0, "unerased_int(): not an integer")
+ return x >> 1
class Entry(ExtRegistryEntry):
_type_ = Erased
def compute_annotation(self):
+ identity = self.instance._identity
s_obj = self.bookkeeper.immutablevalue(self.instance._x)
- if self.instance._list_item_type is not None:
- # only non-resizable lists of instances for now
- clsdef = self.bookkeeper.getuniqueclassdef(self.instance._list_item_type)
- s_item = annmodel.SomeInstance(clsdef)
- s_obj.listdef.generalize(s_item)
- self.instance._s_list = s_obj
+ identity.enter_tunnel(self.bookkeeper, s_obj)
return SomeErased()
# annotation and rtyping support
class SomeErased(annmodel.SomeObject):
- def __init__(self, s_obj=None):
- self.s_obj = s_obj # only non-None for constants
-
def can_be_none(self):
return False # cannot be None, but can contain a None
@@ -232,48 +190,35 @@
def __init__(self, rtyper):
self.rtyper = rtyper
- def specialize_call(self, hop):
- s_arg = hop.args_s[0]
- r_generic_object = getinstancerepr(hop.rtyper, None)
- if (isinstance(s_arg, annmodel.SomeInstance) or
- (s_arg.is_constant() and s_arg.const is None)):
- hop.exception_cannot_occur()
- [v_instance] = hop.inputargs(r_generic_object) # might generate a cast_pointer
- v = hop.genop('cast_opaque_ptr', [v_instance],
- resulttype=self.lowleveltype)
- return v
- elif isinstance(s_arg, annmodel.SomeList):
- hop.exception_cannot_occur()
- r_list = self.rtyper.getrepr(s_arg)
- v_list = hop.inputarg(r_list, 0)
- v = hop.genop('cast_opaque_ptr', [v_list],
- resulttype=self.lowleveltype)
- return v
- else:
- assert isinstance(s_arg, annmodel.SomeInteger)
- v_value = hop.inputarg(lltype.Signed, arg=0)
- c_one = hop.inputconst(lltype.Signed, 1)
- hop.exception_is_here()
- v2 = hop.genop('int_lshift_ovf', [v_value, c_one],
- resulttype = lltype.Signed)
- v2p1 = hop.genop('int_add', [v2, c_one],
- resulttype = lltype.Signed)
- v_instance = hop.genop('cast_int_to_ptr', [v2p1],
- resulttype=self.lowleveltype)
- v = hop.genop('cast_opaque_ptr', [v_instance],
- resulttype=self.lowleveltype)
- return v
+ def rtype_erase(self, hop, s_obj):
+ hop.exception_cannot_occur()
+ r_obj = self.rtyper.getrepr(s_obj)
+ if r_obj.lowleveltype is lltype.Void:
+ return hop.inputconst(self.lowleveltype,
+ lltype.nullptr(self.lowleveltype.TO))
+ [v_obj] = hop.inputargs(r_obj)
+ return hop.genop('cast_opaque_ptr', [v_obj],
+ resulttype=self.lowleveltype)
+ def rtype_erase_int(self, hop):
+ [v_value] = hop.inputargs(lltype.Signed)
+ c_one = hop.inputconst(lltype.Signed, 1)
+ hop.exception_is_here()
+ v2 = hop.genop('int_lshift_ovf', [v_value, c_one],
+ resulttype = lltype.Signed)
+ v2p1 = hop.genop('int_add', [v2, c_one],
+ resulttype = lltype.Signed)
+ v_instance = hop.genop('cast_int_to_ptr', [v2p1],
+ resulttype=self.lowleveltype)
+ v = hop.genop('cast_opaque_ptr', [v_instance],
+ resulttype=self.lowleveltype)
+ return v
def convert_const(self, value):
- if isinstance(value._x, int):
+ if value._identity is _identity_for_ints:
return lltype.cast_int_to_ptr(self.lowleveltype, value._x * 2 + 1)
- if isinstance(value._x, list):
- r_list = self.rtyper.getrepr(value._s_list)
- v = r_list.convert_const(value._x)
- return lltype.cast_opaque_ptr(self.lowleveltype, v)
- else:
- r_generic_object = getinstancerepr(self.rtyper, None)
- v = r_generic_object.convert_const(value._x)
- return lltype.cast_opaque_ptr(self.lowleveltype, v)
-
+ bk = self.rtyper.annotator.bookkeeper
+ s_obj = value._identity.get_input_annotation(bk)
+ r_obj = self.rtyper.getrepr(s_obj)
+ v = r_obj.convert_const(value._x)
+ return lltype.cast_opaque_ptr(self.lowleveltype, v)
diff --git a/pypy/rlib/test/test_rerased.py b/pypy/rlib/test/test_rerased.py
--- a/pypy/rlib/test/test_rerased.py
+++ b/pypy/rlib/test/test_rerased.py
@@ -17,37 +17,42 @@
class Z(X):
pass
+eraseX, uneraseX = new_erasing_pair("X")
+erase_list_X, unerase_list_X = new_erasing_pair("list of X")
+
def test_simple():
x1 = X()
- e = erase(x1)
- assert is_integer(e) is False
- assert unerase(e, X) is x1
+ e = eraseX(x1)
+ #assert is_integer(e) is False
+ assert uneraseX(e) is x1
def test_simple_none():
- e = erase(None)
- assert unerase(e, X) is None
+ e = eraseX(None)
+ assert uneraseX(e) is None
def test_simple_int():
- e = erase(15)
- assert is_integer(e) is True
- assert unerase(e, int) == 15
+ e = erase_int(15)
+ #assert is_integer(e) is True
+ assert unerase_int(e) == 15
def test_simple_int_overflow():
- py.test.raises(OverflowError, erase, sys.maxint)
- py.test.raises(OverflowError, erase, sys.maxint-1)
- py.test.raises(OverflowError, erase, -sys.maxint)
- py.test.raises(OverflowError, erase, -sys.maxint-1)
+ erase_int(sys.maxint//2)
+ py.test.raises(OverflowError, erase_int, sys.maxint//2 + 1)
+ py.test.raises(OverflowError, erase_int, sys.maxint)
+ py.test.raises(OverflowError, erase_int, sys.maxint-1)
+ py.test.raises(OverflowError, erase_int, -sys.maxint)
+ py.test.raises(OverflowError, erase_int, -sys.maxint-1)
def test_list():
l = [X()]
- e = erase_fixedsizelist(l, X)
- assert is_integer(e) is False
- assert unerase_fixedsizelist(e, X) is l
+ e = erase_list_X(l)
+ #assert is_integer(e) is False
+ assert unerase_list_X(e) is l
def test_annotate_1():
def f():
- return erase(X())
+ return eraseX(X())
a = RPythonAnnotator()
s = a.build_types(f, [])
assert isinstance(s, SomeErased)
@@ -55,9 +60,9 @@
def test_annotate_2():
def f():
x1 = X()
- e = erase(x1)
- assert not is_integer(e)
- x2 = unerase(e, X)
+ e = eraseX(x1)
+ #assert not is_integer(e)
+ x2 = uneraseX(e)
return x2
a = RPythonAnnotator()
s = a.build_types(f, [])
@@ -66,9 +71,9 @@
def test_annotate_3():
def f():
- e = erase(16)
- assert is_integer(e)
- x2 = unerase(e, int)
+ e = erase_int(16)
+ #assert is_integer(e)
+ x2 = unerase_int(e)
return x2
a = RPythonAnnotator()
s = a.build_types(f, [])
@@ -76,51 +81,53 @@
def test_rtype_1():
def f():
- return erase(X())
+ return eraseX(X())
x = interpret(f, [])
assert lltype.typeOf(x) == llmemory.GCREF
def test_rtype_2():
def f():
x1 = X()
- e = erase(x1)
- assert not is_integer(e)
- x2 = unerase(e, X)
+ e = eraseX(x1)
+ #assert not is_integer(e)
+ x2 = uneraseX(e)
return x2
x = interpret(f, [])
assert lltype.castable(OBJECTPTR, lltype.typeOf(x)) > 0
def test_rtype_3():
def f():
- e = erase(16)
- assert is_integer(e)
- x2 = unerase(e, int)
+ e = erase_int(16)
+ #assert is_integer(e)
+ x2 = unerase_int(e)
return x2
x = interpret(f, [])
assert x == 16
def test_prebuilt_erased():
- e1 = erase(16)
+ e1 = erase_int(16)
x1 = X()
- e2 = erase(x1)
+ x1.foobar = 42
+ e2 = eraseX(x1)
def f():
- assert is_integer(e1)
- assert not is_integer(e2)
- x2 = unerase(e1, int)
+ #assert is_integer(e1)
+ #assert not is_integer(e2)
+ x1.foobar += 1
+ x2 = unerase_int(e1) + uneraseX(e2).foobar
return x2
x = interpret(f, [])
- assert x == 16
+ assert x == 16 + 42 + 1
def test_overflow():
def f(i):
try:
- e = erase(i)
+ e = erase_int(i)
except OverflowError:
return -1
- assert is_integer(e)
- return unerase(e, int)
+ #assert is_integer(e)
+ return unerase_int(e)
x = interpret(f, [16])
assert x == 16
x = interpret(f, [sys.maxint])
@@ -128,7 +135,14 @@
def test_none():
def foo():
- return unerase(erase(None), X)
+ return uneraseX(eraseX(None))
+ assert foo() is None
+ res = interpret(foo, [])
+ assert not res
+ #
+ def foo():
+ eraseX(X())
+ return uneraseX(eraseX(None))
assert foo() is None
res = interpret(foo, [])
assert not res
@@ -143,19 +157,19 @@
def test_rtype_list():
prebuilt_l = [X()]
- prebuilt_e = erase_fixedsizelist(prebuilt_l, X)
+ prebuilt_e = erase_list_X(prebuilt_l)
def l(flag):
if flag == 1:
l = [X()]
- e = erase_fixedsizelist(l, X)
+ e = erase_list_X(l)
elif flag == 2:
l = prebuilt_l
- e = erase_fixedsizelist(l, X)
+ e = erase_list_X(l)
else:
l = prebuilt_l
e = prebuilt_e
- assert is_integer(e) is False
- assert unerase_fixedsizelist(e, X) is l
+ #assert is_integer(e) is False
+ assert unerase_list_X(e) is l
interpret(l, [0])
interpret(l, [1])
interpret(l, [2])
@@ -170,8 +184,6 @@
erased = erase(x)
assert unerase(erased) is x
#
- assert not is_integer(erased)
- #
erase2, unerase2 = new_erasing_pair("test2")
py.test.raises(AssertionError, unerase2, erased)
@@ -233,3 +245,32 @@
s = a.build_types(f, [])
assert isinstance(s, annmodel.SomeInstance)
assert s.classdef == a.bookkeeper.getuniqueclassdef(A)
+
+def test_annotate_prebuilt():
+ erase, unerase = new_erasing_pair("test1")
+ class X(object):
+ pass
+ x1 = X()
+ e1 = erase(x1)
+ e2 = erase(None)
+
+ def f(i):
+ if i:
+ e = e1
+ else:
+ e = e2
+ return unerase(e)
+ #
+ a = RPythonAnnotator()
+ s = a.build_types(f, [int])
+ assert isinstance(s, annmodel.SomeInstance)
+ assert s.classdef == a.bookkeeper.getuniqueclassdef(X)
+ assert s.can_be_none()
+
+def test_annotate_prebuilt_int():
+ e1 = erase_int(42)
+ def f(i):
+ return unerase_int(e1)
+ a = RPythonAnnotator()
+ s = a.build_types(f, [int])
+ assert isinstance(s, annmodel.SomeInteger)
More information about the Pypy-commit
mailing list