Author: Ronan Lamy <[email protected]>
Branch:
Changeset: r80051:ab645e87e727
Date: 2015-10-08 16:46 +0100
http://bitbucket.org/pypy/pypy/changeset/ab645e87e727/
Log: Merged in callfamily (pull request #339)
Callfamily
diff --git a/rpython/annotator/annrpython.py b/rpython/annotator/annrpython.py
--- a/rpython/annotator/annrpython.py
+++ b/rpython/annotator/annrpython.py
@@ -213,8 +213,6 @@
v = graph.getreturnvar()
if v.annotation is None:
self.setbinding(v, annmodel.s_ImpossibleValue)
- # policy-dependent computation
- self.bookkeeper.compute_at_fixpoint()
def validate(self):
"""Check that the annotation results are valid"""
@@ -292,6 +290,18 @@
graph, block, index = position_key
self.reflowpendingblock(graph, block)
+ def call_sites(self):
+ newblocks = self.added_blocks
+ if newblocks is None:
+ newblocks = self.annotated # all of them
+ for block in newblocks:
+ for op in block.operations:
+ if op.opname in ('simple_call', 'call_args'):
+ yield op
+
+ # some blocks are partially annotated
+ if op.result.annotation is None:
+ break # ignore the unannotated part
#___ simplification (should be moved elsewhere?) _______
@@ -309,6 +319,7 @@
graphs[graph] = True
for graph in graphs:
simplify.eliminate_empty_blocks(graph)
+ self.bookkeeper.compute_at_fixpoint()
if block_subset is None:
perform_normalizations(self)
@@ -396,8 +407,7 @@
i = 0
while i < len(block.operations):
op = block.operations[i]
- self.bookkeeper.enter((graph, block, i))
- try:
+ with self.bookkeeper.at_position((graph, block, i)):
new_ops = op.transform(self)
if new_ops is not None:
block.operations[i:i+1] = new_ops
@@ -406,8 +416,6 @@
new_ops[-1].result = op.result
op = new_ops[0]
self.consider_op(op)
- finally:
- self.bookkeeper.leave()
i += 1
except BlockedInference as e:
diff --git a/rpython/annotator/bookkeeper.py b/rpython/annotator/bookkeeper.py
--- a/rpython/annotator/bookkeeper.py
+++ b/rpython/annotator/bookkeeper.py
@@ -5,6 +5,7 @@
from __future__ import absolute_import
import sys, types, inspect, weakref
+from contextlib import contextmanager
from rpython.flowspace.model import Constant
from rpython.annotator.model import (SomeOrderedDict,
@@ -88,34 +89,29 @@
del TLS.bookkeeper
del self.position_key
+ @contextmanager
+ def at_position(self, pos):
+ """A context manager calling `self.enter()` and `self.leave()`"""
+ if hasattr(self, 'position_key') and pos is None:
+ yield
+ return
+ self.enter(pos)
+ try:
+ yield
+ finally:
+ self.leave()
+
def compute_at_fixpoint(self):
# getbookkeeper() needs to work during this function, so provide
# one with a dummy position
- self.enter(None)
- try:
- def call_sites():
- newblocks = self.annotator.added_blocks
- if newblocks is None:
- newblocks = self.annotator.annotated # all of them
- annotation = self.annotator.annotation
- for block in newblocks:
- for op in block.operations:
- if op.opname in ('simple_call', 'call_args'):
- yield op
-
- # some blocks are partially annotated
- if annotation(op.result) is None:
- break # ignore the unannotated part
-
- for call_op in call_sites():
+ with self.at_position(None):
+ for call_op in self.annotator.call_sites():
self.consider_call_site(call_op)
for pbc, args_s in self.emulated_pbc_calls.itervalues():
args = simple_args(args_s)
pbc.consider_call_site(args, s_ImpossibleValue, None)
self.emulated_pbc_calls = {}
- finally:
- self.leave()
def check_no_flags_on_instances(self):
# sanity check: no flags attached to heap stored instances
@@ -501,10 +497,6 @@
"""Analyse a call to a SomePBC() with the given args (list of
annotations).
"""
- descs = list(pbc.descriptions)
- first = descs[0]
- first.mergecallfamilies(*descs[1:])
-
if emulated is None:
whence = self.position_key
# fish the existing annotation for the result variable,
@@ -522,12 +514,9 @@
op = None
s_previous_result = s_ImpossibleValue
- def schedule(graph, inputcells):
- return self.annotator.recursivecall(graph, whence, inputcells)
-
results = []
- for desc in descs:
- results.append(desc.pycall(schedule, args, s_previous_result, op))
+ for desc in pbc.descriptions:
+ results.append(desc.pycall(whence, args, s_previous_result, op))
s_result = unionof(*results)
return s_result
@@ -552,10 +541,7 @@
"replace" can be set to a list of old unique_key values to
forget now, because the given "unique_key" replaces them.
"""
- emulate_enter = not hasattr(self, 'position_key')
- if emulate_enter:
- self.enter(None)
- try:
+ with self.at_position(None):
emulated_pbc_calls = self.emulated_pbc_calls
prev = [unique_key]
prev.extend(replace)
@@ -570,9 +556,6 @@
else:
emulated = callback
return self.pbc_call(pbc, args, emulated=emulated)
- finally:
- if emulate_enter:
- self.leave()
def _find_current_op(self, opname=None, arity=None, pos=None, s_type=None):
""" Find operation that is currently being annotated. Do some
diff --git a/rpython/annotator/description.py b/rpython/annotator/description.py
--- a/rpython/annotator/description.py
+++ b/rpython/annotator/description.py
@@ -53,6 +53,22 @@
table.append(row)
self.total_calltable_size += 1
+ def find_row(self, bookkeeper, descs, args, op):
+ shape = rawshape(args)
+ with bookkeeper.at_position(None):
+ row = build_calltable_row(descs, args, op)
+ index = self.calltable_lookup_row(shape, row)
+ return shape, index
+
+def build_calltable_row(descs, args, op):
+ # see comments in CallFamily
+ row = {}
+ for desc in descs:
+ graph = desc.get_graph(args, op)
+ assert isinstance(graph, FunctionGraph)
+ row[desc.rowkey()] = graph
+ return row
+
class FrozenAttrFamily(object):
"""A family of FrozenDesc objects that have any common 'getattr' sites.
@@ -295,22 +311,23 @@
else:
return self.specializer(self, inputcells)
- def pycall(self, schedule, args, s_previous_result, op=None):
+ def pycall(self, whence, args, s_previous_result, op=None):
inputcells = self.parse_arguments(args)
result = self.specialize(inputcells, op)
if isinstance(result, FunctionGraph):
graph = result # common case
+ annotator = self.bookkeeper.annotator
# if that graph has a different signature, we need to re-parse
# the arguments.
# recreate the args object because inputcells may have been changed
new_args = args.unmatch_signature(self.signature, inputcells)
inputcells = self.parse_arguments(new_args, graph)
- result = schedule(graph, inputcells)
+ result = annotator.recursivecall(graph, whence, inputcells)
signature = getattr(self.pyobj, '_signature_', None)
if signature:
sigresult = enforce_signature_return(self, signature[1],
result)
if sigresult is not None:
- self.bookkeeper.annotator.addpendingblock(
+ annotator.addpendingblock(
graph, graph.returnblock, [sigresult])
result = sigresult
# Some specializations may break the invariant of returning
@@ -320,6 +337,10 @@
result = unionof(result, s_previous_result)
return result
+ def get_graph(self, args, op):
+ inputs_s = self.parse_arguments(args)
+ return self.specialize(inputs_s, op)
+
def get_call_parameters(self, args_s):
args = simple_args(args_s)
inputcells = self.parse_arguments(args)
@@ -347,37 +368,15 @@
@staticmethod
def consider_call_site(descs, args, s_result, op):
+ family = descs[0].getcallfamily()
shape = rawshape(args)
- row = FunctionDesc.row_to_consider(descs, args, op)
- family = descs[0].getcallfamily()
+ row = build_calltable_row(descs, args, op)
family.calltable_add_row(shape, row)
-
- @staticmethod
- def variant_for_call_site(bookkeeper, family, descs, args, op):
- shape = rawshape(args)
- bookkeeper.enter(None)
- try:
- row = FunctionDesc.row_to_consider(descs, args, op)
- finally:
- bookkeeper.leave()
- index = family.calltable_lookup_row(shape, row)
- return shape, index
+ descs[0].mergecallfamilies(*descs[1:])
def rowkey(self):
return self
- @staticmethod
- def row_to_consider(descs, args, op):
- # see comments in CallFamily
- row = {}
- for desc in descs:
- def enlist(graph, ignore):
- row[desc.rowkey()] = graph
- return s_ImpossibleValue # meaningless
- desc.pycall(enlist, args, s_ImpossibleValue, op)
- assert row
- return row
-
def get_s_signatures(self, shape):
family = self.getcallfamily()
table = family.calltables.get(shape)
@@ -624,7 +623,7 @@
"specialization" % (self.name,))
return self.getclassdef(None)
- def pycall(self, schedule, args, s_previous_result, op=None):
+ def pycall(self, whence, args, s_previous_result, op=None):
from rpython.annotator.model import SomeInstance, SomeImpossibleValue
if self.specialize:
if self.specialize == 'specialize:ctr_location':
@@ -777,6 +776,8 @@
@staticmethod
def consider_call_site(descs, args, s_result, op):
+ descs[0].getcallfamily()
+ descs[0].mergecallfamilies(*descs[1:])
from rpython.annotator.model import SomeInstance, SomePBC, s_None
if len(descs) == 1:
# call to a single class, look at the result annotation
@@ -890,13 +891,20 @@
def getuniquegraph(self):
return self.funcdesc.getuniquegraph()
- def pycall(self, schedule, args, s_previous_result, op=None):
+ def func_args(self, args):
from rpython.annotator.model import SomeInstance
if self.selfclassdef is None:
raise Exception("calling %r" % (self,))
s_instance = SomeInstance(self.selfclassdef, flags=self.flags)
- args = args.prepend(s_instance)
- return self.funcdesc.pycall(schedule, args, s_previous_result, op)
+ return args.prepend(s_instance)
+
+ def pycall(self, whence, args, s_previous_result, op=None):
+ func_args = self.func_args(args)
+ return self.funcdesc.pycall(whence, func_args, s_previous_result, op)
+
+ def get_graph(self, args, op):
+ func_args = self.func_args(args)
+ return self.funcdesc.get_graph(func_args, op)
def bind_under(self, classdef, name):
self.bookkeeper.warning("rebinding an already bound %r" % (self,))
@@ -913,9 +921,10 @@
def consider_call_site(descs, args, s_result, op):
cnt, keys, star = rawshape(args)
shape = cnt + 1, keys, star # account for the extra 'self'
- row = FunctionDesc.row_to_consider(descs, args, op)
+ row = build_calltable_row(descs, args, op)
family = descs[0].getcallfamily()
family.calltable_add_row(shape, row)
+ descs[0].mergecallfamilies(*descs[1:])
def rowkey(self):
# we are computing call families and call tables that always contain
@@ -1064,19 +1073,28 @@
return '<MethodOfFrozenDesc %r of %r>' % (self.funcdesc,
self.frozendesc)
- def pycall(self, schedule, args, s_previous_result, op=None):
+ def func_args(self, args):
from rpython.annotator.model import SomePBC
s_self = SomePBC([self.frozendesc])
- args = args.prepend(s_self)
- return self.funcdesc.pycall(schedule, args, s_previous_result, op)
+ return args.prepend(s_self)
+
+ def pycall(self, whence, args, s_previous_result, op=None):
+ func_args = self.func_args(args)
+ return self.funcdesc.pycall(whence, func_args, s_previous_result, op)
+
+ def get_graph(self, args, op):
+ func_args = self.func_args(args)
+ return self.funcdesc.get_graph(func_args, op)
+
@staticmethod
def consider_call_site(descs, args, s_result, op):
cnt, keys, star = rawshape(args)
shape = cnt + 1, keys, star # account for the extra 'self'
- row = FunctionDesc.row_to_consider(descs, args, op)
+ row = build_calltable_row(descs, args, op)
family = descs[0].getcallfamily()
family.calltable_add_row(shape, row)
+ descs[0].mergecallfamilies(*descs[1:])
def rowkey(self):
return self.funcdesc
diff --git a/rpython/annotator/test/test_annrpython.py
b/rpython/annotator/test/test_annrpython.py
--- a/rpython/annotator/test/test_annrpython.py
+++ b/rpython/annotator/test/test_annrpython.py
@@ -1097,102 +1097,6 @@
assert acc1 is acc2
assert acc1.attrs.keys() == ['v1']
- def test_simple_pbc_call(self):
- def f1(x,y=0):
- pass
- def f2(x):
- pass
- def f3(x):
- pass
- def g(f):
- f(1)
- def h():
- f1(1)
- f1(1,2)
- g(f2)
- g(f3)
-
- a = self.RPythonAnnotator()
- s = a.build_types(h, [])
-
- fdesc1 = a.bookkeeper.getdesc(f1)
- fdesc2 = a.bookkeeper.getdesc(f2)
- fdesc3 = a.bookkeeper.getdesc(f3)
-
- fam1 = fdesc1.getcallfamily()
- fam2 = fdesc2.getcallfamily()
- fam3 = fdesc3.getcallfamily()
-
- assert fam1 is not fam2
- assert fam1 is not fam3
- assert fam3 is fam2
-
- gf1 = graphof(a, f1)
- gf2 = graphof(a, f2)
- gf3 = graphof(a, f3)
-
- assert fam1.calltables == {(2, (), False): [{fdesc1: gf1}],
- (1, (), False): [{fdesc1: gf1}]}
- assert fam2.calltables == {(1, (), False): [{fdesc2: gf2, fdesc3:
gf3}]}
-
- def test_pbc_call_ins(self):
- class A(object):
- def m(self):
- pass
- class B(A):
- def n(self):
- pass
- class C(A):
- def __init__(self):
- pass
- def m(self):
- pass
- def f(x):
- b = B()
- c = C()
- b.n()
- if x:
- a = b
- else:
- a = c
- a.m()
-
- a = self.RPythonAnnotator()
- s = a.build_types(f, [bool])
-
- clsdef = a.bookkeeper.getuniqueclassdef
- bookkeeper = a.bookkeeper
-
- def getmdesc(bmeth):
- return bookkeeper.immutablevalue(bmeth).any_description()
-
- mdescA_m = getmdesc(A().m)
- mdescC_m = getmdesc(C().m)
- mdescB_n = getmdesc(B().n)
-
- assert mdescA_m.name == 'm' == mdescC_m.name
- assert mdescB_n.name == 'n'
-
- famA_m = mdescA_m.getcallfamily()
- famC_m = mdescC_m.getcallfamily()
- famB_n = mdescB_n.getcallfamily()
-
- assert famA_m is famC_m
- assert famB_n is not famA_m
-
- gfB_n = graphof(a, B.n.im_func)
- gfA_m = graphof(a, A.m.im_func)
- gfC_m = graphof(a, C.m.im_func)
-
- assert famB_n.calltables == {(1, (), False): [{mdescB_n.funcdesc:
gfB_n}] }
- assert famA_m.calltables == {(1, (), False): [{mdescA_m.funcdesc:
gfA_m, mdescC_m.funcdesc: gfC_m }] }
-
- mdescCinit = getmdesc(C().__init__)
- famCinit = mdescCinit.getcallfamily()
- gfCinit = graphof(a, C.__init__.im_func)
-
- assert famCinit.calltables == {(1, (), False): [{mdescCinit.funcdesc:
gfCinit}] }
-
def test_isinstance_unsigned_1(self):
def f(x):
return isinstance(x, r_uint)
@@ -2153,6 +2057,7 @@
s_f = a.bookkeeper.immutablevalue(f)
a.bookkeeper.emulate_pbc_call('f', s_f, [annmodel.SomeInteger(),
annmodel.SomeInteger()])
a.complete()
+ a.simplify()
assert a.binding(graphof(a, f).getreturnvar()).knowntype == int
fdesc = a.bookkeeper.getdesc(f)
@@ -3969,28 +3874,6 @@
e = py.test.raises(Exception, a.build_types, f, [int])
assert "field '_my_lst' was migrated" in str(e.value)
- def test_call_classes_with_noarg_init(self):
- class A:
- foo = 21
- class B(A):
- foo = 22
- class C(A):
- def __init__(self):
- self.foo = 42
- class D(A):
- def __init__(self):
- self.foo = 43
- def f(i):
- if i == 1:
- cls = B
- elif i == 2:
- cls = D
- else:
- cls = C
- return cls().foo
- a = self.RPythonAnnotator()
- py.test.raises(Exception, a.build_types, f, [int])
-
def test_range_variable_step(self):
def g(n):
return range(0, 10, n)
diff --git a/rpython/annotator/test/test_annsimplifyrpython.py
b/rpython/annotator/test/test_annsimplifyrpython.py
--- a/rpython/annotator/test/test_annsimplifyrpython.py
+++ b/rpython/annotator/test/test_annsimplifyrpython.py
@@ -1,5 +1,8 @@
-import rpython.annotator.test.test_annrpython
-parent = rpython.annotator.test.test_annrpython.TestAnnotateTestCase
+import py
+
+
+from rpython.annotator.test.test_annrpython import graphof
+from rpython.annotator.test.test_annrpython import TestAnnotateTestCase as
parent
class TestAnnotateAndSimplifyTestCase(parent):
@@ -12,3 +15,122 @@
parent.RPythonAnnotator.complete(self)
if self.translator is not None:
self.simplify()
+
+ def test_simple_pbc_call(self):
+ def f1(x,y=0):
+ pass
+ def f2(x):
+ pass
+ def f3(x):
+ pass
+ def g(f):
+ f(1)
+ def h():
+ f1(1)
+ f1(1,2)
+ g(f2)
+ g(f3)
+
+ a = self.RPythonAnnotator()
+ s = a.build_types(h, [])
+
+ fdesc1 = a.bookkeeper.getdesc(f1)
+ fdesc2 = a.bookkeeper.getdesc(f2)
+ fdesc3 = a.bookkeeper.getdesc(f3)
+
+ fam1 = fdesc1.getcallfamily()
+ fam2 = fdesc2.getcallfamily()
+ fam3 = fdesc3.getcallfamily()
+
+ assert fam1 is not fam2
+ assert fam1 is not fam3
+ assert fam3 is fam2
+
+ gf1 = graphof(a, f1)
+ gf2 = graphof(a, f2)
+ gf3 = graphof(a, f3)
+
+ assert fam1.calltables == {(2, (), False): [{fdesc1: gf1}],
+ (1, (), False): [{fdesc1: gf1}]}
+ assert fam2.calltables == {(1, (), False): [{fdesc2: gf2, fdesc3:
gf3}]}
+
+ def test_pbc_call_ins(self):
+ class A(object):
+ def m(self):
+ pass
+ class B(A):
+ def n(self):
+ pass
+ class C(A):
+ def __init__(self):
+ pass
+ def m(self):
+ pass
+ def f(x):
+ b = B()
+ c = C()
+ b.n()
+ if x:
+ a = b
+ else:
+ a = c
+ a.m()
+
+ a = self.RPythonAnnotator()
+ s = a.build_types(f, [bool])
+
+ bookkeeper = a.bookkeeper
+
+ def getmdesc(bmeth):
+ return bookkeeper.immutablevalue(bmeth).any_description()
+
+ mdescA_m = getmdesc(A().m)
+ mdescC_m = getmdesc(C().m)
+ mdescB_n = getmdesc(B().n)
+
+ assert mdescA_m.name == 'm' == mdescC_m.name
+ assert mdescB_n.name == 'n'
+
+ famA_m = mdescA_m.getcallfamily()
+ famC_m = mdescC_m.getcallfamily()
+ famB_n = mdescB_n.getcallfamily()
+
+ assert famA_m is famC_m
+ assert famB_n is not famA_m
+
+ gfB_n = graphof(a, B.n.im_func)
+ gfA_m = graphof(a, A.m.im_func)
+ gfC_m = graphof(a, C.m.im_func)
+
+ assert famB_n.calltables == {(1, (), False): [{mdescB_n.funcdesc:
gfB_n}]}
+ assert famA_m.calltables == {(1, (), False): [
+ {mdescA_m.funcdesc: gfA_m, mdescC_m.funcdesc: gfC_m }]}
+
+ mdescCinit = getmdesc(C().__init__)
+ famCinit = mdescCinit.getcallfamily()
+ gfCinit = graphof(a, C.__init__.im_func)
+
+ assert famCinit.calltables == {(1, (), False): [{mdescCinit.funcdesc:
gfCinit}]}
+
+ def test_call_classes_with_noarg_init(self):
+ class A:
+ foo = 21
+ class B(A):
+ foo = 22
+ class C(A):
+ def __init__(self):
+ self.foo = 42
+ class D(A):
+ def __init__(self):
+ self.foo = 43
+ def f(i):
+ if i == 1:
+ cls = B
+ elif i == 2:
+ cls = D
+ else:
+ cls = C
+ return cls().foo
+ a = self.RPythonAnnotator()
+ with py.test.raises(Exception):
+ a.build_types(f, [int])
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,303 +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()
- concretetable, uniquerows = get_concrete_calltable(self.rtyper,
- self.callfamily)
- assert len(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
@@ -1,47 +1,59 @@
import types
-from rpython.annotator import model as annmodel, description
+from rpython.flowspace.model import FunctionGraph, Link, Block, SpaceOperation
+from rpython.annotator import model as annmodel
+from rpython.annotator.description import (
+ 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, cast_pointer)
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):
if 1 < len(s_pbc.descriptions) <
rtyper.getconfig().translation.withsmallfuncsets:
callfamily = s_pbc.any_description().getcallfamily()
- concretetable, uniquerows = get_concrete_calltable(rtyper, callfamily)
- if len(uniquerows) == 1 and (not s_pbc.subset_of or small_cand(rtyper,
s_pbc.subset_of)):
+ llct = get_concrete_calltable(rtyper, callfamily)
+ if (len(llct.uniquerows) == 1 and
+ (not s_pbc.subset_of or small_cand(rtyper, s_pbc.subset_of))):
return True
return False
class __extend__(annmodel.SomePBC):
def rtyper_makerepr(self, rtyper):
- from rpython.rtyper.lltypesystem.rpbc import (
- FunctionsPBCRepr, SmallFunctionSetPBCRepr)
kind = self.getKind()
- if issubclass(kind, description.FunctionDesc):
- sample = self.any_description()
- callfamily = sample.querycallfamily()
- if callfamily and callfamily.total_calltable_size > 0:
- getRepr = FunctionsPBCRepr
- if small_cand(rtyper, self):
- getRepr = SmallFunctionSetPBCRepr
+ if issubclass(kind, FunctionDesc):
+ if len(self.descriptions) == 1 and not self.can_be_None:
+ getRepr = FunctionRepr
else:
- getRepr = getFrozenPBCRepr
- elif issubclass(kind, description.ClassDesc):
+ sample = self.any_description()
+ callfamily = sample.querycallfamily()
+ if callfamily and callfamily.total_calltable_size > 0:
+ getRepr = FunctionsPBCRepr
+ if small_cand(rtyper, self):
+ getRepr = SmallFunctionSetPBCRepr
+ else:
+ getRepr = getFrozenPBCRepr
+ elif issubclass(kind, ClassDesc):
# user classes
getRepr = ClassesPBCRepr
- elif issubclass(kind, description.MethodDesc):
+ elif issubclass(kind, MethodDesc):
getRepr = MethodsPBCRepr
- elif issubclass(kind, description.FrozenDesc):
+ elif issubclass(kind, FrozenDesc):
getRepr = getFrozenPBCRepr
- elif issubclass(kind, description.MethodOfFrozenDesc):
+ elif issubclass(kind, MethodOfFrozenDesc):
getRepr = MethodOfFrozenPBCRepr
else:
raise TyperError("unexpected PBC kind %r" % (kind,))
@@ -55,24 +67,34 @@
t = self.subset_of.rtyper_makekey()
else:
t = ()
- return tuple([self.__class__, self.can_be_None]+lst)+t
+ return tuple([self.__class__, self.can_be_None] + lst) + t
# ____________________________________________________________
class ConcreteCallTableRow(dict):
"""A row in a concrete call table."""
+ @classmethod
+ def from_row(cls, rtyper, row):
+ concreterow = cls()
+ for funcdesc, graph in row.items():
+ llfn = rtyper.getcallable(graph)
+ concreterow[funcdesc] = llfn
+ assert len(concreterow) > 0
+ # 'typeOf(llfn)' should be the same for all graphs
+ concreterow.fntype = typeOf(llfn)
+ return concreterow
-def build_concrete_calltable(rtyper, callfamily):
- """Build a complete call table of a call family
- with concrete low-level function objs.
- """
- concretetable = {} # (shape,index): row, maybe with duplicates
- uniquerows = [] # list of rows, without duplicates
- def lookuprow(row):
- # a 'matching' row is one that has the same llfn, expect
- # that it may have more or less 'holes'
- for existingindex, existingrow in enumerate(uniquerows):
+class LLCallTable(object):
+ """A call table of a call family with low-level functions."""
+ def __init__(self, table, uniquerows):
+ self.table = table # (shape,index): row, maybe with duplicates
+ self.uniquerows = uniquerows # list of rows, without duplicates
+
+ def lookup(self, row):
+ """A 'matching' row is one that has the same llfn, except
+ that it may have more or less 'holes'."""
+ for existingindex, existingrow in enumerate(self.uniquerows):
if row.fntype != existingrow.fntype:
continue # not the same pointer type, cannot match
for funcdesc, llfn in row.items():
@@ -90,47 +112,49 @@
return existingindex, merged
raise LookupError
- def addrow(row):
- # add a row to the table, potentially merging it with an existing row
+ def add(self, row):
+ """Add a row to the table, potentially merging it with an existing row
+ """
try:
- index, merged = lookuprow(row)
+ index, merged = self.lookup(row)
except LookupError:
- uniquerows.append(row) # new row
+ self.uniquerows.append(row) # new row
else:
- if merged == uniquerows[index]:
+ if merged == self.uniquerows[index]:
pass # already exactly in the table
else:
- del uniquerows[index]
- addrow(merged) # add the potentially larger merged row
+ del self.uniquerows[index]
+ self.add(merged) # add the potentially larger merged row
+
+
+def build_concrete_calltable(rtyper, callfamily):
+ """Build a complete call table of a call family
+ with concrete low-level function objs.
+ """
+ concretetable = {}
+ uniquerows = []
+ llct = LLCallTable(concretetable, uniquerows)
concreterows = {}
for shape, rows in callfamily.calltables.items():
for index, row in enumerate(rows):
- concreterow = ConcreteCallTableRow()
- for funcdesc, graph in row.items():
- llfn = rtyper.getcallable(graph)
- concreterow[funcdesc] = llfn
- assert len(concreterow) > 0
- concreterow.fntype = lltype.typeOf(llfn)# 'llfn' from the loop
above
- # (they should all have the same type)
+ concreterow = ConcreteCallTableRow.from_row(rtyper, row)
concreterows[shape, index] = concreterow
-
- for row in concreterows.values():
- addrow(row)
+ llct.add(concreterow)
for (shape, index), row in concreterows.items():
- existingindex, biggerrow = lookuprow(row)
- row = uniquerows[existingindex]
- assert biggerrow == row # otherwise, addrow() is broken
- concretetable[shape, index] = row
+ existingindex, biggerrow = llct.lookup(row)
+ row = llct.uniquerows[existingindex]
+ assert biggerrow == row
+ llct.table[shape, index] = row
- if len(uniquerows) == 1:
- uniquerows[0].attrname = None
+ if len(llct.uniquerows) == 1:
+ llct.uniquerows[0].attrname = None
else:
- for finalindex, row in enumerate(uniquerows):
+ for finalindex, row in enumerate(llct.uniquerows):
row.attrname = 'variant%d' % finalindex
- return concretetable, uniquerows
+ return llct
def get_concrete_calltable(rtyper, callfamily):
"""Get a complete call table of a call family
@@ -140,40 +164,20 @@
try:
cached = rtyper.concrete_calltables[callfamily]
except KeyError:
- concretetable, uniquerows = build_concrete_calltable(rtyper,
callfamily)
- cached = concretetable, uniquerows, callfamily.total_calltable_size
+ llct = build_concrete_calltable(rtyper, callfamily)
+ cached = llct, callfamily.total_calltable_size
rtyper.concrete_calltables[callfamily] = cached
else:
- concretetable, uniquerows, oldsize = cached
+ llct, oldsize = cached
if oldsize != callfamily.total_calltable_size:
raise TyperError("call table was unexpectedly extended")
- return concretetable, uniquerows
+ return llct
-
-class AbstractFunctionsPBCRepr(CanBeNull, Repr):
- """Representation selected for a PBC of function(s)."""
-
+class FunctionReprBase(Repr):
def __init__(self, rtyper, s_pbc):
self.rtyper = rtyper
self.s_pbc = s_pbc
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
- else:
- concretetable, uniquerows = get_concrete_calltable(self.rtyper,
- self.callfamily)
- self.concretetable = concretetable
- self.uniquerows = uniquerows
- if len(uniquerows) == 1:
- row = uniquerows[0]
- self.lowleveltype = row.fntype
- else:
- # several functions, each with several specialized variants.
- # each function becomes a pointer to a Struct containing
- # pointers to its variants.
- self.lowleveltype = self.setup_specfunc()
- self.funccache = {}
def get_s_callable(self):
return self.s_pbc
@@ -185,50 +189,107 @@
funcdesc = self.s_pbc.any_description()
return funcdesc.get_s_signatures(shape)
+ def rtype_simple_call(self, hop):
+ return self.call(hop)
+
+ def rtype_call_args(self, hop):
+ return self.call(hop)
+
+ 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)
+ shape, index = self.callfamily.find_row(bk, descs, args, hop.spaceop)
+ row_of_graphs = self.callfamily.calltables[shape][index]
+ anygraph = row_of_graphs.itervalues().next() # pick any witness
+ vfn = hop.inputarg(self, arg=0)
+ vlist = [self.convert_to_concrete_llfn(vfn, shape, index,
+ hop.llops)]
+ vlist += callparse.callparse(self.rtyper, anygraph, hop)
+ rresult = callparse.getrresult(self.rtyper, anygraph)
+ hop.exception_is_here()
+ if isinstance(vlist[0], Constant):
+ v = hop.genop('direct_call', vlist, resulttype=rresult)
+ else:
+ 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 FunctionsPBCRepr(CanBeNull, FunctionReprBase):
+ """Representation selected for a PBC of functions."""
+
+ def __init__(self, rtyper, s_pbc):
+ FunctionReprBase.__init__(self, rtyper, s_pbc)
+ llct = get_concrete_calltable(self.rtyper, self.callfamily)
+ self.concretetable = llct.table
+ self.uniquerows = llct.uniquerows
+ if len(llct.uniquerows) == 1:
+ row = llct.uniquerows[0]
+ self.lowleveltype = row.fntype
+ else:
+ # several functions, each with several specialized variants.
+ # each function becomes a pointer to a Struct containing
+ # pointers to its variants.
+ 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 convert_desc(self, funcdesc):
# get the whole "column" of the call table corresponding to this desc
try:
return self.funccache[funcdesc]
except KeyError:
pass
- if self.lowleveltype is lltype.Void:
- result = None
+ llfns = {}
+ found_anything = False
+ for row in self.uniquerows:
+ if funcdesc in row:
+ llfn = row[funcdesc]
+ found_anything = True
+ else:
+ # missing entry -- need a 'null' of the type that matches
+ # this row
+ llfn = self.rtyper.type_system.null_callable(row.fntype)
+ llfns[row.attrname] = llfn
+ if len(self.uniquerows) == 1:
+ if found_anything:
+ result = llfn # from the loop above
+ else:
+ # extremely rare case, shown only sometimes by
+ # test_bug_callfamily: don't emit NULL, because that
+ # would be interpreted as equal to None... It should
+ # never be called anyway.
+ result = rffi.cast(self.lowleveltype, ~len(self.funccache))
else:
- llfns = {}
- found_anything = False
- for row in self.uniquerows:
- if funcdesc in row:
- llfn = row[funcdesc]
- found_anything = True
- else:
- # missing entry -- need a 'null' of the type that matches
- # this row
- llfn = self.rtyper.type_system.null_callable(row.fntype)
- llfns[row.attrname] = llfn
- if len(self.uniquerows) == 1:
- if found_anything:
- result = llfn # from the loop above
- else:
- # extremely rare case, shown only sometimes by
- # test_bug_callfamily: don't emit NULL, because that
- # would be interpreted as equal to None... It should
- # never be called anyway.
- result = rffi.cast(self.lowleveltype, ~len(self.funccache))
- else:
- # build a Struct with all the values collected in 'llfns'
- result = self.create_specfunc()
- for attrname, llfn in llfns.items():
- setattr(result, attrname, llfn)
+ # build a Struct with all the values collected in 'llfns'
+ result = self.create_specfunc()
+ for attrname, llfn in llfns.items():
+ setattr(result, attrname, llfn)
self.funccache[funcdesc] = result
return result
def convert_const(self, value):
if isinstance(value, types.MethodType) and value.im_self is None:
- value = value.im_func # unbound method -> bare function
+ 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:
- return None
+ value = value.__get__(42) # hackish, get the function wrapped by
staticmethod
if value is None:
null = self.rtyper.type_system.null_callable(self.lowleveltype)
return null
@@ -241,30 +302,42 @@
'index' and 'shape' tells which of its items we are interested in.
"""
assert v.concretetype == self.lowleveltype
- if self.lowleveltype is lltype.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)
- elif len(self.uniquerows) == 1:
+ if 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)
+
+class FunctionRepr(FunctionReprBase):
+ """Repr for a constant function"""
+
+ lowleveltype = Void
+
+ def convert_desc(self, funcdesc):
+ return None
+
+ def convert_const(self, value):
+ return None
+
+ def convert_to_concrete_llfn(self, v, shape, index, llop):
+ """Convert the variable 'v' to a variable referring to a concrete
+ low-level function. In case the call table contains multiple rows,
+ 'index' and 'shape' tells which of its items we are interested in.
+ """
+ assert v.concretetype == Void
+ 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(typeOf(llfn), llfn)
+
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:
- raise TyperError("cannot pass multiple functions here")
- assert len(self.s_pbc.descriptions) == 1
- # lowleveltype wouldn't be Void otherwise
funcdesc, = self.s_pbc.descriptions
tables = [] # find the simple call in the calltable
for shape, table in self.callfamily.calltables.items():
@@ -280,69 +353,229 @@
if not graphs:
raise TyperError("cannot pass here a function that is not called")
graph = graphs[0]
- if graphs != [graph]*len(graphs):
+ 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
- descs = list(s_pbc.descriptions)
- vfcs = description.FunctionDesc.variant_for_call_site
+ funcdesc, = s_pbc.descriptions
args = simple_args(args_s)
- shape, index = vfcs(bk, self.callfamily, descs, args, op)
- funcdesc, = descs
- row_of_one_graph = self.callfamily.calltables[shape][index]
- graph = row_of_one_graph[funcdesc]
+ with bk.at_position(None):
+ graph = funcdesc.get_graph(args, op)
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)
- def rtype_call_args(self, hop):
- return self.call(hop)
+
+class __extend__(pairtype(FunctionRepr, FunctionRepr)):
+ def convert_from_to((r_fpbc1, r_fpbc2), v, llops):
+ return v
+
+class __extend__(pairtype(FunctionRepr, FunctionsPBCRepr)):
+ def convert_from_to((r_fpbc1, r_fpbc2), v, llops):
+ return inputconst(r_fpbc2, r_fpbc1.s_pbc.const)
+
+class __extend__(pairtype(FunctionsPBCRepr, FunctionRepr)):
+ def convert_from_to((r_fpbc1, r_fpbc2), v, llops):
+ return inputconst(Void, None)
+
+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
+ return NotImplemented
+
+
+class SmallFunctionSetPBCRepr(FunctionReprBase):
+ def __init__(self, rtyper, s_pbc):
+ FunctionReprBase.__init__(self, rtyper, s_pbc)
+ 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 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 dispatcher(self, shape, index, argtypes, resulttype):
+ key = shape, index, tuple(argtypes), resulttype
+ if key in self._dispatch_cache:
+ return self._dispatch_cache[key]
+ graph = self.make_dispatcher(shape, index, argtypes, resulttype)
+ self.rtyper.annotator.translator.graphs.append(graph)
+ ll_ret = getfunctionptr(graph)
+ c_ret = self._dispatch_cache[key] = inputconst(typeOf(ll_ret), ll_ret)
+ return c_ret
+
+ def make_dispatcher(self, shape, index, argtypes, resulttype):
+ 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)
+ return graph
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)
+ shape, index = self.callfamily.find_row(bk, descs, args, hop.spaceop)
row_of_graphs = self.callfamily.calltables[shape][index]
anygraph = row_of_graphs.itervalues().next() # pick any witness
- vfn = hop.inputarg(self, arg=0)
- vlist = [self.convert_to_concrete_llfn(vfn, shape, index,
- hop.llops)]
+ vlist = [hop.inputarg(self, arg=0)]
vlist += callparse.callparse(self.rtyper, anygraph, hop)
rresult = callparse.getrresult(self.rtyper, anygraph)
hop.exception_is_here()
- if isinstance(vlist[0], Constant):
- v = hop.genop('direct_call', vlist, resulttype = rresult)
+ 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:
- vlist.append(hop.inputconst(lltype.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
+ v1, = hop.inputargs(self)
+ return hop.genop('char_ne', [v1, inputconst(Char, '\000')],
+ resulttype=Bool)
+
+
+class __extend__(pairtype(SmallFunctionSetPBCRepr, FunctionRepr)):
+ def convert_from_to((r_set, r_ptr), v, llops):
+ return inputconst(Void, None)
+
+class __extend__(pairtype(SmallFunctionSetPBCRepr, FunctionsPBCRepr)):
+ def convert_from_to((r_set, r_ptr), v, llops):
+ 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(FunctionRepr, SmallFunctionSetPBCRepr)):
+ def convert_from_to((r_ptr, r_set), v, llops):
+ desc, = r_ptr.s_pbc.descriptions
+ return inputconst(Char, r_set.convert_desc(desc))
+
+class __extend__(pairtype(FunctionsPBCRepr, SmallFunctionSetPBCRepr)):
+ def convert_from_to((r_ptr, r_set), v, llops):
+ 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:
- return hop.llops.convertvar(v, rresult, hop.r_result)
+ r = inputconst(Ptr(Array(Char, hints={'nolength': True})), t)
+ r_from._conversion_tables[r_to] = r
+ return r
-class __extend__(pairtype(AbstractFunctionsPBCRepr, AbstractFunctionsPBCRepr)):
- 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:
+
+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
- if r_fpbc1.lowleveltype is lltype.Void:
- return inputconst(r_fpbc2, r_fpbc1.s_pbc.const)
- if r_fpbc2.lowleveltype is lltype.Void:
- return inputconst(lltype.Void, None)
- return NotImplemented
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:
@@ -369,7 +602,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
@@ -394,9 +627,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
@@ -407,7 +649,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:
@@ -416,22 +658,62 @@
self.converted_pbc_cache[frozendesc] = convpbc
return convpbc
- def convert_const(self, pbc):
- if pbc is None:
- return self.null_instance()
- if isinstance(pbc, types.MethodType) and pbc.im_self is None:
- value = pbc.im_func # unbound method -> bare function
- 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 = {}
@@ -448,7 +730,7 @@
def convert_desc(self, frozendesc):
if (self.access_set is not None and
- frozendesc not in self.access_set.descs):
+ frozendesc not in self.access_set.descs):
raise TyperError("not found in PBC access set: %r" % (frozendesc,))
try:
return self.pbc_cache[frozendesc]
@@ -457,7 +739,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]
@@ -474,18 +756,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()
@@ -495,10 +782,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):
@@ -523,7 +810,10 @@
im_selves = []
for desc in s_pbc.descriptions:
- assert desc.funcdesc is self.funcdesc, "You can't mix a set of
methods on a frozen PBC in RPython that are different underlaying functions"
+ if desc.funcdesc is not self.funcdesc:
+ raise TyperError(
+ "You can't mix a set of methods on a frozen PBC in "
+ "RPython that are different underlying functions")
im_selves.append(desc.frozendesc)
self.s_im_self = annmodel.SomePBC(im_selves)
@@ -589,7 +879,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()
@@ -612,7 +902,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)
@@ -620,7 +910,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
@@ -637,12 +927,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)
@@ -671,7 +961,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
@@ -728,10 +1018,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()"
@@ -751,7 +1041,7 @@
return None
def ll_str(self, ptr):
- cls = lltype.cast_pointer(CLASSTYPE, ptr)
+ cls = cast_pointer(CLASSTYPE, ptr)
return cls.name
@@ -766,7 +1056,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)
@@ -776,10 +1066,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):
@@ -856,12 +1146,9 @@
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,
- SmallFunctionSetPBCRepr))
+ assert isinstance(r_func, FunctionReprBase)
# s_func = r_func.s_pbc -- not precise enough, see
# test_precise_method_call_1. Build a more precise one...
funcdescs = [desc.funcdesc for desc in hop.args_s[0].descriptions]
@@ -882,28 +1169,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
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit