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

« back to all changes in this revision

Viewing changes to pypy/rpython/rmodel.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
from pypy.annotation.pairtype import pairtype, extendabletype, pair
 
2
from pypy.annotation import model as annmodel
 
3
from pypy.annotation import description
 
4
from pypy.objspace.flow.model import Constant
 
5
from pypy.rpython.lltypesystem.lltype import \
 
6
     Void, Bool, Float, Signed, Char, UniChar, \
 
7
     typeOf, LowLevelType, Ptr, PyObject, isCompatibleType
 
8
from pypy.rpython.lltypesystem import lltype, llmemory
 
9
from pypy.rpython.ootypesystem import ootype
 
10
from pypy.rpython.error import TyperError, MissingRTypeOperation 
 
11
 
 
12
# initialization states for Repr instances 
 
13
 
 
14
class setupstate: 
 
15
    NOTINITIALIZED = 0 
 
16
    INPROGRESS = 1
 
17
    BROKEN = 2 
 
18
    FINISHED = 3
 
19
    DELAYED = 4
 
20
 
 
21
class Repr:
 
22
    """ An instance of Repr is associated with each instance of SomeXxx.
 
23
    It defines the chosen representation for the SomeXxx.  The Repr subclasses
 
24
    generally follows the SomeXxx subclass hierarchy, but there are numerous
 
25
    exceptions.  For example, the annotator uses SomeIter for any iterator, but
 
26
    we need different representations according to the type of container we are
 
27
    iterating over.
 
28
    """
 
29
    __metaclass__ = extendabletype
 
30
    _initialized = setupstate.NOTINITIALIZED 
 
31
 
 
32
    def __repr__(self):
 
33
        return '<%s %s>' % (self.__class__.__name__, self.lowleveltype)
 
34
 
 
35
    def compact_repr(self):
 
36
        return '%s %s' % (self.__class__.__name__.replace('Repr','R'), self.lowleveltype._short_name())
 
37
 
 
38
    def setup(self): 
 
39
        """ call _setup_repr() and keep track of the initializiation
 
40
            status to e.g. detect recursive _setup_repr invocations.
 
41
            the '_initialized' attr has four states: 
 
42
        """
 
43
        if self._initialized == setupstate.FINISHED: 
 
44
            return 
 
45
        elif self._initialized == setupstate.BROKEN: 
 
46
            raise BrokenReprTyperError(
 
47
                "cannot setup already failed Repr: %r" %(self,))
 
48
        elif self._initialized == setupstate.INPROGRESS: 
 
49
            raise AssertionError(
 
50
                "recursive invocation of Repr setup(): %r" %(self,))
 
51
        elif self._initialized == setupstate.DELAYED:
 
52
            raise AssertionError(
 
53
                "Repr setup() is delayed and cannot be called yet: %r" %(self,))
 
54
        assert self._initialized == setupstate.NOTINITIALIZED 
 
55
        self._initialized = setupstate.INPROGRESS 
 
56
        try: 
 
57
            self._setup_repr() 
 
58
        except TyperError, e: 
 
59
            self._initialized = setupstate.BROKEN 
 
60
            raise 
 
61
        else: 
 
62
            self._initialized = setupstate.FINISHED 
 
63
 
 
64
    def _setup_repr(self):
 
65
        "For recursive data structure, which must be initialized in two steps."
 
66
 
 
67
    def setup_final(self):
 
68
        """Same as setup(), called a bit later, for effects that are only
 
69
        needed after the typer finished (as opposed to needed for other parts
 
70
        of the typer itself)."""
 
71
        if self._initialized == setupstate.BROKEN: 
 
72
            raise BrokenReprTyperError("cannot perform setup_final_touch "
 
73
                             "on failed Repr: %r" %(self,))
 
74
        assert self._initialized == setupstate.FINISHED, (
 
75
                "setup_final() on repr with state %s: %r" %
 
76
                (self._initialized, self))
 
77
        self._setup_repr_final() 
 
78
 
 
79
    def _setup_repr_final(self): 
 
80
        pass
 
81
 
 
82
    def is_setup_delayed(self):
 
83
        return self._initialized == setupstate.DELAYED
 
84
 
 
85
    def set_setup_delayed(self, flag):
 
86
        assert self._initialized in (setupstate.NOTINITIALIZED,
 
87
                                     setupstate.DELAYED)
 
88
        if flag:
 
89
            self._initialized = setupstate.DELAYED
 
90
        else:
 
91
            self._initialized = setupstate.NOTINITIALIZED
 
92
 
 
93
    def set_setup_maybe_delayed(self):
 
94
        if self._initialized == setupstate.NOTINITIALIZED:
 
