~ubuntu-branches/ubuntu/karmic/pypy/karmic

« back to all changes in this revision

Viewing changes to pypy/rpython/lltypesystem/rpbc.py

  • Committer: Bazaar Package Importer
  • Author(s): Alexandre Fayolle
  • Date: 2007-04-13 09:33:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070413093309-yoojh4jcoocu2krz
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import types
 
2
import sys
 
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
 
19
 
 
20
from pypy.rpython import callparse
 
21
 
 
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')],
 
36
                             resulttype=Bool)
 
37
        else:
 
38
            return inputconst(Bool, False)
 
39
    else:
 
40
        raise TyperError('rtype_is_None of %r' % (robj1))
 
41
 
 
42
# ____________________________________________________________
 
43
 
 
44
class MultipleFrozenPBCRepr(AbstractMultipleFrozenPBCRepr):
 
45
    """Representation selected for multiple non-callable pre-built constants."""
 
46
    def __init__(self, rtyper, access_set):
 
47
        self.rtyper = rtyper
 
48
        self.access_set = access_set
 
49
        self.pbc_type = ForwardReference()
 
50
        self.lowleveltype = Ptr(self.pbc_type)
 
51
        self.pbc_cache = {}
 
52
 
 
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))
 
57
 
 
58
    def create_instance(self):
 
59
        return malloc(self.pbc_type, immortal=True)
 
60
 
 
61
    def null_instance(self):
 
62
        return nullptr(self.pbc_type)
 
63
 
 
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],
 
68
                           resulttype = r_value)
 
69
 
 
70
 
 
71
class MultipleUnrelatedFrozenPBCRepr(AbstractMultipleUnrelatedFrozenPBCRepr):
 
72
    """Representation selected for multiple non-callable pre-built constants
 
73
    with no common access set."""
 
74
 
 
75
    lowleveltype = llmemory.Address
 
76
    EMPTY = Struct('pbc', hints={'immutable': True})
 
77
 
 
78
    def convert_pbc(self, pbcptr):
 
79
        return llmemory.fakeaddress(pbcptr)
 
80
 
 
81
    def create_instance(self):
 
82
        return malloc(self.EMPTY, immortal=True)
 
83
 
 
84
    def null_instance(self):
 
85
        return llmemory.Address._defl()
 
86
 
 
87
class __extend__(pairtype(MultipleUnrelatedFrozenPBCRepr,
 
88
                          MultipleUnrelatedFrozenPBCRepr),
 
89
                 pairtype(MultipleUnrelatedFrozenPBCRepr,
 
90
                          SingleFrozenPBCRepr),
 
91
                 pairtype(SingleFrozenPBCRepr,
 
92
                          MultipleUnrelatedFrozenPBCRepr)):
 
93
    def rtype_is_((robj1, robj2), hop):
 
94
        if isinstance(robj1, MultipleUnrelatedFrozenPBCRepr):
 
95
            r = robj1
 
96
        else:
 
97
            r = robj2
 
98
        vlist = hop.inputargs(r, r)
 
99
        return hop.genop('adr_eq', vlist, resulttype=Bool)
 
100
 
 
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)
 
105
 
 
106
# ____________________________________________________________
 
107
 
 
108
class FunctionsPBCRepr(AbstractFunctionsPBCRepr):
 
109
    """Representation selected for a PBC of function(s)."""
 
110
 
 
111
    def setup_specfunc(self):
 
112
        fields = []
 
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))
 
117
        
 
118
    def create_specfunc(self):
 
119
        return malloc(self.lowleveltype.TO, immortal=True)
 
120
 
 
121
    def get_specfunc_row(self, llop, v, c_rowname, resulttype):
 
122
        return llop.genop('getfield', [v, c_rowname], resulttype=resulttype)
 
123
 
 
124
class SmallFunctionSetPBCRepr(Repr):
 
125
    def __init__(self, rtyper, s_pbc):
 
126
        self.rtyper = rtyper
 
127
        self.s_pbc = s_pbc
 
128
        self.callfamily = s_pbc.descriptions.iterkeys().next().getcallfamily()
 
129
        concretetable, uniquerows = get_concrete_calltable(self.rtyper,
 
130
                                                           self.callfamily)
 
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 = {}
 
136
 
 
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)
 
141
            if r is not self:
 
142
                r.setup()
 
143
                self.descriptions = r.descriptions
 
144
                self.c_pointer_table = r.c_pointer_table
 
145
                return
 
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),
 
151
                               immortal=True)
 
152
        for i, desc in enumerate(self.descriptions):
 
153
            if desc is not None:
 
154
                pointer_table[i] = self.pointer_repr.convert_desc(desc)
 
155
            else:
 
156
                pointer_table[i] = self.pointer_repr.convert_const(None)
 
157
        self.c_pointer_table = inputconst(Ptr(POINTER_TABLE), pointer_table)
 
158
 
 
159
    def get_s_callable(self):
 
160
        return self.s_pbc
 
161
 
 
162
    def get_r_implfunc(self):
 
163
        return self, 0
 
164
 
 
165
    def get_s_signatures(self, shape):
 
166
        funcdesc = self.s_pbc.descriptions.iterkeys().next()
 
167
        return funcdesc.get_s_signatures(shape)
 
