1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
|
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 rclass, 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 (
AbstractClassesPBCRepr, 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
# ____________________________________________________________
class ClassesPBCRepr(AbstractClassesPBCRepr):
"""Representation selected for a PBC of class(es)."""
# no __init__ here, AbstractClassesPBCRepr.__init__ is good enough
def _instantiate_runtime_class(self, hop, vtypeptr, r_instance):
graphs = []
for desc in self.s_pbc.descriptions:
classdef = desc.getclassdef(None)
assert hasattr(classdef, 'my_instantiate_graph')
graphs.append(classdef.my_instantiate_graph)
c_graphs = hop.inputconst(Void, graphs)
#
# "my_instantiate = typeptr.instantiate"
c_name = hop.inputconst(Void, 'instantiate')
v_instantiate = hop.genop('getfield', [vtypeptr, c_name],
resulttype=rclass.OBJECT_VTABLE.instantiate)
# "my_instantiate()"
v_inst = hop.genop('indirect_call', [v_instantiate, c_graphs],
resulttype=rclass.OBJECTPTR)
return hop.genop('cast_pointer', [v_inst], resulttype=r_instance)
def getlowleveltype(self):
return rclass.CLASSTYPE
def get_ll_hash_function(self):
return ll_cls_hash
get_ll_fasthash_function = get_ll_hash_function
def get_ll_eq_function(self):
return None
def ll_cls_hash(cls):
if not cls:
return 0
else:
return cls.hash
|