[pypy-commit] pypy callfamily: Merge rpython.rtyper.lltypesystem.rpbc into rpython.rtyper.rpbc

rlamy noreply at buildbot.pypy.org
Sat Apr 18 21:09:58 CEST 2015


Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: callfamily
Changeset: r76829:19ac7c5e6243
Date: 2015-04-18 20:10 +0100
http://bitbucket.org/pypy/pypy/changeset/19ac7c5e6243/

Log:	Merge rpython.rtyper.lltypesystem.rpbc into rpython.rtyper.rpbc

diff --git a/rpython/rtyper/lltypesystem/rpbc.py b/rpython/rtyper/lltypesystem/rpbc.py
deleted file mode 100644
--- a/rpython/rtyper/lltypesystem/rpbc.py
+++ /dev/null
@@ -1,302 +0,0 @@
-import types
-
-from rpython.annotator import description
-from rpython.rlib.debug import ll_assert
-from rpython.rlib.unroll import unrolling_iterable
-from rpython.rtyper import callparse
-from rpython.rtyper.lltypesystem import llmemory
-from rpython.rtyper.lltypesystem.lltype import (typeOf, Void, ForwardReference,
-    Struct, Bool, Char, Ptr, malloc, nullptr, Array, Signed)
-from rpython.rtyper.rmodel import Repr, inputconst
-from rpython.rtyper.rpbc import (
-    AbstractMultipleFrozenPBCRepr,
-    AbstractFunctionsPBCRepr, AbstractMultipleUnrelatedFrozenPBCRepr,
-    SingleFrozenPBCRepr, get_concrete_calltable)
-from rpython.rtyper.typesystem import getfunctionptr
-from rpython.tool.pairtype import pairtype
-
-
-class MultipleFrozenPBCRepr(AbstractMultipleFrozenPBCRepr):
-    """Representation selected for multiple non-callable pre-built constants."""
-    def __init__(self, rtyper, access_set):
-        self.rtyper = rtyper
-        self.access_set = access_set
-        self.pbc_type = ForwardReference()
-        self.lowleveltype = Ptr(self.pbc_type)
-        self.pbc_cache = {}
-
-    def _setup_repr(self):
-        llfields = self._setup_repr_fields()
-        kwds = {'hints': {'immutable': True}}
-        self.pbc_type.become(Struct('pbc', *llfields, **kwds))
-
-    def create_instance(self):
-        return malloc(self.pbc_type, immortal=True)
-
-    def null_instance(self):
-        return nullptr(self.pbc_type)
-
-    def getfield(self, vpbc, attr, llops):
-        mangled_name, r_value = self.fieldmap[attr]
-        cmangledname = inputconst(Void, mangled_name)
-        return llops.genop('getfield', [vpbc, cmangledname],
-                           resulttype=r_value)
-
-
-class MultipleUnrelatedFrozenPBCRepr(AbstractMultipleUnrelatedFrozenPBCRepr):
-    """Representation selected for multiple non-callable pre-built constants
-    with no common access set."""
-
-    lowleveltype = llmemory.Address
-    EMPTY = Struct('pbc', hints={'immutable': True})
-
-    def convert_pbc(self, pbcptr):
-        return llmemory.fakeaddress(pbcptr)
-
-    def create_instance(self):
-        return malloc(self.EMPTY, immortal=True)
-
-    def null_instance(self):
-        return llmemory.Address._defl()
-
-
-class __extend__(pairtype(MultipleUnrelatedFrozenPBCRepr,
-                          MultipleUnrelatedFrozenPBCRepr),
-                 pairtype(MultipleUnrelatedFrozenPBCRepr,
-                          SingleFrozenPBCRepr),
-                 pairtype(SingleFrozenPBCRepr,
-                          MultipleUnrelatedFrozenPBCRepr)):
-    def rtype_is_((robj1, robj2), hop):
-        if isinstance(robj1, MultipleUnrelatedFrozenPBCRepr):
-            r = robj1
-        else:
-            r = robj2
-        vlist = hop.inputargs(r, r)
-        return hop.genop('adr_eq', vlist, resulttype=Bool)
-
-
-class __extend__(pairtype(MultipleFrozenPBCRepr,
-                          MultipleUnrelatedFrozenPBCRepr)):
-    def convert_from_to((robj1, robj2), v, llops):
-        return llops.genop('cast_ptr_to_adr', [v], resulttype=llmemory.Address)
-
-
-# ____________________________________________________________
-
-class FunctionsPBCRepr(AbstractFunctionsPBCRepr):
-    """Representation selected for a PBC of function(s)."""
-
-    def setup_specfunc(self):
-        fields = []
-        for row in self.uniquerows:
-            fields.append((row.attrname, row.fntype))
-        kwds = {'hints': {'immutable': True}}
-        return Ptr(Struct('specfunc', *fields, **kwds))
-
-    def create_specfunc(self):
-        return malloc(self.lowleveltype.TO, immortal=True)
-
-    def get_specfunc_row(self, llop, v, c_rowname, resulttype):
-        return llop.genop('getfield', [v, c_rowname], resulttype=resulttype)
-
-
-class SmallFunctionSetPBCRepr(Repr):
-    def __init__(self, rtyper, s_pbc):
-        self.rtyper = rtyper
-        self.s_pbc = s_pbc
-        self.callfamily = s_pbc.any_description().getcallfamily()
-        llct = get_concrete_calltable(self.rtyper, self.callfamily)
-        assert len(llct.uniquerows) == 1
-        self.lowleveltype = Char
-        self.pointer_repr = FunctionsPBCRepr(rtyper, s_pbc)
-        self._conversion_tables = {}
-        self._compression_function = None
-        self._dispatch_cache = {}
-
-    def _setup_repr(self):
-        if self.s_pbc.subset_of:
-            assert self.s_pbc.can_be_None == self.s_pbc.subset_of.can_be_None
-            r = self.rtyper.getrepr(self.s_pbc.subset_of)
-            if r is not self:
-                r.setup()
-                self.descriptions = r.descriptions
-                self.c_pointer_table = r.c_pointer_table
-                return
-        self.descriptions = list(self.s_pbc.descriptions)
-        if self.s_pbc.can_be_None:
-            self.descriptions.insert(0, None)
-        POINTER_TABLE = Array(self.pointer_repr.lowleveltype,
-                              hints={'nolength': True})
-        pointer_table = malloc(POINTER_TABLE, len(self.descriptions),
-                               immortal=True)
-        for i, desc in enumerate(self.descriptions):
-            if desc is not None:
-                pointer_table[i] = self.pointer_repr.convert_desc(desc)
-            else:
-                pointer_table[i] = self.pointer_repr.convert_const(None)
-        self.c_pointer_table = inputconst(Ptr(POINTER_TABLE), pointer_table)
-
-    def get_s_callable(self):
-        return self.s_pbc
-
-    def get_r_implfunc(self):
-        return self, 0
-
-    def get_s_signatures(self, shape):
-        funcdesc = self.s_pbc.any_description()
-        return funcdesc.get_s_signatures(shape)
-
-    def convert_desc(self, funcdesc):
-        return chr(self.descriptions.index(funcdesc))
-
-    def convert_const(self, value):
-        if isinstance(value, types.MethodType) and value.im_self is None:
-            value = value.im_func   # unbound method -> bare function
-        if value is None:
-            return chr(0)
-        funcdesc = self.rtyper.annotator.bookkeeper.getdesc(value)
-        return self.convert_desc(funcdesc)
-
-    def rtype_simple_call(self, hop):
-        return self.call(hop)
-
-    def rtype_call_args(self, hop):
-        return self.call(hop)
-
-    def dispatcher(self, shape, index, argtypes, resulttype):
-        key = shape, index, tuple(argtypes), resulttype
-        if key in self._dispatch_cache:
-            return self._dispatch_cache[key]
-        from rpython.translator.unsimplify import varoftype
-        from rpython.flowspace.model import FunctionGraph, Link, Block, SpaceOperation
-        inputargs = [varoftype(t) for t in [Char] + argtypes]
-        startblock = Block(inputargs)
-        startblock.exitswitch = inputargs[0]
-        graph = FunctionGraph("dispatcher", startblock, varoftype(resulttype))
-        row_of_graphs = self.callfamily.calltables[shape][index]
-        links = []
-        descs = list(self.s_pbc.descriptions)
-        if self.s_pbc.can_be_None:
-            descs.insert(0, None)
-        for desc in descs:
-            if desc is None:
-                continue
-            args_v = [varoftype(t) for t in argtypes]
-            b = Block(args_v)
-            llfn = self.rtyper.getcallable(row_of_graphs[desc])
-            v_fn = inputconst(typeOf(llfn), llfn)
-            v_result = varoftype(resulttype)
-            b.operations.append(
-                SpaceOperation("direct_call", [v_fn] + args_v, v_result))
-            b.closeblock(Link([v_result], graph.returnblock))
-            i = self.descriptions.index(desc)
-            links.append(Link(inputargs[1:], b, chr(i)))
-            links[-1].llexitcase = chr(i)
-        startblock.closeblock(*links)
-        self.rtyper.annotator.translator.graphs.append(graph)
-        ll_ret = getfunctionptr(graph)
-        #FTYPE = FuncType
-        c_ret = self._dispatch_cache[key] = inputconst(typeOf(ll_ret), ll_ret)
-        return c_ret
-
-    def call(self, hop):
-        bk = self.rtyper.annotator.bookkeeper
-        args = hop.spaceop.build_args(hop.args_s[1:])
-        s_pbc = hop.args_s[0]   # possibly more precise than self.s_pbc
-        descs = list(s_pbc.descriptions)
-        vfcs = description.FunctionDesc.variant_for_call_site
-        shape, index = vfcs(bk, self.callfamily, descs, args, hop.spaceop)
-        row_of_graphs = self.callfamily.calltables[shape][index]
-        anygraph = row_of_graphs.itervalues().next()  # pick any witness
-        vlist = [hop.inputarg(self, arg=0)]
-        vlist += callparse.callparse(self.rtyper, anygraph, hop)
-        rresult = callparse.getrresult(self.rtyper, anygraph)
-        hop.exception_is_here()
-        v_dispatcher = self.dispatcher(shape, index, [v.concretetype for v in vlist[1:]], rresult.lowleveltype)
-        v_result = hop.genop('direct_call', [v_dispatcher] + vlist,
-                             resulttype=rresult)
-        return hop.llops.convertvar(v_result, rresult, hop.r_result)
-
-    def rtype_bool(self, hop):
-        if not self.s_pbc.can_be_None:
-            return inputconst(Bool, True)
-        else:
-            v1, = hop.inputargs(self)
-            return hop.genop('char_ne', [v1, inputconst(Char, '\000')],
-                         resulttype=Bool)
-
-
-class __extend__(pairtype(SmallFunctionSetPBCRepr, FunctionsPBCRepr)):
-    def convert_from_to((r_set, r_ptr), v, llops):
-        if r_ptr.lowleveltype is Void:
-            return inputconst(Void, None)
-        else:
-            assert v.concretetype is Char
-            v_int = llops.genop('cast_char_to_int', [v],
-                                resulttype=Signed)
-            return llops.genop('getarrayitem', [r_set.c_pointer_table, v_int],
-                               resulttype=r_ptr.lowleveltype)
-
-
-def compression_function(r_set):
-    if r_set._compression_function is None:
-        table = []
-        for i, p in enumerate(r_set.c_pointer_table.value):
-            table.append((chr(i), p))
-        last_c, last_p = table[-1]
-        unroll_table = unrolling_iterable(table[:-1])
-
-        def ll_compress(fnptr):
-            for c, p in unroll_table:
-                if fnptr == p:
-                    return c
-            else:
-                ll_assert(fnptr == last_p, "unexpected function pointer")
-                return last_c
-        r_set._compression_function = ll_compress
-    return r_set._compression_function
-
-
-class __extend__(pairtype(FunctionsPBCRepr, SmallFunctionSetPBCRepr)):
-    def convert_from_to((r_ptr, r_set), v, llops):
-        if r_ptr.lowleveltype is Void:
-            desc, = r_ptr.s_pbc.descriptions
-            return inputconst(Char, r_set.convert_desc(desc))
-        else:
-            ll_compress = compression_function(r_set)
-            return llops.gendirectcall(ll_compress, v)
-
-
-def conversion_table(r_from, r_to):
-    if r_to in r_from._conversion_tables:
-        return r_from._conversion_tables[r_to]
-    else:
-        t = malloc(Array(Char, hints={'nolength': True}),
-                   len(r_from.descriptions), immortal=True)
-        l = []
-        for i, d in enumerate(r_from.descriptions):
-            if d in r_to.descriptions:
-                j = r_to.descriptions.index(d)
-                l.append(j)
-                t[i] = chr(j)
-            else:
-                l.append(None)
-        if l == range(len(r_from.descriptions)):
-            r = None
-        else:
-            r = inputconst(Ptr(Array(Char, hints={'nolength': True})), t)
-        r_from._conversion_tables[r_to] = r
-        return r
-
-
-class __extend__(pairtype(SmallFunctionSetPBCRepr, SmallFunctionSetPBCRepr)):
-    def convert_from_to((r_from, r_to), v, llops):
-        c_table = conversion_table(r_from, r_to)
-        if c_table:
-            assert v.concretetype is Char
-            v_int = llops.genop('cast_char_to_int', [v],
-                                resulttype=Signed)
-            return llops.genop('getarrayitem', [c_table, v_int],
-                               resulttype=Char)
-        else:
-            return v
diff --git a/rpython/rtyper/rnone.py b/rpython/rtyper/rnone.py
--- a/rpython/rtyper/rnone.py
+++ b/rpython/rtyper/rnone.py
@@ -3,7 +3,7 @@
 from rpython.rtyper.rmodel import Repr, TyperError, inputconst
 from rpython.rtyper.lltypesystem.lltype import Void, Bool, Ptr, Char
 from rpython.rtyper.lltypesystem.llmemory import Address
-from rpython.rtyper.lltypesystem.rpbc import SmallFunctionSetPBCRepr
+from rpython.rtyper.rpbc import SmallFunctionSetPBCRepr
 from rpython.rtyper.annlowlevel import llstr
 from rpython.tool.pairtype import pairtype
 
diff --git a/rpython/rtyper/rpbc.py b/rpython/rtyper/rpbc.py
--- a/rpython/rtyper/rpbc.py
+++ b/rpython/rtyper/rpbc.py
@@ -5,13 +5,20 @@
     FunctionDesc, ClassDesc, MethodDesc, FrozenDesc, MethodOfFrozenDesc)
 from rpython.flowspace.model import Constant
 from rpython.annotator.argument import simple_args
+from rpython.rlib.debug import ll_assert
+from rpython.rlib.unroll import unrolling_iterable
 from rpython.rtyper import rclass, callparse
 from rpython.rtyper.rclass import CLASSTYPE, OBJECT_VTABLE, OBJECTPTR
 from rpython.rtyper.error import TyperError
-from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.rtyper.lltypesystem import rffi
+from rpython.rtyper.lltypesystem import llmemory
+from rpython.rtyper.lltypesystem.lltype import (typeOf, Void, ForwardReference,
+    Struct, Bool, Char, Ptr, malloc, nullptr, Array, Signed)
 from rpython.rtyper.rmodel import (Repr, inputconst, CanBeNull, mangle,
     warning, impossible_repr)