95
            self._initialized = setupstate.DELAYED
 
96
        return self._initialized == setupstate.DELAYED
 
97
 
 
98
    def __getattr__(self, name):
 
99
        # Assume that when an attribute is missing, it's because setup() needs
 
100
        # to be called
 
101
        if not (name[:2] == '__' == name[-2:]): 
 
102
            if self._initialized == setupstate.NOTINITIALIZED: 
 
103
                self.setup()
 
104
                try:
 
105
                    return self.__dict__[name]
 
106
                except KeyError:
 
107
                    pass
 
108
        raise AttributeError("%s instance has no attribute %s" % (
 
109
            self.__class__.__name__, name))
 
110
 
 
111
    def _freeze_(self):
 
112
        return True
 
113
 
 
114
    def convert_desc_or_const(self, desc_or_const):
 
115
        if isinstance(desc_or_const, description.Desc):
 
116
            return self.convert_desc(desc_or_const)
 
117
        elif isinstance(desc_or_const, Constant):
 
118
            return self.convert_const(desc_or_const.value)
 
119
        else:
 
120
            raise TyperError("convert_desc_or_const expects a Desc"
 
121
                             "or Constant: %r" % desc_or_const)
 
122
                            
 
123
    def convert_const(self, value):
 
124
        "Convert the given constant value to the low-level repr of 'self'."
 
125
        if self.lowleveltype is not Void:
 
126
            try:
 
127
                realtype = typeOf(value)
 
128
            except (AssertionError, AttributeError, TypeError):
 
129
                realtype = '???'
 
130
            if realtype != self.lowleveltype:
 
131
                raise TyperError("convert_const(self = %r, value = %r)" % (
 
132
                    self, value))
 
133
        return value
 
134
 
 
135
    def get_ll_eq_function(self):
 
136
        """Return an eq(x,y) function to use to compare two low-level
 
137
        values of this Repr.
 
138
        This can return None to mean that simply using '==' is fine.
 
139
        """
 
140
        raise TyperError, 'no equality function for %r' % self
 
141
 
 
142
    def get_ll_hash_function(self):
 
143
        """Return a hash(x) function for low-level values of this Repr.
 
144
        """
 
145
        raise TyperError, 'no hashing function for %r' % self
 
146
 
 
147
    def get_ll_fasthash_function(self):
 
148
        """Return a 'fast' hash(x) function for low-level values of this
 
149
        Repr.  The function can assume that 'x' is already stored as a
 
150
        key in a dict.  get_ll_fasthash_function() should return None if
 
151
        the hash should rather be cached in the dict entry.
 
152
        """
 
153
        return None
 
154
 
 
155
    def can_ll_be_null(self, s_value):
 
156
        """Check if the low-level repr can take the value 0/NULL.
 
157
        The annotation s_value is provided as a hint because it may
 
158
        contain more information than the Repr.
 
159
        """
 
160
        return True   # conservative
 
161
 
 
162
    def get_ll_dummyval_obj(self, rtyper, s_value):
 
163
        """A dummy value is a special low-level value, not otherwise
 
164
        used.  It should not be the NULL value even if it is special.
 
165
        This returns either None, or a hashable object that has a
 
166
        (possibly lazy) attribute 'll_dummy_value'.
 
167
        The annotation s_value is provided as a hint because it may
 
168
        contain more information than the Repr.
 
169
        """
 
170
        T = self.lowleveltype
 
171
        if (isinstance(T, lltype.Ptr) and
 
172
            isinstance(T.TO, (lltype.Struct,
 
173
                              lltype.Array,
 
174
                              lltype.ForwardReference)) and
 
175
            T.TO._gckind != 'cpy'):
 
176
            return DummyValueBuilder(rtyper, T.TO)
 
177
        else:
 
178
            return None
 
179
 
 
180
    def rtype_bltn_list(self, hop):
 
181
        raise TyperError, 'no list() support for %r' % self
 
182
 
 
183
    def rtype_unichr(self, hop):
 
184
        raise TyperError, 'no unichr() support for %r' % self
 
185
 
 
186
    # default implementation of some operations
 
187
 
 
188
    def rtype_getattr(self, hop):
 
189
        s_attr = hop.args_s[1]
 
190
        if s_attr.is_constant() and isinstance(s_attr.const, str):
 
191
            attr = s_attr.const
 
192
            s_obj = hop.args_s[0]
 
193
            if s_obj.find_method(attr) is None:
 
194
                raise TyperError("no method %s on %r" % (attr, s_obj))
 
195
            else:
 
196
                # implement methods (of a known name) as just their 'self'
 