168
 
 
169
    def convert_desc(self, funcdesc):
 
170
        return chr(self.descriptions.index(funcdesc))
 
171
 
 
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
 
175
        if value is None:
 
176
            return chr(0)
 
177
        funcdesc = self.rtyper.annotator.bookkeeper.getdesc(value)
 
178
        return self.convert_desc(funcdesc)
 
179
 
 
180
##     def convert_to_concrete_llfn(self, v, shape, index, llop):
 
181
##         return v
 
182
 
 
183
    def rtype_simple_call(self, hop):
 
184
        return self.call('simple_call', hop)
 
185
 
 
186
    def rtype_call_args(self, hop):
 
187
        return self.call('call_args', hop)
 
188
 
 
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]
 
201
        links = []
 
202
        descs = list(self.s_pbc.descriptions)
 
203
        if self.s_pbc.can_be_None:
 
204
            descs.insert(0, None)
 
205
        for desc in descs:
 
206
            if desc is None:
 
207
                continue
 
208
            args_v = [varoftype(t) for t in argtypes]
 
209
            b = Block(args_v)
 
210
            llfn = self.rtyper.getcallable(row_of_graphs[desc])
 
211
            v_fn = inputconst(typeOf(llfn), llfn)
 
212
            v_result = varoftype(resulttype)
 
213
            b.operations.append(
 
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)
 
222
        #FTYPE = FuncType
 
223
        c_ret = self._dispatch_cache[key] = inputconst(typeOf(ll_ret), ll_ret)
 
224
        return c_ret
 
225
 
 
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,
 
240
                             resulttype=rresult)
 
241
        return hop.llops.convertvar(v_result, rresult, hop.r_result)
 
242
 
 
243
    def rtype_is_true(self, hop):
 
244
        if not self.s_pbc.can_be_None:
 
245
            return inputconst(Bool, True)
 
246
        else:
 
247
            v1, = hop.inputargs(self)
 
248
            return hop.genop('char_ne', [v1, inputconst(Char, '\000')],
 
249
                         resulttype=Bool)
 
250
 
 
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)
 
254
##         hop2 = hop.copy()
 
255
##         hop2.args_r[0] = self.pointer_repr
 
256
##         hop2.args_v[0] = v_ptr
 
257
##         return hop2.dispatch()
 
258
 
 
259
##     rtype_call_args = rtype_simple_call
 
260
 
 
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)
 
266
        else:
 
267
            assert v.concretetype is Char
 
268
            v_int = llops.genop('cast_char_to_int', [v],
 
269
                                resulttype=Signed)
 
270
            return llops.genop('getarrayitem', [r_set.c_pointer_table, v_int],
 
271
                               resulttype=r_ptr.lowleveltype)
 
272
 
 
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))
 
278
 
 
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]
 
282
    else:
 
283
        t = malloc(Array(Char), len(r_from.descriptions), immortal=True)
 
284
        l = []
 
285
        for i, d in enumerate(r_from.descriptions):
 
286
            if d in r_to.descriptions:
 
287
                j = r_to.descriptions.index(d)
 
288
                l.append(j)
 
289
                t[i] = chr(j)
 
290
            else:
 
291
                l.append(None)
 
292
        if l == range(len(r_from.descriptions)):
 
293
            r = None
 
294
        else:
 
295
            r = inputconst(Ptr(Array(Char)), t)
 
296
        r_from._conversion_tables[r_to] = r
 
297
        return r
 
298
 
 
299
## myf = open('convlog.txt', 'w')
 
300
 
 
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)
 
304
        if c_table:
 
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],
 
316
                                resulttype=Signed)
 
317
            return llops.genop('getarrayitem', [c_table, v_int],
 
318
                               resulttype=Char)
 
319
        else:
 
320
            return v
 
321
 
 
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
 
325
    classdef."""
 
326
 
 
327
    def rtype_simple_call(self, hop):
 
328
        return self.redispatch_call(hop, call_args=False)
 
329
 
 
330
    def rtype_call_args(self, hop):
 
331
        return self.redispatch_call(hop, call_args=True)
 
332
 
 
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)
 
346
 
 
347
        hop2 = self.add_instance_arg_to_hop(hop, call_args)
 
348
        opname = 'simple_call'
 
349
        if call_args:
 
350
            opname = 'call_args'
 
351
        hop2.forced_opname = opname
 
352
 
 
353
        hop2.v_s_insertfirstarg(v_func, s_func)   # insert 'function'
 
354
 
 
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)
 
357
        else:
 
358
            hop2.args_v[0] = hop2.llops.convertvar(hop2.args_v[0], r_func, hop2.args_r[0])
 
359
 
 
360
        # now hop2 looks like simple_call(function, self, args...)
 
361
        return hop2.dispatch()
 
362
 
 
363
 
 
364
# ____________________________________________________________
 
365
 
 
366
 
 
367
class ClassesPBCRepr(AbstractClassesPBCRepr):
 
368
    """Representation selected for a PBC of class(es)."""
 
369
 
 
370
    # no __init__ here, AbstractClassesPBCRepr.__init__ is good enough
 
371
 
 
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)
 
376
 
 
377
 
 
378
 
 
379
# ____________________________________________________________
 
380
 
 
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"  
 
387
 
 
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)