+from rpython.rtyper.typesystem import getfunctionptr
 from rpython.tool.pairtype import pair, pairtype
+from rpython.translator.unsimplify import varoftype
 
 
 def small_cand(rtyper, s_pbc):
@@ -25,8 +32,6 @@
 
 class __extend__(annmodel.SomePBC):
     def rtyper_makerepr(self, rtyper):
-        from rpython.rtyper.lltypesystem.rpbc import (
-            FunctionsPBCRepr, SmallFunctionSetPBCRepr)
         kind = self.getKind()
         if issubclass(kind, FunctionDesc):
             sample = self.any_description()
@@ -124,7 +129,7 @@
                 concreterow[funcdesc] = llfn
             assert len(concreterow) > 0
             # 'llfn' should be the same for all graphs
-            concreterow.fntype = lltype.typeOf(llfn)
+            concreterow.fntype = typeOf(llfn)
             concreterows[shape, index] = concreterow
 
     for row in concreterows.values():
@@ -162,7 +167,7 @@
     return llct
 
 
-class AbstractFunctionsPBCRepr(CanBeNull, Repr):
+class FunctionsPBCRepr(CanBeNull, Repr):
     """Representation selected for a PBC of function(s)."""
 
     def __init__(self, rtyper, s_pbc):
@@ -171,7 +176,7 @@
         self.callfamily = s_pbc.any_description().getcallfamily()
         if len(s_pbc.descriptions) == 1 and not s_pbc.can_be_None:
             # a single function
