3
from pypy.annotation.pairtype import pairtype, pair
4
from pypy.annotation import model as annmodel
5
from pypy.annotation import description
6
from pypy.objspace.flow.model import Constant, Variable
7
from pypy.rpython.lltypesystem.lltype import \
8
typeOf, Void, ForwardReference, Struct, Bool, Char, \
9
Ptr, malloc, nullptr, Array, Signed, FuncType
10
from pypy.rpython.rmodel import Repr, TyperError, inputconst, inputdesc, HalfConcreteWrapper
11
from pypy.rpython.rpbc import samesig,\
12
commonbase, allattributenames, adjust_shape, \
13
AbstractClassesPBCRepr, AbstractMethodsPBCRepr, OverriddenFunctionPBCRepr, \
14
AbstractMultipleFrozenPBCRepr, MethodOfFrozenPBCRepr, \
15
AbstractFunctionsPBCRepr, AbstractMultipleUnrelatedFrozenPBCRepr, \
16
SingleFrozenPBCRepr, none_frozen_pbc_repr, get_concrete_calltable
17
from pypy.rpython.lltypesystem import rclass, llmemory
18
from pypy.tool.sourcetools import has_varargs
20
from pypy.rpython import callparse
22
def rtype_is_None(robj1, rnone2, hop, pos=0):
23
if isinstance(robj1.lowleveltype, Ptr):
24
v1 = hop.inputarg(robj1, pos)
25
return hop.genop('ptr_iszero', [v1], resulttype=Bool)
26
elif robj1.lowleveltype == llmemory.Address:
27
v1 = hop.inputarg(robj1, pos)
28
cnull = hop.inputconst(llmemory.Address, robj1.null_instance())
29
return hop.genop('adr_eq', [v1, cnull], resulttype=Bool)
30
elif robj1 == none_frozen_pbc_repr:
31
return hop.inputconst(Bool, True)
32
elif isinstance(robj1, SmallFunctionSetPBCRepr):
33
if robj1.s_pbc.can_be_None:
34
v1 = hop.inputarg(robj1, pos)
35
return hop.genop('char_eq', [v1, inputconst(Char, '\000')],
38
return inputconst(Bool, False)
40
raise TyperError('rtype_is_None of %r' % (robj1))
42
# ____________________________________________________________
44
class MultipleFrozenPBCRepr(AbstractMultipleFrozenPBCRepr):
45
"""Representation selected for multiple non-callable pre-built constants."""
46
def __init__(self, rtyper, access_set):
48
self.access_set = access_set
49
self.pbc_type = ForwardReference()
50
self.lowleveltype = Ptr(self.pbc_type)
53
def _setup_repr(self):
54
llfields = self._setup_repr_fields()
55
kwds = {'hints': {'immutable': True}}
56
self.pbc_type.become(Struct('pbc', *llfields, **kwds))
58
def create_instance(self):
59
return malloc(self.pbc_type, immortal=True)
61
def null_instance(self):
62
return nullptr(self.pbc_type)
64
def getfield(self, vpbc, attr, llops):
65
mangled_name, r_value = self.fieldmap[attr]
66
cmangledname = inputconst(Void, mangled_name)
67
return llops.genop('getfield', [vpbc, cmangledname],
71
class MultipleUnrelatedFrozenPBCRepr(AbstractMultipleUnrelatedFrozenPBCRepr):
72
"""Representation selected for multiple non-callable pre-built constants
73
with no common access set."""
75
lowleveltype = llmemory.Address
76
EMPTY = Struct('pbc', hints={'immutable': True})
78
def convert_pbc(self, pbcptr):
79
return llmemory.fakeaddress(pbcptr)
81
def create_instance(self):
82
return malloc(self.EMPTY, immortal=True)
84
def null_instance(self):
85
return llmemory.Address._defl()
87
class __extend__(pairtype(MultipleUnrelatedFrozenPBCRepr,
88
MultipleUnrelatedFrozenPBCRepr),
89
pairtype(MultipleUnrelatedFrozenPBCRepr,
91
pairtype(SingleFrozenPBCRepr,
92
MultipleUnrelatedFrozenPBCRepr)):
93
def rtype_is_((robj1, robj2), hop):
94
if isinstance(robj1, MultipleUnrelatedFrozenPBCRepr):
98
vlist = hop.inputargs(r, r)
99
return hop.genop('adr_eq', vlist, resulttype=Bool)
101
class __extend__(pairtype(MultipleFrozenPBCRepr,
102
MultipleUnrelatedFrozenPBCRepr)):
103
def convert_from_to((robj1, robj2), v, llops):
104
return llops.genop('cast_ptr_to_adr', [v], resulttype=llmemory.Address)
106
# ____________________________________________________________
108
class FunctionsPBCRepr(AbstractFunctionsPBCRepr):
109
"""Representation selected for a PBC of function(s)."""
111
def setup_specfunc(self):
113
for row in self.uniquerows:
114
fields.append((row.attrname, row.fntype))
115
kwds = {'hints': {'immutable': True}}
116
return Ptr(Struct('specfunc', *fields, **kwds))
118
def create_specfunc(self):
119
return malloc(self.lowleveltype.TO, immortal=True)
121
def get_specfunc_row(self, llop, v, c_rowname, resulttype):
122
return llop.genop('getfield', [v, c_rowname], resulttype=resulttype)
124
class SmallFunctionSetPBCRepr(Repr):
125
def __init__(self, rtyper, s_pbc):
128
self.callfamily = s_pbc.descriptions.iterkeys().next().getcallfamily()
129
concretetable, uniquerows = get_concrete_calltable(self.rtyper,
131
assert len(uniquerows) == 1
132
self.lowleveltype = Char
133
self.pointer_repr = FunctionsPBCRepr(rtyper, s_pbc)
134
self._conversion_tables = {}
135
self._dispatch_cache = {}
137
def _setup_repr(self):
138
if self.s_pbc.subset_of:
139
assert self.s_pbc.can_be_None == self.s_pbc.subset_of.can_be_None
140
r = self.rtyper.getrepr(self.s_pbc.subset_of)
143
self.descriptions = r.descriptions
144
self.c_pointer_table = r.c_pointer_table
146
self.descriptions = list(self.s_pbc.descriptions)
147
if self.s_pbc.can_be_None:
148
self.descriptions.insert(0, None)
149
POINTER_TABLE = Array(self.pointer_repr.lowleveltype)
150
pointer_table = malloc(POINTER_TABLE, len(self.descriptions),
152
for i, desc in enumerate(self.descriptions):
154
pointer_table[i] = self.pointer_repr.convert_desc(desc)
156
pointer_table[i] = self.pointer_repr.convert_const(None)
157
self.c_pointer_table = inputconst(Ptr(POINTER_TABLE), pointer_table)
159
def get_s_callable(self):
162
def get_r_implfunc(self):
165
def get_s_signatures(self, shape):
166
funcdesc = self.s_pbc.descriptions.iterkeys().next()
167
return funcdesc.get_s_signatures(shape)
169
def convert_desc(self, funcdesc):
170
return chr(self.descriptions.index(funcdesc))
172
def convert_const(self, value):
173
if isinstance(value, types.MethodType) and value.im_self is None:
174
value = value.im_func # unbound method -> bare function
177
funcdesc = self.rtyper.annotator.bookkeeper.getdesc(value)
178
return self.convert_desc(funcdesc)
180
## def convert_to_concrete_llfn(self, v, shape, index, llop):
183
def rtype_simple_call(self, hop):
184
return self.call('simple_call', hop)
186
def rtype_call_args(self, hop):
187
return self.call('call_args', hop)
189
def dispatcher(self, shape, index, argtypes, resulttype):
190
key = shape, index, tuple(argtypes), resulttype
191
if key in self._dispatch_cache:
192
return self._dispatch_cache[key]
193
from pypy.translator.unsimplify import varoftype
194
from pypy.objspace.flow.model import FunctionGraph, Link, Block, SpaceOperation
195
inputargs = [varoftype(t) for t in [Char] + argtypes]
196
startblock = Block(inputargs)
197
startblock.exitswitch = inputargs[0]
198
#startblock.operations.append(SpaceOperation('debug_pdb', [], varoftype(Void)))
199
graph = FunctionGraph("dispatcher", startblock, varoftype(resulttype))
200
row_of_graphs = self.callfamily.calltables[shape][index]
202
descs = list(self.s_pbc.descriptions)
203
if self.s_pbc.can_be_None:
204
descs.insert(0, None)
208
args_v = [varoftype(t) for t in argtypes]
210
llfn = self.rtyper.getcallable(row_of_graphs[desc])
211
v_fn = inputconst(typeOf(llfn), llfn)
212
v_result = varoftype(resulttype)
214
SpaceOperation("direct_call", [v_fn] + args_v, v_result))
215
b.closeblock(Link([v_result], graph.returnblock))
216
i = self.descriptions.index(desc)
217
links.append(Link(inputargs[1:], b, chr(i)))
218
links[-1].llexitcase = chr(i)
219
startblock.closeblock(*links)
220
self.rtyper.annotator.translator.graphs.append(graph)
221
ll_ret = self.rtyper.type_system.getcallable(graph)
223
c_ret = self._dispatch_cache[key] = inputconst(typeOf(ll_ret), ll_ret)
226
def call(self, opname, hop):
227
bk = self.rtyper.annotator.bookkeeper
228
args = bk.build_args(opname, hop.args_s[1:])
229
s_pbc = hop.args_s[0] # possibly more precise than self.s_pbc
230
descs = s_pbc.descriptions.keys()
231
shape, index = description.FunctionDesc.variant_for_call_site(bk, self.callfamily, descs, args)
232
row_of_graphs = self.callfamily.calltables[shape][index]
233
anygraph = row_of_graphs.itervalues().next() # pick any witness
234
vlist = [hop.inputarg(self, arg=0)]
235
vlist += callparse.callparse(self.rtyper, anygraph, hop, opname)
236
rresult = callparse.getrresult(self.rtyper, anygraph)
237
hop.exception_is_here()
238
v_dispatcher = self.dispatcher(shape, index, [v.concretetype for v in vlist[1:]], rresult.lowleveltype)
239
v_result = hop.genop('direct_call', [v_dispatcher] + vlist,
241
return hop.llops.convertvar(v_result, rresult, hop.r_result)
243
def rtype_is_true(self, hop):
244
if not self.s_pbc.can_be_None:
245
return inputconst(Bool, True)
247
v1, = hop.inputargs(self)
248
return hop.genop('char_ne', [v1, inputconst(Char, '\000')],
251
## def rtype_simple_call(self, hop):
252
## v_index = hop.inputarg(self, arg=0)
253
## v_ptr = hop.llops.convertvar(v_index, self, self.pointer_repr)
255
## hop2.args_r[0] = self.pointer_repr
256
## hop2.args_v[0] = v_ptr
257
## return hop2.dispatch()
259
## rtype_call_args = rtype_simple_call
261
class __extend__(pairtype(SmallFunctionSetPBCRepr, FunctionsPBCRepr)):
262
def convert_from_to((r_set, r_ptr), v, llops):
263
if r_ptr.lowleveltype is Void:
264
wrapper = HalfConcreteWrapper(r_ptr.get_unique_llfn)
265
return inputconst(Void, wrapper)
267
assert v.concretetype is Char
268
v_int = llops.genop('cast_char_to_int', [v],
270
return llops.genop('getarrayitem', [r_set.c_pointer_table, v_int],
271
resulttype=r_ptr.lowleveltype)
273
class __extend__(pairtype(FunctionsPBCRepr, SmallFunctionSetPBCRepr)):
274
def convert_from_to((r_ptr, r_set), v, llops):
275
assert r_ptr.lowleveltype is Void
276
desc, = r_ptr.s_pbc.descriptions
277
return inputconst(Char, r_set.convert_desc(desc))
279
def conversion_table(r_from, r_to):
280
if r_to in r_from._conversion_tables:
281
return r_from._conversion_tables[r_to]
283
t = malloc(Array(Char), len(r_from.descriptions), immortal=True)
285
for i, d in enumerate(r_from.descriptions):
286
if d in r_to.descriptions:
287
j = r_to.descriptions.index(d)
292
if l == range(len(r_from.descriptions)):
295
r = inputconst(Ptr(Array(Char)), t)
296
r_from._conversion_tables[r_to] = r
299
## myf = open('convlog.txt', 'w')
301
class __extend__(pairtype(SmallFunctionSetPBCRepr, SmallFunctionSetPBCRepr)):
302
def convert_from_to((r_from, r_to), v, llops):
303
c_table = conversion_table(r_from, r_to)
305
assert v.concretetype is Char
306
## from pypy.rpython.lltypesystem.rstr import string_repr
307
## s = repr(llops.rtyper.annotator.annotated.get(llops.originalblock))
308
## if 'LOAD_GLOBAL' in s:
309
## import pdb; pdb.set_trace()
310
## print >> myf, 'static small conv', s
311
## print 'static small conv', s
312
## llops.genop('debug_print',
313
## [Constant(string_repr.convert_const("dynamic small conv" + s),
314
## string_repr.lowleveltype)])
315
v_int = llops.genop('cast_char_to_int', [v],
317
return llops.genop('getarrayitem', [c_table, v_int],
322
class MethodsPBCRepr(AbstractMethodsPBCRepr):
323
"""Representation selected for a PBC of the form {func: classdef...}.
324
It assumes that all the methods come from the same name in a base
327
def rtype_simple_call(self, hop):
328
return self.redispatch_call(hop, call_args=False)
330
def rtype_call_args(self, hop):
331
return self.redispatch_call(hop, call_args=True)
333
def redispatch_call(self, hop, call_args):
334
r_class = self.r_im_self.rclass
335
mangled_name, r_func = r_class.clsfields[self.methodname]
336
assert isinstance(r_func, (FunctionsPBCRepr,
337
OverriddenFunctionPBCRepr,
338
SmallFunctionSetPBCRepr))
339
# s_func = r_func.s_pbc -- not precise enough, see
340
# test_precise_method_call_1. Build a more precise one...
341
funcdescs = [desc.funcdesc for desc in hop.args_s[0].descriptions]
342
s_func = annmodel.SomePBC(funcdescs, subset_of=r_func.s_pbc)
343
v_im_self = hop.inputarg(self, arg=0)
344
v_cls = self.r_im_self.getfield(v_im_self, '__class__', hop.llops)
345
v_func = r_class.getclsfield(v_cls, self.methodname, hop.llops)
347
hop2 = self.add_instance_arg_to_hop(hop, call_args)
348
opname = 'simple_call'
351
hop2.forced_opname = opname
353
hop2.v_s_insertfirstarg(v_func, s_func) # insert 'function'
355
if type(hop2.args_r[0]) is SmallFunctionSetPBCRepr and type(r_func) is FunctionsPBCRepr:
356
hop2.args_r[0] = FunctionsPBCRepr(self.rtyper, s_func)
358
hop2.args_v[0] = hop2.llops.convertvar(hop2.args_v[0], r_func, hop2.args_r[0])
360
# now hop2 looks like simple_call(function, self, args...)
361
return hop2.dispatch()
364
# ____________________________________________________________
367
class ClassesPBCRepr(AbstractClassesPBCRepr):
368
"""Representation selected for a PBC of class(es)."""
370
# no __init__ here, AbstractClassesPBCRepr.__init__ is good enough
372
def _instantiate_runtime_class(self, hop, vtypeptr, r_instance):
373
from pypy.rpython.lltypesystem.rbuiltin import ll_instantiate
374
v_inst1 = hop.gendirectcall(ll_instantiate, vtypeptr)
375
return hop.genop('cast_pointer', [v_inst1], resulttype = r_instance)
379
# ____________________________________________________________
381
##def rtype_call_memo(hop):
382
## memo_table = hop.args_v[0].value
383
## if memo_table.s_result.is_constant():
384
## return hop.inputconst(hop.r_result, memo_table.s_result.const)
385
## fieldname = memo_table.fieldname
386
## assert hop.nb_args == 2, "XXX"
388
## r_pbc = hop.args_r[1]
389
## assert isinstance(r_pbc, (MultipleFrozenPBCRepr, ClassesPBCRepr))
390
## v_table, v_pbc = hop.inputargs(Void, r_pbc)
391
## return r_pbc.getfield(v_pbc, fieldname, hop.llops)