197
                return hop.inputarg(self, arg=0)
 
198
        else:
 
199
            raise TyperError("getattr() with a non-constant attribute name")
 
200
 
 
201
    def rtype_str(self, hop):
 
202
        [v_self] = hop.inputargs(self)
 
203
        return hop.gendirectcall(self.ll_str, v_self)
 
204
 
 
205
    def rtype_nonzero(self, hop):
 
206
        return self.rtype_is_true(hop)   # can call a subclass' rtype_is_true()
 
207
 
 
208
    def rtype_is_true(self, hop):
 
209
        try:
 
210
            vlen = self.rtype_len(hop)
 
211
        except MissingRTypeOperation:
 
212
            if not hop.s_result.is_constant():
 
213
                raise TyperError("rtype_is_true(%r) not implemented" % (self,))
 
214
            return hop.inputconst(Bool, hop.s_result.const)
 
215
        else:
 
216
            return hop.genop('int_is_true', [vlen], resulttype=Bool)
 
217
 
 
218
    def rtype_id(self, hop):
 
219
        if not isinstance(self.lowleveltype, Ptr):
 
220
            raise TyperError('id() of an instance of the non-pointer %r' % (
 
221
                self,))
 
222
        vobj, = hop.inputargs(self)
 
223
        # XXX why did this go through weakadr??
 
224
        #v_waddr = hop.genop('cast_ptr_to_weakadr', [vobj],
 
225
        #                    resulttype=llmemory.WeakGcAddress)
 
226
        #return hop.genop('cast_weakadr_to_int', [v_waddr], resulttype=Signed)
 
227
 
 
228
        return hop.genop('cast_ptr_to_int', [vobj], resulttype=Signed)
 
229
 
 
230
    def rtype_hash(self, hop):
 
231
        ll_hash = self.get_ll_hash_function()
 
232
        v, = hop.inputargs(self)
 
233
        return hop.gendirectcall(ll_hash, v)
 
234
 
 
235
    def rtype_iter(self, hop):
 
236
        r_iter = self.make_iterator_repr()
 
237
        return r_iter.newiter(hop)
 
238
 
 
239
    def make_iterator_repr(self, *variant):
 
240
        raise TyperError("%s is not iterable" % (self,))
 
241
 
 
242
    def rtype_hint(self, hop):
 
243
        return hop.inputarg(hop.r_result, arg=0)
 
244
 
 
245
    # hlinvoke helpers
 
246
 
 
247
    def get_r_implfunc(self):
 
248
        raise TyperError("%s has no corresponding implementation function representation" % (self,))
 
249
 
 
250
    def get_s_callable(self):
 
251
        raise TyperError("%s is not callable or cannot reconstruct a pbc annotation for itself" % (self,))
 
252
 
 
253
def ll_hash_void(v):
 
254
    return 0
 
255
 
 
256
 
 
257
class CanBeNull(object):
 
258
    """A mix-in base class for subclasses of Repr that represent None as
 
259
    'null' and true values as non-'null'.
 
260
    """
 
261
    def rtype_is_true(self, hop):
 
262
        if hop.s_result.is_constant():
 
263
            return hop.inputconst(Bool, hop.s_result.const)
 
264
        else:
 
265
            return hop.rtyper.type_system.check_null(self, hop)
 
266
 
 
267
 
 
268
class IteratorRepr(Repr):
 
269
    """Base class of Reprs of any kind of iterator."""
 
270
 
 
271
    def rtype_iter(self, hop):    #   iter(iter(x))  <==>  iter(x)
 
272
        v_iter, = hop.inputargs(self)
 
273
        return v_iter
 
274
 
 
275
    def rtype_method_next(self, hop):
 
276
        return self.rtype_next(hop)
 
277
 
 
278
 
 
279
class __extend__(annmodel.SomeIterator):
 
280
    # NOTE: SomeIterator is for iterators over any container, not just list
 
281
    def rtyper_makerepr(self, rtyper):
 
282
        r_container = rtyper.getrepr(self.s_container)
 
283
        return r_container.make_iterator_repr(*self.variant)
 
284
    def rtyper_makekey_ex(self, rtyper):
 
285
        return self.__class__, rtyper.makekey(self.s_container), self.variant
 
286
 
 
287
class __extend__(annmodel.SomeImpossibleValue):
 
288
    def rtyper_makerepr(self, rtyper):
 
289
        return impossible_repr
 
290
    def rtyper_makekey(self):
 
291
        return self.__class__,
 
292
 
 
293
# ____ generic binary operations _____________________________
 
294
 
 
295
 
 
296
class __extend__(pairtype(Repr, Repr)):
 