-            self.lowleveltype = lltype.Void
+            self.lowleveltype = Void
         else:
             llct = get_concrete_calltable(self.rtyper, self.callfamily)
             self.concretetable = llct.table
@@ -186,6 +191,19 @@
                 self.lowleveltype = self.setup_specfunc()
         self.funccache = {}
 
+    def setup_specfunc(self):
+        fields = []
+        for row in self.uniquerows:
+            fields.append((row.attrname, row.fntype))
+        kwds = {'hints': {'immutable': True}}
+        return Ptr(Struct('specfunc', *fields, **kwds))
+
+    def create_specfunc(self):
+        return malloc(self.lowleveltype.TO, immortal=True)
+
+    def get_specfunc_row(self, llop, v, c_rowname, resulttype):
+        return llop.genop('getfield', [v, c_rowname], resulttype=resulttype)
+
     def get_s_callable(self):
         return self.s_pbc
 
@@ -202,7 +220,7 @@
             return self.funccache[funcdesc]
         except KeyError:
             pass
-        if self.lowleveltype is lltype.Void:
+        if self.lowleveltype is Void:
             result = None
         else:
             llfns = {}
@@ -238,7 +256,7 @@
             value = value.im_func  # unbound method -> bare function
         elif isinstance(value, staticmethod):
             value = value.__get__(42)  # hackish, get the function wrapped by staticmethod
-        if self.lowleveltype is lltype.Void:
+        if self.lowleveltype is Void:
             return None
         if value is None:
             null = self.rtyper.type_system.null_callable(self.lowleveltype)
