[pypy-svn] r73069 - in pypy/branch/reduce-instance-size-experiments/pypy/rlib: . test
cfbolz at codespeak.net
cfbolz at codespeak.net
Mon Mar 29 15:52:28 CEST 2010
Author: cfbolz
Date: Mon Mar 29 15:52:26 2010
New Revision: 73069
Added:
pypy/branch/reduce-instance-size-experiments/pypy/rlib/rerased.py (contents, props changed)
pypy/branch/reduce-instance-size-experiments/pypy/rlib/test/test_rerased.py (contents, props changed)
Log:
Add a mechanism for tagging and untagging pointers fully under the programmers
control.
Added: pypy/branch/reduce-instance-size-experiments/pypy/rlib/rerased.py
==============================================================================
--- (empty file)
+++ pypy/branch/reduce-instance-size-experiments/pypy/rlib/rerased.py Mon Mar 29 15:52:26 2010
@@ -0,0 +1,154 @@
+""" 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. """
+
+import sys
+from pypy.annotation import model as annmodel
+from pypy.tool.pairtype import pairtype
+from pypy.rpython.extregistry import ExtRegistryEntry
+from pypy.rpython.rclass import getinstancerepr
+from pypy.rpython.rmodel import Repr
+from pypy.rpython.lltypesystem.lloperation import llop
+from pypy.rpython.lltypesystem.rclass import OBJECTPTR
+from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.error import TyperError
+
+
+
+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
+ return Erased(x)
+
+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)
+ return y._x
+
+def is_integer(e):
+ """Gives information whether the erased argument is a tagged integer or not."""
+ return isinstance(e._x, int)
+
+
+# ---------- implementation-specific ----------
+
+class Erased(object):
+ def __init__(self, x):
+ self._x = x
+
+class Entry(ExtRegistryEntry):
+ _about_ = erase
+
+ def compute_result_annotation(self, s_obj):
+ return someErased
+
+ def specialize_call(self, hop):
+ return hop.r_result.specialize_call(hop)
+
+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.descriptions.keys()[0].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_pointer', [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)
+
+
+class Entry(ExtRegistryEntry):
+ _type_ = Erased
+
+ def compute_annotation(self):
+ from pypy.rlib import _jit_vref
+ s_obj = self.bookkeeper.immutablevalue(self.instance._x)
+ return someErased
+
+# annotation and rtyping support
+
+class SomeErased(annmodel.SomeObject):
+
+ def __init__(self):
+ pass
+
+ def can_be_none(self):
+ return False # cannot be None, but can contain a None
+
+ def rtyper_makerepr(self, rtyper):
+ return ErasedRepr(rtyper)
+
+ def rtyper_makekey(self):
+ return self.__class__,
+
+someErased = SomeErased()
+
+class __extend__(pairtype(SomeErased, SomeErased)):
+
+ def union((serased1, serased2)):
+ return serased1
+
+
+class ErasedRepr(Repr):
+ lowleveltype = OBJECTPTR
+ def __init__(self, rtyper):
+ self.rtyper = rtyper
+
+ def specialize_call(self, hop):
+ s_arg, = hop.args_s
+ if isinstance(s_arg, annmodel.SomeInstance):
+ r_generic_object = getinstancerepr(hop.rtyper, None)
+ hop.exception_cannot_occur()
+ [v] = hop.inputargs(r_generic_object) # might generate a cast_pointer
+ 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)
+ return v_instance
+
+
+ def convert_const(self, value):
+ if isinstance(value._x, int):
+ return lltype.cast_int_to_ptr(self.lowleveltype, value._x * 2 + 1)
+ else:
+ r_generic_object = getinstancerepr(self.rtyper, None)
+ v = r_generic_object.convert_const(value._x)
+ return v
+
Added: pypy/branch/reduce-instance-size-experiments/pypy/rlib/test/test_rerased.py
==============================================================================
--- (empty file)
+++ pypy/branch/reduce-instance-size-experiments/pypy/rlib/test/test_rerased.py Mon Mar 29 15:52:26 2010
@@ -0,0 +1,119 @@
+import py
+import sys
+from pypy.rlib.rerased import erase, unerase, is_integer, SomeErased
+from pypy.annotation import model as annmodel
+from pypy.annotation.annrpython import RPythonAnnotator
+from pypy.rpython.test.test_llinterp import interpret
+from pypy.rpython.lltypesystem.rclass import OBJECTPTR
+from pypy.rpython.lltypesystem import lltype
+
+
+class X(object):
+ pass
+
+class Y(X):
+ pass
+
+class Z(X):
+ pass
+
+
+def test_simple():
+ x1 = X()
+ e = erase(x1)
+ assert is_integer(e) is False
+ assert unerase(e, X) is x1
+
+def test_simple_none():
+ e = erase(None)
+ assert unerase(e, X) is None
+
+def test_simple_int():
+ e = erase(15)
+ assert is_integer(e) is True
+ assert unerase(e, int) == 15
+
+def test_simple_int_overflow():
+ py.test.raises(OverflowError, erase, sys.maxint)
+ py.test.raises(OverflowError, erase, -sys.maxint)
+
+def test_annotate_1():
+ def f():
+ return erase(X())
+ a = RPythonAnnotator()
+ s = a.build_types(f, [])
+ assert isinstance(s, SomeErased)
+
+def test_annotate_2():
+ def f():
+ x1 = X()
+ e = erase(x1)
+ assert not is_integer(e)
+ x2 = unerase(e, X)
+ return x2
+ a = RPythonAnnotator()
+ s = a.build_types(f, [])
+ assert isinstance(s, annmodel.SomeInstance)
+ assert s.classdef == a.bookkeeper.getuniqueclassdef(X)
+
+def test_annotate_3():
+ def f():
+ e = erase(16)
+ assert is_integer(e)
+ x2 = unerase(e, int)
+ return x2
+ a = RPythonAnnotator()
+ s = a.build_types(f, [])
+ assert isinstance(s, annmodel.SomeInteger)
+
+def test_rtype_1():
+ def f():
+ return erase(X())
+ x = interpret(f, [])
+ assert lltype.typeOf(x) == OBJECTPTR
+
+def test_rtype_2():
+ def f():
+ x1 = X()
+ e = erase(x1)
+ assert not is_integer(e)
+ x2 = unerase(e, X)
+ 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)
+ return x2
+ x = interpret(f, [])
+ assert x == 16
+
+
+def test_prebuilt_erased():
+ e1 = erase(16)
+ x1 = X()
+ e2 = erase(x1)
+
+ def f():
+ assert is_integer(e1)
+ assert not is_integer(e2)
+ x2 = unerase(e1, int)
+ return x2
+ x = interpret(f, [])
+ assert x == 16
+
+def test_overflow():
+ def f(i):
+ try:
+ e = erase(i)
+ except OverflowError:
+ return -1
+ assert is_integer(e)
+ return unerase(e, int)
+ x = interpret(f, [16])
+ assert x == 16
+ x = interpret(f, [sys.maxint])
+ assert x == -1
More information about the Pypy-commit
mailing list