297
    
 
298
    def rtype_is_((robj1, robj2), hop):
 
299
        if hop.s_result.is_constant():
 
300
            return inputconst(Bool, hop.s_result.const)
 
301
        return hop.rtyper.type_system.generic_is(robj1, robj2, hop)
 
302
 
 
303
    # default implementation for checked getitems
 
304
    
 
305
    def rtype_getitem_idx_key((r_c1, r_o1), hop):
 
306
        return pair(r_c1, r_o1).rtype_getitem(hop)
 
307
 
 
308
    rtype_getitem_idx = rtype_getitem_idx_key
 
309
    rtype_getitem_key = rtype_getitem_idx_key
 
310
 
 
311
# ____________________________________________________________
 
312
 
 
313
 
 
314
def make_missing_op(rcls, opname):
 
315
    attr = 'rtype_' + opname
 
316
    if not hasattr(rcls, attr):
 
317
        def missing_rtype_operation(self, hop):
 
318
            raise MissingRTypeOperation("unimplemented operation: "
 
319
                                        "'%s' on %r" % (opname, self))
 
320
        setattr(rcls, attr, missing_rtype_operation)
 
321
 
 
322
for opname in annmodel.UNARY_OPERATIONS:
 
323
    make_missing_op(Repr, opname)
 
324
 
 
325
for opname in annmodel.BINARY_OPERATIONS:
 
326
    make_missing_op(pairtype(Repr, Repr), opname)
 
327
 
 
328
# not in BINARY_OPERATIONS
 
329
make_missing_op(pairtype(Repr, Repr), 'contains')
 
330
 
 
331
class __extend__(pairtype(Repr, Repr)):
 
332
    def convert_from_to((r_from, r_to), v, llops):
 
333
        return NotImplemented
 
334
 
 
335
# ____________________________________________________________
 
336
# Primitive Repr classes, in the same hierarchical order as
 
337
# the corresponding SomeObjects
 
338
 
 
339
class FloatRepr(Repr):
 
340
    lowleveltype = Float
 
341
 
 
342
class IntegerRepr(FloatRepr):
 
343
    def __init__(self, lowleveltype, opprefix):
 
344
        self.lowleveltype = lowleveltype
 
345
        self._opprefix = opprefix
 
346
        self.as_int = self
 
347
 
 
348
    def _get_opprefix(self):
 
349
        if self._opprefix is None:
 
350
            raise TyperError("arithmetic not supported on %r" %
 
351
                             self.lowleveltype)
 
352
        return self._opprefix
 
353
 
 
354
    opprefix =property(_get_opprefix)
 
355
    
 
356
class BoolRepr(IntegerRepr):
 
357
    lowleveltype = Bool
 
358
    # NB. no 'opprefix' here.  Use 'as_int' systematically.
 
359
    def __init__(self):
 
360
        from pypy.rpython.rint import signed_repr
 
361
        self.as_int = signed_repr
 
362
 
 
363
class VoidRepr(Repr):
 
364
    lowleveltype = Void
 
365
    def get_ll_eq_function(self): return None
 
366
    def get_ll_hash_function(self): return ll_hash_void
 
367
    get_ll_fasthash_function = get_ll_hash_function
 
368
    def ll_str(self, nothing): raise AssertionError("unreachable code")
 
369
impossible_repr = VoidRepr()
 
370
 
 
371
class SimplePointerRepr(Repr):
 
372
    "Convenience Repr for simple ll pointer types with no operation on them."
 
373
 
 
374
    def __init__(self, lowleveltype):
 
375
        self.lowleveltype = lowleveltype
 
376
 
 
377
    def convert_const(self, value):
 
378
        if value is not None:
 
379
            raise TyperError("%r only supports None as prebuilt constant, "
 
380
                             "got %r" % (self, value))
 
381
        return lltype.nullptr(self.lowleveltype.TO)
 
382
 
 
383
# ____________________________________________________________
 
384
 
 
385
def inputdesc(reqtype, desc):
 
386
    """Return a Constant for the given desc, of the requested type,
 
387
    which can only be a Repr.
 
388
    """
 
389
    assert isinstance(reqtype, Repr)
 
390
    value = reqtype.convert_desc(desc)
 
391
    lltype = reqtype.lowleveltype
 
392
    c = Constant(value)
 
393
    c.concretetype = lltype
 
394
    return c
 
395
 
 
396
def inputconst(reqtype, value):
 
397
    """Return a Constant with the given value, of the requested type,
 
398
    which can be a Repr instance or a low-level type.
 
399
    """
 
400
    if isinstance(reqtype, Repr):
 
401
        value = reqtype.convert_const(value)
 