@@ -252,27 +270,27 @@
         'index' and 'shape' tells which of its items we are interested in.
         """
         assert v.concretetype == self.lowleveltype
-        if self.lowleveltype is lltype.Void:
+        if self.lowleveltype is Void:
             assert len(self.s_pbc.descriptions) == 1
                                       # lowleveltype wouldn't be Void otherwise
             funcdesc, = self.s_pbc.descriptions
             row_of_one_graph = self.callfamily.calltables[shape][index]
             graph = row_of_one_graph[funcdesc]
             llfn = self.rtyper.getcallable(graph)
-            return inputconst(lltype.typeOf(llfn), llfn)
+            return inputconst(typeOf(llfn), llfn)
         elif len(self.uniquerows) == 1:
             return v
         else:
             # 'v' is a Struct pointer, read the corresponding field
             row = self.concretetable[shape, index]
-            cname = inputconst(lltype.Void, row.attrname)
+            cname = inputconst(Void, row.attrname)
             return self.get_specfunc_row(llop, v, cname, row.fntype)
 
     def get_unique_llfn(self):
         # try to build a unique low-level function.  Avoid to use
         # whenever possible!  Doesn't work with specialization, multiple
         # different call sites, etc.
-        if self.lowleveltype is not lltype.Void:
+        if self.lowleveltype is not Void:
             raise TyperError("cannot pass multiple functions here")
         assert len(self.s_pbc.descriptions) == 1
                                   # lowleveltype wouldn't be Void otherwise
@@ -294,7 +312,7 @@
         if graphs != [graph] * len(graphs):
             raise TyperError("cannot pass a specialized function here")
         llfn = self.rtyper.getcallable(graph)
-        return inputconst(lltype.typeOf(llfn), llfn)
+        return inputconst(typeOf(llfn), llfn)
 
     def get_concrete_llfn(self, s_pbc, args_s, op):
         bk = self.rtyper.annotator.bookkeeper
@@ -306,7 +324,7 @@
         row_of_one_graph = self.callfamily.calltables[shape][index]
         graph = row_of_one_graph[funcdesc]
         llfn = self.rtyper.getcallable(graph)
-        return inputconst(lltype.typeOf(llfn), llfn)
+        return inputconst(typeOf(llfn), llfn)
 
     def rtype_simple_call(self, hop):
         return self.call(hop)
@@ -332,28 +350,227 @@
         if isinstance(vlist[0], Constant):
             v = hop.genop('direct_call', vlist, resulttype=rresult)
         else:
-            vlist.append(hop.inputconst(lltype.Void, row_of_graphs.values()))
+            vlist.append(hop.inputconst(Void, row_of_graphs.values()))
             v = hop.genop('indirect_call', vlist, resulttype=rresult)
         if hop.r_result is impossible_repr:
             return None      # see test_always_raising_methods
         else:
             return hop.llops.convertvar(v, rresult, hop.r_result)
 
-class __extend__(pairtype(AbstractFunctionsPBCRepr, AbstractFunctionsPBCRepr)):
+class __extend__(pairtype(FunctionsPBCRepr, FunctionsPBCRepr)):
     def convert_from_to((r_fpbc1, r_fpbc2), v, llops):
         # this check makes sense because both source and dest repr are FunctionsPBCRepr
         if r_fpbc1.lowleveltype == r_fpbc2.lowleveltype:
             return v
-        if r_fpbc1.lowleveltype is lltype.Void:
+        if r_fpbc1.lowleveltype is Void:
             return inputconst(r_fpbc2, r_fpbc1.s_pbc.const)
-        if r_fpbc2.lowleveltype is lltype.Void:
-            return inputconst(lltype.Void, None)
+        if r_fpbc2.lowleveltype is Void:
+            return inputconst(Void, None)
         return NotImplemented
 
 
+class SmallFunctionSetPBCRepr(Repr):
+    def __init__(self, rtyper, s_pbc):
+        self.rtyper = rtyper
+        self.s_pbc = s_pbc
+        self.callfamily = s_pbc.any_description().getcallfamily()
+        llct = get_concrete_calltable(self.rtyper, self.callfamily)
+        assert len(llct.uniquerows) == 1
+        self.lowleveltype = Char
+        self.pointer_repr = FunctionsPBCRepr(rtyper, s_pbc)
+        self._conversion_tables = {}
+        self._compression_function = None
+        self._dispatch_cache = {}
+
+    def _setup_repr(self):
+        if self.s_pbc.subset_of:
+            assert self.s_pbc.can_be_None == self.s_pbc.subset_of.can_be_None
+            r = self.rtyper.getrepr(self.s_pbc.subset_of)
+            if r is not self:
+                r.setup()
+                self.descriptions = r.descriptions
+                self.c_pointer_table = r.c_pointer_table
+                return
+        self.descriptions = list(self.s_pbc.descriptions)
+        if self.s_pbc.can_be_None:
+            self.descriptions.insert(0, None)
+        POINTER_TABLE = Array(self.pointer_repr.lowleveltype,
+                              hints={'nolength': True})
+        pointer_table = malloc(POINTER_TABLE, len(self.descriptions),
+                               immortal=True)
+        for i, desc in enumerate(self.descriptions):
+            if desc is not None:
+                pointer_table[i] = self.pointer_repr.convert_desc(desc)
+            else:
+                pointer_table[i] = self.pointer_repr.convert_const(None)
+        self.c_pointer_table = inputconst(Ptr(POINTER_TABLE), pointer_table)
+
+    def get_s_callable(self):
+        return self.s_pbc
+
+    def get_r_implfunc(self):
+        return self, 0
+
+    def get_s_signatures(self, shape):
+        funcdesc = self.s_pbc.any_description()
+        return funcdesc.get_s_signatures(shape)
+
+    def convert_desc(self, funcdesc):
+        return chr(self.descriptions.index(funcdesc))
+
+    def convert_const(self, value):
+        if isinstance(value, types.MethodType) and value.im_self is None:
+            value = value.im_func   # unbound method -> bare function
+        if value is None:
+            return chr(0)
+        funcdesc = self.rtyper.annotator.bookkeeper.getdesc(value)
+        return self.convert_desc(funcdesc)
+
+    def rtype_simple_call(self, hop):
+        return self.call(hop)
+
+    def rtype_call_args(self, hop):
+        return self.call(hop)
+
+    def dispatcher(self, shape, index, argtypes, resulttype):
+        key = shape, index, tuple(argtypes), resulttype
+        if key in self._dispatch_cache:
+            return self._dispatch_cache[key]
+        inputargs = [varoftype(t) for t in [Char] + argtypes]
+        startblock = Block(inputargs)
+        startblock.exitswitch = inputargs[0]
+        graph = FunctionGraph("dispatcher", startblock, varoftype(resulttype))
+        row_of_graphs = self.callfamily.calltables[shape][index]
+        links = []
+        descs = list(self.s_pbc.descriptions)
+        if self.s_pbc.can_be_None:
+            descs.insert(0, None)
+        for desc in descs:
+            if desc is None:
+                continue
+            args_v = [varoftype(t) for t in argtypes]
+            b = Block(args_v)
+            llfn = self.rtyper.getcallable(row_of_graphs[desc])
+            v_fn = inputconst(typeOf(llfn), llfn)
+            v_result = varoftype(resulttype)
+            b.operations.append(
+                SpaceOperation("direct_call", [v_fn] + args_v, v_result))
+            b.closeblock(Link([v_result], graph.returnblock))
+            i = self.descriptions.index(desc)
+            links.append(Link(inputargs[1:], b, chr(i)))
+            links[-1].llexitcase = chr(i)
+        startblock.closeblock(*links)
+        self.rtyper.annotator.translator.graphs.append(graph)
+        ll_ret = getfunctionptr(graph)
+        #FTYPE = FuncType
+        c_ret = self._dispatch_cache[key] = inputconst(typeOf(ll_ret), ll_ret)
+        return c_ret
+
+    def call(self, hop):
+        bk = self.rtyper.annotator.bookkeeper
+        args = hop.spaceop.build_args(hop.args_s[1:])
+        s_pbc = hop.args_s[0]   # possibly more precise than self.s_pbc
+        descs = list(s_pbc.descriptions)
+        vfcs = FunctionDesc.variant_for_call_site
+        shape, index = vfcs(bk, self.callfamily, descs, args, hop.spaceop)
+        row_of_graphs = self.callfamily.calltables[shape][index]
+        anygraph = row_of_graphs.itervalues().next()  # pick any witness
+        vlist = [hop.inputarg(self, arg=0)]
+        vlist += callparse.callparse(self.rtyper, anygraph, hop)
+        rresult = callparse.getrresult(self.rtyper, anygraph)
+        hop.exception_is_here()
+        v_dispatcher = self.dispatcher(shape, index,
+                [v.concretetype for v in vlist[1:]], rresult.lowleveltype)
+        v_result = hop.genop('direct_call', [v_dispatcher] + vlist,
+                             resulttype=rresult)
+        return hop.llops.convertvar(v_result, rresult, hop.r_result)
+
+    def rtype_bool(self, hop):
+        if not self.s_pbc.can_be_None:
+            return inputconst(Bool, True)
+        else:
+            v1, = hop.inputargs(self)
+            return hop.genop('char_ne', [v1, inputconst(Char, '\000')],
+                         resulttype=Bool)
+
+
+class __extend__(pairtype(SmallFunctionSetPBCRepr, FunctionsPBCRepr)):
+    def convert_from_to((r_set, r_ptr), v, llops):
+        if r_ptr.lowleveltype is Void:
+            return inputconst(Void, None)
+        else:
+            assert v.concretetype is Char
+            v_int = llops.genop('cast_char_to_int', [v],
+                                resulttype=Signed)
+            return llops.genop('getarrayitem', [r_set.c_pointer_table, v_int],
+                               resulttype=r_ptr.lowleveltype)
+
+
+def compression_function(r_set):
+    if r_set._compression_function is None:
+        table = []
+        for i, p in enumerate(r_set.c_pointer_table.value):
+            table.append((chr(i), p))
+        last_c, last_p = table[-1]
+        unroll_table = unrolling_iterable(table[:-1])
+
+        def ll_compress(fnptr):
+            for c, p in unroll_table:
+                if fnptr == p:
+                    return c
+            else:
+                ll_assert(fnptr == last_p, "unexpected function pointer")
+                return last_c
+        r_set._compression_function = ll_compress
+    return r_set._compression_function
+
+
+class __extend__(pairtype(FunctionsPBCRepr, SmallFunctionSetPBCRepr)):
+    def convert_from_to((r_ptr, r_set), v, llops):
+        if r_ptr.lowleveltype is Void:
+            desc, = r_ptr.s_pbc.descriptions
+            return inputconst(Char, r_set.convert_desc(desc))
+        else:
+            ll_compress = compression_function(r_set)
+            return llops.gendirectcall(ll_compress, v)
+
+
+def conversion_table(r_from, r_to):
+    if r_to in r_from._conversion_tables:
+        return r_from._conversion_tables[r_to]
+    else:
+        t = malloc(Array(Char, hints={'nolength': True}),
+                   len(r_from.descriptions), immortal=True)
+        l = []
+        for i, d in enumerate(r_from.descriptions):
+            if d in r_to.descriptions:
+                j = r_to.descriptions.index(d)
+                l.append(j)
+                t[i] = chr(j)
+            else:
+                l.append(None)
+        if l == range(len(r_from.descriptions)):
+            r = None
+        else:
+            r = inputconst(Ptr(Array(Char, hints={'nolength': True})), t)
+        r_from._conversion_tables[r_to] = r
+        return r
+
+
+class __extend__(pairtype(SmallFunctionSetPBCRepr, SmallFunctionSetPBCRepr)):
+    def convert_from_to((r_from, r_to), v, llops):
+        c_table = conversion_table(r_from, r_to)
+        if c_table:
+            assert v.concretetype is Char
+            v_int = llops.genop('cast_char_to_int', [v],
+                                resulttype=Signed)
+            return llops.genop('getarrayitem', [c_table, v_int],
+                               resulttype=Char)
+        else:
+            return v
+
+
 def getFrozenPBCRepr(rtyper, s_pbc):
-    from rpython.rtyper.lltypesystem.rpbc import (
-        MultipleUnrelatedFrozenPBCRepr, MultipleFrozenPBCRepr)
     descs = list(s_pbc.descriptions)
     assert len(descs) >= 1
     if len(descs) == 1 and not s_pbc.can_be_None:
@@ -380,7 +597,7 @@
 
 class SingleFrozenPBCRepr(Repr):
     """Representation selected for a single non-callable pre-built constant."""
-    lowleveltype = lltype.Void
+    lowleveltype = Void
 
     def __init__(self, frozendesc):
         self.frozendesc = frozendesc
@@ -405,9 +622,18 @@
         return self.getstr()
 
 
-class AbstractMultipleUnrelatedFrozenPBCRepr(CanBeNull, Repr):
+class MultipleFrozenPBCReprBase(CanBeNull, Repr):
+    def convert_const(self, pbc):
+        if pbc is None:
+            return self.null_instance()
+        frozendesc = self.rtyper.annotator.bookkeeper.getdesc(pbc)
+        return self.convert_desc(frozendesc)
+
+class MultipleUnrelatedFrozenPBCRepr(MultipleFrozenPBCReprBase):
     """For a SomePBC of frozen PBCs that have no common access set.
     The only possible operation on such a thing is comparison with 'is'."""
+    lowleveltype = llmemory.Address
+    EMPTY = Struct('pbc', hints={'immutable': True})
 
     def __init__(self, rtyper):
         self.rtyper = rtyper
@@ -418,7 +644,7 @@
             return self.converted_pbc_cache[frozendesc]
         except KeyError:
             r = self.rtyper.getrepr(annmodel.SomePBC([frozendesc]))
-            if r.lowleveltype is lltype.Void:
+            if r.lowleveltype is Void:
                 # must create a new empty structure, as a placeholder
                 pbc = self.create_instance()
             else:
@@ -427,20 +653,62 @@
             self.converted_pbc_cache[frozendesc] = convpbc
             return convpbc
 
-    def convert_const(self, pbc):
-        if pbc is None:
-            return self.null_instance()
-        frozendesc = self.rtyper.annotator.bookkeeper.getdesc(pbc)
-        return self.convert_desc(frozendesc)
+    def convert_pbc(self, pbcptr):
+        return llmemory.fakeaddress(pbcptr)
+
+    def create_instance(self):
+        return malloc(self.EMPTY, immortal=True)
+
+    def null_instance(self):
+        return llmemory.Address._defl()
 
     def rtype_getattr(_, hop):
         if not hop.s_result.is_constant():
             raise TyperError("getattr on a constant PBC returns a non-constant")
         return hop.inputconst(hop.r_result, hop.s_result.const)
 
-class AbstractMultipleFrozenPBCRepr(AbstractMultipleUnrelatedFrozenPBCRepr):
+class __extend__(pairtype(MultipleUnrelatedFrozenPBCRepr,
+                          MultipleUnrelatedFrozenPBCRepr),
+                 pairtype(MultipleUnrelatedFrozenPBCRepr,
+                          SingleFrozenPBCRepr),
+                 pairtype(SingleFrozenPBCRepr,
+                          MultipleUnrelatedFrozenPBCRepr)):
+    def rtype_is_((robj1, robj2), hop):
+        if isinstance(robj1, MultipleUnrelatedFrozenPBCRepr):
+            r = robj1
+        else:
+            r = robj2
+        vlist = hop.inputargs(r, r)
+        return hop.genop('adr_eq', vlist, resulttype=Bool)
+
+
+class MultipleFrozenPBCRepr(MultipleFrozenPBCReprBase):
     """For a SomePBC of frozen PBCs with a common attribute access set."""
 
+    def __init__(self, rtyper, access_set):
+        self.rtyper = rtyper
+        self.access_set = access_set
+        self.pbc_type = ForwardReference()
+        self.lowleveltype = Ptr(self.pbc_type)
+        self.pbc_cache = {}
+
+    def _setup_repr(self):
+        llfields = self._setup_repr_fields()
+        kwds = {'hints': {'immutable': True}}
+        self.pbc_type.become(Struct('pbc', *llfields, **kwds))
+
+    def create_instance(self):
+        return malloc(self.pbc_type, immortal=True)
+
+    def null_instance(self):
+        return nullptr(self.pbc_type)
+
+    def getfield(self, vpbc, attr, llops):
+        mangled_name, r_value = self.fieldmap[attr]
+        cmangledname = inputconst(Void, mangled_name)
+        return llops.genop('getfield', [vpbc, cmangledname],
+                           resulttype=r_value)
+
     def _setup_repr_fields(self):
         fields = []
         self.fieldmap = {}
@@ -466,7 +734,7 @@
             result = self.create_instance()
             self.pbc_cache[frozendesc] = result
             for attr, (mangled_name, r_value) in self.fieldmap.items():
-                if r_value.lowleveltype is lltype.Void:
+                if r_value.lowleveltype is Void:
                     continue
                 try:
                     thisattrvalue = frozendesc.attrcache[attr]
@@ -483,18 +751,23 @@
             return hop.inputconst(hop.r_result, hop.s_result.const)
 
         attr = hop.args_s[1].const
-        vpbc, vattr = hop.inputargs(self, lltype.Void)
+        vpbc, vattr = hop.inputargs(self, Void)
         v_res = self.getfield(vpbc, attr, hop.llops)
         mangled_name, r_res = self.fieldmap[attr]
         return hop.llops.convertvar(v_res, r_res, hop.r_result)
 
-class __extend__(pairtype(AbstractMultipleFrozenPBCRepr, AbstractMultipleFrozenPBCRepr)):
+class __extend__(pairtype(MultipleFrozenPBCRepr,
+                          MultipleUnrelatedFrozenPBCRepr)):
+    def convert_from_to((robj1, robj2), v, llops):
+        return llops.genop('cast_ptr_to_adr', [v], resulttype=llmemory.Address)
+
+class __extend__(pairtype(MultipleFrozenPBCRepr, MultipleFrozenPBCRepr)):
     def convert_from_to((r_pbc1, r_pbc2), v, llops):
         if r_pbc1.access_set == r_pbc2.access_set:
             return v
         return NotImplemented
 
-class __extend__(pairtype(SingleFrozenPBCRepr, AbstractMultipleFrozenPBCRepr)):
+class __extend__(pairtype(SingleFrozenPBCRepr, MultipleFrozenPBCRepr)):
     def convert_from_to((r_pbc1, r_pbc2), v, llops):
         frozendesc1 = r_pbc1.frozendesc
         access = frozendesc1.queryattrfamily()
@@ -504,10 +777,10 @@
             return Constant(value, lltype)
         return NotImplemented
 
-class __extend__(pairtype(AbstractMultipleUnrelatedFrozenPBCRepr,
+class __extend__(pairtype(MultipleFrozenPBCReprBase,
                           SingleFrozenPBCRepr)):
     def convert_from_to((r_pbc1, r_pbc2), v, llops):
-        return inputconst(lltype.Void, r_pbc2.frozendesc)
+        return inputconst(Void, r_pbc2.frozendesc)
 
 
 class MethodOfFrozenPBCRepr(Repr):
@@ -601,7 +874,7 @@
         #    raise TyperError("unsupported: variable of type "
         #                     "class-pointer or None")
         if s_pbc.is_constant():
-            self.lowleveltype = lltype.Void
+            self.lowleveltype = Void
         else:
             self.lowleveltype = self.getlowleveltype()
 
@@ -624,7 +897,7 @@
     def convert_desc(self, desc):
         if desc not in self.s_pbc.descriptions:
             raise TyperError("%r not in %r" % (desc, self))
-        if self.lowleveltype is lltype.Void:
+        if self.lowleveltype is Void:
             return None
         subclassdef = desc.getuniqueclassdef()
         r_subclass = rclass.getclassrepr(self.rtyper, subclassdef)
@@ -632,7 +905,7 @@
 
     def convert_const(self, cls):
         if cls is None:
-            if self.lowleveltype is lltype.Void:
+            if self.lowleveltype is Void:
                 return None
             else:
                 T = self.lowleveltype
@@ -649,12 +922,12 @@
             if attr == '__name__':
                 from rpython.rtyper.lltypesystem import rstr
                 class_repr = self.rtyper.rootclass_repr
-                vcls, vattr = hop.inputargs(class_repr, lltype.Void)
-                cname = inputconst(lltype.Void, 'name')
+                vcls, vattr = hop.inputargs(class_repr, Void)
+                cname = inputconst(Void, 'name')
                 return hop.genop('getfield', [vcls, cname],
-                                 resulttype = lltype.Ptr(rstr.STR))
+                                 resulttype = Ptr(rstr.STR))
             access_set, class_repr = self.get_access_set(attr)
-            vcls, vattr = hop.inputargs(class_repr, lltype.Void)
+            vcls, vattr = hop.inputargs(class_repr, Void)
             v_res = class_repr.getpbcfield(vcls, access_set, attr, hop.llops)
             s_res = access_set.s_value
             r_res = self.rtyper.getrepr(s_res)
@@ -683,7 +956,7 @@
 
         if len(self.s_pbc.descriptions) == 1:
             # instantiating a single class
-            if self.lowleveltype is not lltype.Void:
+            if self.lowleveltype is not Void:
                 assert 0, "XXX None-or-1-class instantation not implemented"
             assert isinstance(s_instance, annmodel.SomeInstance)
             classdef = s_instance.classdef
@@ -740,10 +1013,10 @@
             classdef = desc.getclassdef(None)
             assert hasattr(classdef, 'my_instantiate_graph')
             graphs.append(classdef.my_instantiate_graph)
-        c_graphs = hop.inputconst(lltype.Void, graphs)
+        c_graphs = hop.inputconst(Void, graphs)
         #
         # "my_instantiate = typeptr.instantiate"
-        c_name = hop.inputconst(lltype.Void, 'instantiate')
+        c_name = hop.inputconst(Void, 'instantiate')
         v_instantiate = hop.genop('getfield', [vtypeptr, c_name],
                                  resulttype=OBJECT_VTABLE.instantiate)
         # "my_instantiate()"
@@ -774,7 +1047,7 @@
         # turn a PBC of classes to a standard pointer-to-vtable class repr
         if r_clspbc.lowleveltype == r_cls.lowleveltype:
             return v
-        if r_clspbc.lowleveltype is lltype.Void:
+        if r_clspbc.lowleveltype is Void:
             return inputconst(r_cls, r_clspbc.s_pbc.const)
         # convert from ptr-to-object-vtable to ptr-to-more-precise-vtable
         return r_cls.fromclasstype(v, llops)
@@ -784,10 +1057,10 @@
         # this check makes sense because both source and dest repr are ClassesPBCRepr
         if r_clspbc1.lowleveltype == r_clspbc2.lowleveltype:
             return v
-        if r_clspbc1.lowleveltype is lltype.Void:
+        if r_clspbc1.lowleveltype is Void:
             return inputconst(r_clspbc2, r_clspbc1.s_pbc.const)
-        if r_clspbc2.lowleveltype is lltype.Void:
-            return inputconst(lltype.Void, r_clspbc2.s_pbc.const)
+        if r_clspbc2.lowleveltype is Void:
+            return inputconst(Void, r_clspbc2.s_pbc.const)
         return NotImplemented
 
 def adjust_shape(hop2, s_shape):
@@ -864,8 +1137,6 @@
         return self.redispatch_call(hop, call_args=True)
 
     def redispatch_call(self, hop, call_args):
-        from rpython.rtyper.lltypesystem.rpbc import (
-            FunctionsPBCRepr, SmallFunctionSetPBCRepr)
         r_class = self.r_im_self.rclass
         mangled_name, r_func = r_class.clsfields[self.methodname]
         assert isinstance(r_func, (FunctionsPBCRepr,
@@ -890,28 +1161,3 @@
 
         # now hop2 looks like simple_call(function, self, args...)
         return hop2.dispatch()
-
-# ____________________________________________________________
-
-def samesig(funcs):
-    import inspect
-    argspec = inspect.getargspec(funcs[0])
-    for func in funcs:
-        if inspect.getargspec(func) != argspec:
-            return False
-    return True
-
-# ____________________________________________________________
-
-def commonbase(classdefs):
-    result = classdefs[0]
-    for cdef in classdefs[1:]:
-        result = result.commonbase(cdef)
-        if result is None:
-            raise TyperError("no common base class in %r" % (classdefs,))
-    return result
-
-def allattributenames(classdef):
-    for cdef1 in classdef.getmro():
-        for attrname in cdef1.attrs:
-            yield cdef1, attrname


More information about the pypy-commit mailing list