402
        lltype = reqtype.lowleveltype
 
403
    elif isinstance(reqtype, LowLevelType):
 
404
        lltype = reqtype
 
405
    else:
 
406
        raise TypeError(repr(reqtype))
 
407
    # Void Constants can hold any value;
 
408
    # non-Void Constants must hold a correctly ll-typed value
 
409
    if lltype is not Void:
 
410
        try:
 
411
            realtype = typeOf(value)
 
412
        except (AssertionError, AttributeError):
 
413
            realtype = '???'
 
414
        if not isCompatibleType(realtype, lltype):
 
415
            raise TyperError("inputconst(reqtype = %s, value = %s):\n"
 
416
                             "expected a %r,\n"
 
417
                             "     got a %r" % (reqtype, value,
 
418
                                                lltype, realtype))
 
419
    c = Constant(value)
 
420
    c.concretetype = lltype
 
421
    return c
 
422
 
 
423
class BrokenReprTyperError(TyperError): 
 
424
    """ raised when trying to setup a Repr whose setup 
 
425
        has failed already. 
 
426
    """
 
427
 
 
428
def mangle(prefix, name):
 
429
    """Make a unique identifier from the prefix and the name.  The name
 
430
    is allowed to start with $."""
 
431
    if name.startswith('$'):
 
432
        return '%sinternal_%s' % (prefix, name[1:])
 
433
    else:
 
434
        return '%s_%s' % (prefix, name)
 
435
 
 
436
class HalfConcreteWrapper:
 
437
    # see rtyper.gendirectcall()
 
438
    def __init__(self, callback):
 
439
        self.concretize = callback   # should produce a concrete const
 
440
    def _freeze_(self):
 
441
        return True
 
442
 
 
443
# __________ utilities __________
 
444
PyObjPtr = Ptr(PyObject)
 
445
 
 
446
def getgcflavor(classdef):
 
447
    for parentdef in classdef.getmro():
 
448
        if hasattr(parentdef, '_cpy_exported_type_'):
 
449
            return 'cpy'
 
450
    classdesc = classdef.classdesc
 
451
    alloc_flavor = classdesc.read_attribute('_alloc_flavor_',
 
452
                                            Constant('gc')).value
 
453
    return alloc_flavor
 
454
 
 
455
def externalvsinternal(rtyper, item_repr): # -> external_item_repr, (internal_)item_repr
 
456
    from pypy.rpython import rclass
 
457
    if (isinstance(item_repr, rclass.AbstractInstanceRepr) and
 
458
        getattr(item_repr, 'gcflavor', 'gc') == 'gc'):
 
459
        return item_repr, rclass.getinstancerepr(rtyper, None)
 
460
    else:
 
461
        return item_repr, item_repr
 
462
 
 
463
 
 
464
class DummyValueBuilder(object):
 
465
 
 
466
    def __init__(self, rtyper, TYPE):
 
467
        self.rtyper = rtyper
 
468
        self.TYPE = TYPE
 
469
 
 
470
    def _freeze_(self):
 
471
        return True
 
472
 
 
473
    def __hash__(self):
 
474
        return hash(self.TYPE)
 
475
 
 
476
    def __eq__(self, other):
 
477
        return (isinstance(other, DummyValueBuilder) and
 
478
                self.rtyper is other.rtyper and
 
479
                self.TYPE == other.TYPE)
 
480
 
 
481
    def __ne__(self, other):
 
482
        return not (self == other)
 
483
 
 
484
    def build_ll_dummy_value(self):
 
485
        TYPE = self.TYPE
 
486
        try:
 
487
            return self.rtyper.cache_dummy_values[TYPE]
 
488
        except KeyError:
 
489
            # generate a dummy ptr to an immortal placeholder struct/array
 
490
            if TYPE._is_varsize():
 
491
                p = lltype.malloc(TYPE, 0, immortal=True)
 
492
            else:
 
493
                p = lltype.malloc(TYPE, immortal=True)
 
494
            self.rtyper.cache_dummy_values[TYPE] = p
 
495
            return p
 
496
 
 
497
    ll_dummy_value = property(build_ll_dummy_value)
 
498
 
 
499
 
 
500
# logging/warning
 
501
 
 
502
import py
 
503
from pypy.tool.ansi_print import ansi_log
 
504
 
 
505
log = py.log.Producer("rtyper")
 
506
py.log.setconsumer("rtyper", ansi_log)
 
507
py.log.setconsumer("rtyper translating", None)
 
508
py.log.setconsumer("rtyper debug", None)
 
509
 
 
510
def warning(msg):
 
511
    log.WARNING(msg)
 
512
 
 
513
 
 
514