/rpython/rtyper/lltypesystem/lltype.py
Python | 2527 lines | 2396 code | 97 blank | 34 comment | 109 complexity | 3f9008f894992a905e51e46070eaba89 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
Large files files are truncated, but you can click here to view the full file
- import weakref
- from types import MethodType, NoneType
- from rpython.annotator.bookkeeper import analyzer_for, immutablevalue
- from rpython.annotator.model import (
- AnnotatorError, SomeBool, SomeInteger, SomeObject)
- from rpython.rlib.objectmodel import Symbolic
- from rpython.rlib.rarithmetic import (
- base_int, intmask, is_emulated_long, is_valid_int, longlonglongmask,
- longlongmask, maxint, normalizedinttype, r_int, r_longfloat, r_longlong,
- r_longlonglong, r_singlefloat, r_uint, r_ulonglong)
- from rpython.rtyper.extregistry import ExtRegistryEntry
- from rpython.tool import leakfinder
- from rpython.tool.identity_dict import identity_dict
- class State(object):
- pass
- TLS = State()
- class WeakValueDictionary(weakref.WeakValueDictionary):
- """A subclass of weakref.WeakValueDictionary
- which resets the 'nested_hash_level' when keys are being deleted.
- """
- def __init__(self, *args, **kwargs):
- weakref.WeakValueDictionary.__init__(self, *args, **kwargs)
- remove_base = self._remove
- def remove(*args):
- if safe_equal is None:
- # The interpreter is shutting down, and the comparison
- # function is already gone.
- return
- if TLS is None: # Happens when the interpreter is shutting down
- return remove_base(*args)
- nested_hash_level = TLS.nested_hash_level
- try:
- # The 'remove' function is called when an object dies. This
- # can happen anywhere when they are reference cycles,
- # especially when we are already computing another __hash__
- # value. It's not really a recursion in this case, so we
- # reset the counter; otherwise the hash value may be be
- # incorrect and the key won't be deleted.
- TLS.nested_hash_level = 0
- remove_base(*args)
- finally:
- TLS.nested_hash_level = nested_hash_level
- self._remove = remove
- class _uninitialized(object):
- def __init__(self, TYPE):
- #self._TYPE = TYPE
- self.TYPE = TYPE
- def __repr__(self):
- return '<Uninitialized %r>'%(self.TYPE,)
- def saferecursive(func, defl, TLS=TLS):
- def safe(*args):
- try:
- seeing = TLS.seeing
- except AttributeError:
- seeing = TLS.seeing = {}
- seeingkey = tuple([func] + [id(arg) for arg in args])
- if seeingkey in seeing:
- return defl
- seeing[seeingkey] = True
- try:
- return func(*args)
- finally:
- del seeing[seeingkey]
- return safe
- #safe_equal = saferecursive(operator.eq, True)
- def safe_equal(x, y, TLS=TLS):
- # a specialized version for performance
- try:
- seeing = TLS.seeing_eq
- except AttributeError:
- seeing = TLS.seeing_eq = {}
- seeingkey = (id(x), id(y))
- if seeingkey in seeing:
- return True
- seeing[seeingkey] = True
- try:
- return x == y
- finally:
- del seeing[seeingkey]
- class frozendict(dict):
- def __hash__(self):
- items = self.items()
- items.sort()
- return hash(tuple(items))
- class LowLevelType(object):
- # the following line prevents '__cached_hash' to be in the __dict__ of
- # the instance, which is needed for __eq__() and __hash__() to work.
- __slots__ = ['__dict__', '__cached_hash']
- def __eq__(self, other):
- if isinstance(other, Typedef):
- return other.__eq__(self)
- return self.__class__ is other.__class__ and (
- self is other or safe_equal(self.__dict__, other.__dict__))
- def __ne__(self, other):
- return not (self == other)
- _is_compatible = __eq__
- def __setattr__(self, attr, nvalue):
- try:
- LowLevelType.__cached_hash.__get__(self)
- except AttributeError:
- pass
- else:
- try:
- reprself = repr(self)
- except:
- try:
- reprself = str(self)
- except:
- reprself = object.__repr__(self)
- raise AssertionError("%s: changing the field %r but we already "
- "computed the hash" % (reprself, attr))
- object.__setattr__(self, attr, nvalue)
- def _enforce(self, value):
- if typeOf(value) != self:
- raise TypeError
- return value
- def __hash__(self, TLS=TLS):
- # cannot use saferecursive() -- see test_lltype.test_hash().
- # NB. the __cached_hash should neither be used nor updated
- # if we enter with hash_level > 0, because the computed
- # __hash__ can be different in this situation.
- hash_level = 0
- try:
- hash_level = TLS.nested_hash_level
- if hash_level == 0:
- return self.__cached_hash
- except AttributeError:
- pass
- if hash_level >= 3:
- return 0
- items = self.__dict__.items()
- items.sort()
- TLS.nested_hash_level = hash_level + 1
- try:
- result = hash((self.__class__,) + tuple(items))
- finally:
- TLS.nested_hash_level = hash_level
- if hash_level == 0:
- self.__cached_hash = result
- return result
- # due to this dynamic hash value, we should forbid
- # pickling, until we have an algorithm for that.
- # but we just provide a tag for external help.
- __hash_is_not_constant__ = True
- def __repr__(self):
- return '<%s>' % (self,)
- def __str__(self):
- return self.__class__.__name__
- def _short_name(self):
- return str(self)
- def _defl(self, parent=None, parentindex=None):
- raise NotImplementedError
- def _allocate(self, initialization, parent=None, parentindex=None):
- assert initialization in ('raw', 'malloc', 'example')
- raise NotImplementedError
- def _freeze_(self):
- return True
- def _note_inlined_into(self, parent, first, last):
- """Called when this type is being used inline in a container."""
- def _is_atomic(self):
- return False
- def _is_varsize(self):
- return False
- def _contains_value(self, value):
- if self is Void:
- return True
- return isCompatibleType(typeOf(value), self)
- NFOUND = object()
- class ContainerType(LowLevelType):
- _adtmeths = {}
- def _note_inlined_into(self, parent, first, last):
- raise TypeError("%r cannot be inlined in %r" % (
- self.__class__.__name__, parent.__class__.__name__))
- def _install_extras(self, adtmeths={}, hints={}):
- self._adtmeths = frozendict(adtmeths)
- self._hints = frozendict(hints)
- def __getattr__(self, name):
- adtmeth = self._adtmeths.get(name, NFOUND)
- if adtmeth is not NFOUND:
- if getattr(adtmeth, '_type_method', False):
- return adtmeth.__get__(self)
- else:
- return adtmeth
- self._nofield(name)
- def _nofield(self, name):
- raise AttributeError("no field %r" % name)
- def _container_example(self):
- raise NotImplementedError
- class Typedef(LowLevelType):
- """A typedef is just another name for an existing type"""
- def __init__(self, OF, c_name):
- """
- @param OF: the equivalent rffi type
- @param c_name: the name we want in C code
- """
- assert isinstance(OF, LowLevelType)
- # Look through typedefs, so other places don't have to
- if isinstance(OF, Typedef):
- OF = OF.OF # haha
- self.OF = OF
- self.c_name = c_name
- def __repr__(self):
- return '<Typedef "%s" of %r>' % (self.c_name, self.OF)
- def __eq__(self, other):
- return other == self.OF
- def __getattr__(self, name):
- return self.OF.get(name)
- def _defl(self, parent=None, parentindex=None):
- return self.OF._defl()
- def _allocate(self, initialization, parent=None, parentindex=None):
- return self.OF._allocate(initialization, parent, parentindex)
- class Struct(ContainerType):
- _gckind = 'raw'
- def __init__(self, name, *fields, **kwds):
- self._name = self.__name__ = name
- flds = {}
- names = []
- self._arrayfld = None
- for name, typ in fields:
- if name.startswith('_'):
- raise NameError("%s: field name %r should not start with "
- "an underscore" % (self._name, name,))
- names.append(name)
- if name in flds:
- raise TypeError("%s: repeated field name" % self._name)
- flds[name] = typ
- if isinstance(typ, ContainerType) and typ._gckind != 'raw':
- if name == fields[0][0] and typ._gckind == self._gckind:
- pass # can inline a XxContainer as 1st field of XxStruct
- else:
- raise TypeError("%s: cannot inline %s container %r" % (
- self._name, typ._gckind, typ))
- # look if we have an inlined variable-sized array as the last field
- if fields:
- first = True
- for name, typ in fields[:-1]:
- typ._note_inlined_into(self, first=first, last=False)
- first = False
- name, typ = fields[-1]
- typ._note_inlined_into(self, first=first, last=True)
- if typ._is_varsize():
- self._arrayfld = name
- self._flds = frozendict(flds)
- self._names = tuple(names)
- self._install_extras(**kwds)
- def _first_struct(self):
- if self._names:
- first = self._names[0]
- FIRSTTYPE = self._flds[first]
- if (isinstance(FIRSTTYPE, Struct) and
- self._gckind == FIRSTTYPE._gckind):
- return first, FIRSTTYPE
- return None, None
- def _note_inlined_into(self, parent, first, last):
- if self._arrayfld is not None:
- raise TypeError("cannot inline a var-sized struct "
- "inside another container")
- if self._gckind == 'gc':
- if not first or not isinstance(parent, GcStruct):
- raise TypeError("a GcStruct can only be inlined as the first "
- "field of another GcStruct")
- def _is_atomic(self):
- for typ in self._flds.values():
- if not typ._is_atomic():
- return False
- return True
- def _is_varsize(self):
- return self._arrayfld is not None
- def __getattr__(self, name):
- try:
- return self._flds[name]
- except KeyError:
- return ContainerType.__getattr__(self, name)
- def _nofield(self, name):
- raise AttributeError('struct %s has no field %r' % (self._name,
- name))
- def _names_without_voids(self):
- return [name for name in self._names if self._flds[name] is not Void]
- def _str_fields_without_voids(self):
- return ', '.join(['%s: %s' % (name, self._flds[name])
- for name in self._names_without_voids(False)])
- _str_fields_without_voids = saferecursive(_str_fields_without_voids, '...')
- def _str_without_voids(self):
- return "%s %s { %s }" % (self.__class__.__name__,
- self._name, self._str_fields_without_voids())
- def _str_fields(self):
- return ', '.join(['%s: %s' % (name, self._flds[name])
- for name in self._names])
- _str_fields = saferecursive(_str_fields, '...')
- def __str__(self):
- # -- long version --
- #return "%s %s { %s }" % (self.__class__.__name__,
- # self._name, self._str_fields())
- # -- short version --
- return "%s %s { %s }" % (self.__class__.__name__, self._name,
- ', '.join(self._names))
- def _short_name(self):
- return "%s %s" % (self.__class__.__name__, self._name)
- def _allocate(self, initialization, parent=None, parentindex=None):
- return _struct(self, initialization=initialization,
- parent=parent, parentindex=parentindex)
- def _container_example(self):
- if self._arrayfld is None:
- n = None
- else:
- n = 1
- return _struct(self, n, initialization='example')
- def _immutable_field(self, field):
- if self._hints.get('immutable'):
- return True
- if 'immutable_fields' in self._hints:
- try:
- return self._hints['immutable_fields'].fields[field]
- except KeyError:
- pass
- return False
- class RttiStruct(Struct):
- _runtime_type_info = None
- def _install_extras(self, rtti=False, **kwds):
- if rtti:
- self._runtime_type_info = opaqueptr(RuntimeTypeInfo,
- name=self._name,
- about=self)._obj
- Struct._install_extras(self, **kwds)
- def _attach_runtime_type_info_funcptr(self, funcptr, destrptr):
- if self._runtime_type_info is None:
- raise TypeError("attachRuntimeTypeInfo: %r must have been built "
- "with the rtti=True argument" % (self,))
- if funcptr is not None:
- T = typeOf(funcptr)
- if (not isinstance(T, Ptr) or
- not isinstance(T.TO, FuncType) or
- len(T.TO.ARGS) != 1 or
- T.TO.RESULT != Ptr(RuntimeTypeInfo) or
- castable(T.TO.ARGS[0], Ptr(self)) < 0):
- raise TypeError("expected a runtime type info function "
- "implementation, got: %s" % funcptr)
- self._runtime_type_info.query_funcptr = funcptr
- if destrptr is not None:
- T = typeOf(destrptr)
- if (not isinstance(T, Ptr) or
- not isinstance(T.TO, FuncType) or
- len(T.TO.ARGS) != 1 or
- T.TO.RESULT != Void or
- castable(T.TO.ARGS[0], Ptr(self)) < 0):
- raise TypeError("expected a destructor function "
- "implementation, got: %s" % destrptr)
- self._runtime_type_info.destructor_funcptr = destrptr
- class GcStruct(RttiStruct):
- _gckind = 'gc'
- STRUCT_BY_FLAVOR = {'raw': Struct,
- 'gc': GcStruct}
- class Array(ContainerType):
- _gckind = 'raw'
- __name__ = 'array'
- _anonym_struct = False
- def __init__(self, *fields, **kwds):
- if len(fields) == 1 and isinstance(fields[0], LowLevelType):
- self.OF = fields[0]
- else:
- self.OF = Struct("<arrayitem>", *fields)
- self._anonym_struct = True
- if isinstance(self.OF, ContainerType) and self.OF._gckind != 'raw':
- raise TypeError("cannot have a %s container as array item type"
- % (self.OF._gckind,))
- self.OF._note_inlined_into(self, first=False, last=False)
- self._install_extras(**kwds)
- def _note_inlined_into(self, parent, first, last):
- if not last or not isinstance(parent, Struct):
- raise TypeError("cannot inline an array in another container"
- " unless as the last field of a structure")
- if self._gckind == 'gc':
- raise TypeError("cannot inline a GC array inside a structure")
- if parent._gckind == 'gc' and self._hints.get('nolength', False):
- raise TypeError("cannot inline a no-length array inside a GcStruct")
- def _is_atomic(self):
- return self.OF._is_atomic()
- def _is_varsize(self):
- return True
- def _str_fields(self):
- if isinstance(self.OF, Struct):
- of = self.OF
- if self._anonym_struct:
- return "{ %s }" % of._str_fields()
- else:
- return "%s { %s }" % (of._name, of._str_fields())
- elif self._hints.get('render_as_void'):
- return 'void'
- else:
- return str(self.OF)
- _str_fields = saferecursive(_str_fields, '...')
- def __str__(self):
- return "%s of %s " % (self.__class__.__name__,
- self._str_fields(),)
- def _short_name(self):
- return "%s %s" % (self.__class__.__name__,
- self.OF._short_name(),)
- _short_name = saferecursive(_short_name, '...')
- def _container_example(self):
- return _array(self, 1, initialization='example')
- def _immutable_field(self, index=None):
- return self._hints.get('immutable', False)
- class GcArray(Array):
- _gckind = 'gc'
- class FixedSizeArray(Struct):
- # behaves more or less like a Struct with fields item0, item1, ...
- # but also supports __getitem__(), __setitem__(), __len__().
- _cache = WeakValueDictionary() # cache the length-1 FixedSizeArrays
- def __new__(cls, OF, length, **kwds):
- if length == 1 and not kwds:
- try:
- obj = FixedSizeArray._cache[OF]
- except KeyError:
- obj = FixedSizeArray._cache[OF] = Struct.__new__(cls)
- except TypeError:
- obj = Struct.__new__(cls)
- else:
- obj = Struct.__new__(cls)
- return obj
- def __init__(self, OF, length, **kwds):
- if '_name' in self.__dict__:
- assert self.OF == OF
- assert self.length == length
- return
- fields = [('item%d' % i, OF) for i in range(length)]
- super(FixedSizeArray, self).__init__('array%d' % length, *fields,
- **kwds)
- self.OF = OF
- self.length = length
- if isinstance(self.OF, ContainerType) and self.OF._gckind != 'raw':
- raise TypeError("cannot have a %s container as array item type"
- % (self.OF._gckind,))
- self.OF._note_inlined_into(self, first=False, last=False)
- def _str_fields(self):
- return str(self.OF)
- _str_fields = saferecursive(_str_fields, '...')
- def __str__(self):
- return "%s of %d %s " % (self.__class__.__name__,
- self.length,
- self._str_fields(),)
- def _short_name(self):
- return "%s %d %s" % (self.__class__.__name__,
- self.length,
- self.OF._short_name(),)
- _short_name = saferecursive(_short_name, '...')
- def _first_struct(self):
- # don't consider item0 as an inlined first substructure
- return None, None
- class FuncType(ContainerType):
- _gckind = 'raw'
- __name__ = 'func'
- def __init__(self, args, result, abi='FFI_DEFAULT_ABI'):
- for arg in args:
- assert isinstance(arg, LowLevelType)
- # There are external C functions eating raw structures, not
- # pointers, don't check args not being container types
- self.ARGS = tuple(args)
- assert isinstance(result, LowLevelType)
- if isinstance(result, ContainerType):
- raise TypeError("function result can only be primitive or pointer")
- self.RESULT = result
- self.ABI = abi
- def __str__(self):
- args = ', '.join(map(str, self.ARGS))
- return "Func ( %s ) -> %s" % (args, self.RESULT)
- __str__ = saferecursive(__str__, '...')
- def _short_name(self):
- args = ', '.join([ARG._short_name() for ARG in self.ARGS])
- return "Func(%s)->%s" % (args, self.RESULT._short_name())
- _short_name = saferecursive(_short_name, '...')
- def _container_example(self):
- def ex(*args):
- return self.RESULT._defl()
- return _func(self, _callable=ex)
- def _trueargs(self):
- return [arg for arg in self.ARGS if arg is not Void]
- class OpaqueType(ContainerType):
- _gckind = 'raw'
- def __init__(self, tag, hints={}):
- """If hints['render_structure'] is set, the type is internal and
- not considered to come from somewhere else (it should be
- rendered as a structure)
- """
- self.tag = tag
- self.__name__ = tag
- self.hints = frozendict(hints)
- def __str__(self):
- return "%s (opaque)" % self.tag
- def _note_inlined_into(self, parent, first, last):
- # OpaqueType can be inlined, but not GcOpaqueType
- if self._gckind == 'gc':
- raise TypeError("%r cannot be inlined in %r" % (
- self.__class__.__name__, parent.__class__.__name__))
- def _container_example(self):
- return _opaque(self)
- def _defl(self, parent=None, parentindex=None):
- return _opaque(self, parent=parent, parentindex=parentindex)
- def _allocate(self, initialization, parent=None, parentindex=None):
- return self._defl(parent=parent, parentindex=parentindex)
- RuntimeTypeInfo = OpaqueType("RuntimeTypeInfo")
- class GcOpaqueType(OpaqueType):
- _gckind = 'gc'
- def __str__(self):
- return "%s (gcopaque)" % self.tag
- class ForwardReference(ContainerType):
- _gckind = 'raw'
- def become(self, realcontainertype):
- if not isinstance(realcontainertype, ContainerType):
- raise TypeError("ForwardReference can only be to a container, "
- "not %r" % (realcontainertype,))
- if realcontainertype._gckind != self._gckind:
- raise TypeError("become() gives conflicting gckind, use the "
- "correct XxForwardReference")
- self.__class__ = realcontainertype.__class__
- self.__dict__ = realcontainertype.__dict__
- def __hash__(self):
- raise TypeError("%r object is not hashable" % self.__class__.__name__)
- class GcForwardReference(ForwardReference):
- _gckind = 'gc'
- class FuncForwardReference(ForwardReference):
- _gckind = 'prebuilt'
- FORWARDREF_BY_FLAVOR = {'raw': ForwardReference,
- 'gc': GcForwardReference,
- 'prebuilt': FuncForwardReference}
- class Primitive(LowLevelType):
- def __init__(self, name, default):
- self._name = self.__name__ = name
- self._default = default
- def __str__(self):
- return self._name
- def _defl(self, parent=None, parentindex=None):
- return self._default
- def _allocate(self, initialization, parent=None, parentindex=None):
- if self is not Void and initialization != 'example':
- return _uninitialized(self)
- else:
- return self._default
- def _is_atomic(self):
- return True
- def _example(self, parent=None, parentindex=None):
- return self._default
- class Number(Primitive):
- def __init__(self, name, type, cast=None):
- Primitive.__init__(self, name, type())
- self._type = type
- if cast is None:
- self._cast = type
- else:
- self._cast = cast
- def normalized(self):
- return build_number(None, normalizedinttype(self._type))
- _numbertypes = {int: Number("Signed", int, intmask)}
- _numbertypes[r_int] = _numbertypes[int]
- _numbertypes[r_longlonglong] = Number("SignedLongLongLong", r_longlonglong,
- longlonglongmask)
- if r_longlong is not r_int:
- _numbertypes[r_longlong] = Number("SignedLongLong", r_longlong,
- longlongmask)
- def build_number(name, type):
- try:
- return _numbertypes[type]
- except KeyError:
- pass
- if name is None:
- raise ValueError('No matching lowlevel type for %r'%type)
- number = _numbertypes[type] = Number(name, type)
- return number
- if is_emulated_long:
- SignedFmt = 'q'
- else:
- SignedFmt = 'l'
- Signed = build_number("Signed", int)
- Unsigned = build_number("Unsigned", r_uint)
- SignedLongLong = build_number("SignedLongLong", r_longlong)
- SignedLongLongLong = build_number("SignedLongLongLong", r_longlonglong)
- UnsignedLongLong = build_number("UnsignedLongLong", r_ulonglong)
- Float = Primitive("Float", 0.0) # C type 'double'
- SingleFloat = Primitive("SingleFloat", r_singlefloat(0.0)) # 'float'
- LongFloat = Primitive("LongFloat", r_longfloat(0.0)) # 'long double'
- r_singlefloat._TYPE = SingleFloat
- Char = Primitive("Char", '\x00')
- Bool = Primitive("Bool", False)
- Void = Primitive("Void", None)
- UniChar = Primitive("UniChar", u'\x00')
- class Ptr(LowLevelType):
- __name__ = property(lambda self: '%sPtr' % self.TO.__name__)
- _cache = WeakValueDictionary() # cache the Ptrs
- def __new__(cls, TO, use_cache=True):
- if not isinstance(TO, ContainerType):
- raise TypeError("can only point to a Container type, "
- "not to %s" % (TO,))
- if not use_cache:
- obj = LowLevelType.__new__(cls)
- else:
- try:
- return Ptr._cache[TO]
- except KeyError:
- obj = Ptr._cache[TO] = LowLevelType.__new__(cls)
- except TypeError:
- obj = LowLevelType.__new__(cls)
- obj.TO = TO
- return obj
- def _needsgc(self):
- # XXX deprecated interface
- return self.TO._gckind not in ('raw', 'prebuilt')
- def __str__(self):
- return '* %s' % (self.TO, )
- def _short_name(self):
- return 'Ptr %s' % (self.TO._short_name(), )
- def _is_atomic(self):
- return self.TO._gckind == 'raw'
- def _defl(self, parent=None, parentindex=None):
- return _ptr(self, None)
- def _allocate(self, initialization, parent=None, parentindex=None):
- if initialization == 'example':
- return _ptr(self, None)
- elif initialization == 'malloc' and self._needsgc():
- return _ptr(self, None)
- else:
- return _uninitialized(self)
- def _example(self):
- o = self.TO._container_example()
- return _ptr(self, o, solid=True)
- def _interior_ptr_type_with_index(self, TO):
- assert self.TO._gckind == 'gc'
- if isinstance(TO, Struct):
- R = GcStruct("Interior", ('ptr', self), ('index', Signed),
- hints={'interior_ptr_type':True},
- adtmeths=TO._adtmeths)
- else:
- R = GcStruct("Interior", ('ptr', self), ('index', Signed),
- hints={'interior_ptr_type':True})
- return R
- @analyzer_for(Ptr)
- def constPtr(T):
- assert T.is_constant()
- return immutablevalue(Ptr(T.const))
- class InteriorPtr(LowLevelType):
- def __init__(self, PARENTTYPE, TO, offsets):
- self.PARENTTYPE = PARENTTYPE
- self.TO = TO
- self.offsets = tuple(offsets)
- def __str__(self):
- return '%s (%s).%s'%(self.__class__.__name__,
- self.PARENTTYPE._short_name(),
- '.'.join(map(str, self.offsets)))
- def _example(self):
- ob = Ptr(self.PARENTTYPE)._example()
- for o in self.offsets:
- if isinstance(o, str):
- ob = getattr(ob, o)
- else:
- ob = ob[0]
- return ob
- # ____________________________________________________________
- def typeOf(val):
- try:
- return val._TYPE
- except AttributeError:
- tp = type(val)
- if tp is _uninitialized:
- raise UninitializedMemoryAccess("typeOf uninitialized value")
- if tp is NoneType:
- return Void # maybe
- if tp is int:
- return Signed
- if tp is long:
- if -maxint-1 <= val <= maxint:
- return Signed
- elif longlongmask(val) == val:
- return SignedLongLong
- else:
- raise OverflowError("integer %r is out of bounds" % (val,))
- if tp is bool:
- return Bool
- if issubclass(tp, base_int):
- return build_number(None, tp)
- if tp is float:
- return Float
- if tp is r_longfloat:
- return LongFloat
- if tp is str:
- assert len(val) == 1
- return Char
- if tp is unicode:
- assert len(val) == 1
- return UniChar
- if issubclass(tp, Symbolic):
- return val.lltype()
- # if you get a TypeError: typeOf('_interior_ptr' object)
- # here, it is very likely that you are accessing an interior pointer
- # in an illegal way!
- raise TypeError("typeOf(%r object)" % (tp.__name__,))
- @analyzer_for(typeOf)
- def ann_typeOf(s_val):
- from rpython.rtyper.llannotation import annotation_to_lltype
- lltype = annotation_to_lltype(s_val, info="in typeOf(): ")
- return immutablevalue(lltype)
- _to_primitive = {
- Char: chr,
- UniChar: unichr,
- Float: float,
- Bool: bool,
- }
- def cast_primitive(TGT, value):
- ORIG = typeOf(value)
- if not isinstance(TGT, Primitive) or not isinstance(ORIG, Primitive):
- raise TypeError("can only primitive to primitive")
- if ORIG == TGT:
- return value
- if ORIG == Char or ORIG == UniChar:
- value = ord(value)
- elif ORIG == Float:
- if TGT == SingleFloat:
- return r_singlefloat(value)
- elif TGT == LongFloat:
- return r_longfloat(value)
- value = long(value)
- cast = _to_primitive.get(TGT)
- if cast is not None:
- return cast(value)
- if isinstance(TGT, Number):
- return TGT._cast(value)
- if ORIG == SingleFloat and TGT == Float:
- return float(value)
- if ORIG == LongFloat and TGT == Float:
- return float(value)
- raise TypeError("unsupported cast")
- @analyzer_for(cast_primitive)
- def ann_cast_primitive(T, s_v):
- from rpython.rtyper.llannotation import (
- annotation_to_lltype, ll_to_annotation)
- assert T.is_constant()
- return ll_to_annotation(cast_primitive(T.const,
- annotation_to_lltype(s_v)._defl()))
- def _cast_whatever(TGT, value):
- from rpython.rtyper.lltypesystem import llmemory, rffi
- ORIG = typeOf(value)
- if ORIG == TGT:
- return value
- if (isinstance(TGT, Primitive) and
- isinstance(ORIG, Primitive)):
- return cast_primitive(TGT, value)
- elif isinstance(TGT, Ptr):
- if isinstance(ORIG, Ptr):
- if (isinstance(TGT.TO, OpaqueType) or
- isinstance(ORIG.TO, OpaqueType)):
- return cast_opaque_ptr(TGT, value)
- else:
- return cast_pointer(TGT, value)
- elif ORIG == llmemory.Address:
- return llmemory.cast_adr_to_ptr(value, TGT)
- elif TGT == rffi.VOIDP and ORIG == Unsigned:
- return rffi.cast(TGT, value)
- elif ORIG == Signed:
- return cast_int_to_ptr(TGT, value)
- elif TGT == llmemory.Address and isinstance(ORIG, Ptr):
- return llmemory.cast_ptr_to_adr(value)
- elif TGT == Signed and isinstance(ORIG, Ptr) and ORIG.TO._gckind == 'raw':
- return llmemory.cast_adr_to_int(llmemory.cast_ptr_to_adr(value),
- 'symbolic')
- raise TypeError("don't know how to cast from %r to %r" % (ORIG, TGT))
- def erasedType(T):
- while isinstance(T, Ptr) and isinstance(T.TO, Struct):
- first, FIRSTTYPE = T.TO._first_struct()
- if first is None:
- break
- T = Ptr(FIRSTTYPE)
- return T
- class InvalidCast(TypeError):
- pass
- def _castdepth(OUTSIDE, INSIDE):
- if OUTSIDE == INSIDE:
- return 0
- dwn = 0
- while isinstance(OUTSIDE, Struct):
- first, FIRSTTYPE = OUTSIDE._first_struct()
- if first is None:
- break
- dwn += 1
- if FIRSTTYPE == INSIDE:
- return dwn
- OUTSIDE = getattr(OUTSIDE, first)
- return -1
- def castable(PTRTYPE, CURTYPE):
- if CURTYPE.TO._gckind != PTRTYPE.TO._gckind:
- raise TypeError("cast_pointer() cannot change the gc status: %s to %s"
- % (CURTYPE, PTRTYPE))
- if CURTYPE == PTRTYPE:
- return 0
- if (not isinstance(CURTYPE.TO, Struct) or
- not isinstance(PTRTYPE.TO, Struct)):
- raise InvalidCast(CURTYPE, PTRTYPE)
- CURSTRUC = CURTYPE.TO
- PTRSTRUC = PTRTYPE.TO
- d = _castdepth(CURSTRUC, PTRSTRUC)
- if d >= 0:
- return d
- u = _castdepth(PTRSTRUC, CURSTRUC)
- if u == -1:
- raise InvalidCast(CURTYPE, PTRTYPE)
- return -u
- def cast_pointer(PTRTYPE, ptr):
- CURTYPE = typeOf(ptr)
- if not isinstance(CURTYPE, Ptr) or not isinstance(PTRTYPE, Ptr):
- raise TypeError("can only cast pointers to other pointers")
- return ptr._cast_to(PTRTYPE)
- @analyzer_for(cast_pointer)
- def ann_cast_pointer(PtrT, s_p):
- assert isinstance(s_p, SomePtr), "casting of non-pointer: %r" % s_p
- assert PtrT.is_constant()
- cast_p = cast_pointer(PtrT.const, s_p.ll_ptrtype._defl())
- return SomePtr(ll_ptrtype=typeOf(cast_p))
- def cast_opaque_ptr(PTRTYPE, ptr):
- CURTYPE = typeOf(ptr)
- if not isinstance(CURTYPE, Ptr) or not isinstance(PTRTYPE, Ptr):
- raise TypeError("can only cast pointers to other pointers")
- if CURTYPE == PTRTYPE:
- return ptr
- if CURTYPE.TO._gckind != PTRTYPE.TO._gckind:
- raise TypeError("cast_opaque_ptr() cannot change the gc status: "
- "%s to %s" % (CURTYPE, PTRTYPE))
- if (isinstance(CURTYPE.TO, OpaqueType)
- and not isinstance(PTRTYPE.TO, OpaqueType)):
- if hasattr(ptr._obj, '_cast_to_ptr'):
- return ptr._obj._cast_to_ptr(PTRTYPE)
- if not ptr:
- return nullptr(PTRTYPE.TO)
- try:
- container = ptr._obj.container
- except AttributeError:
- raise InvalidCast("%r does not come from a container" % (ptr,))
- solid = getattr(ptr._obj, 'solid', False)
- p = _ptr(Ptr(typeOf(container)), container, solid)
- return cast_pointer(PTRTYPE, p)
- elif (not isinstance(CURTYPE.TO, OpaqueType)
- and isinstance(PTRTYPE.TO, OpaqueType)):
- if hasattr(ptr, '_cast_to_opaque'):
- return ptr._cast_to_opaque(PTRTYPE)
- if not ptr:
- return nullptr(PTRTYPE.TO)
- return opaqueptr(PTRTYPE.TO, 'hidden', container = ptr._obj,
- ORIGTYPE = CURTYPE,
- solid = ptr._solid)
- elif (isinstance(CURTYPE.TO, OpaqueType)
- and isinstance(PTRTYPE.TO, OpaqueType)):
- if not ptr:
- return nullptr(PTRTYPE.TO)
- try:
- container = ptr._obj.container
- except AttributeError:
- raise InvalidCast("%r does not come from a container" % (ptr,))
- return opaqueptr(PTRTYPE.TO, 'hidden',
- container = container,
- solid = ptr._obj.solid)
- else:
- raise TypeError("invalid cast_opaque_ptr(): %r -> %r" %
- (CURTYPE, PTRTYPE))
- @analyzer_for(cast_opaque_ptr)
- def ann_cast_opaque_ptr(PtrT, s_p):
- assert isinstance(s_p, SomePtr), "casting of non-pointer: %r" % s_p
- assert PtrT.is_constant()
- cast_p = cast_opaque_ptr(PtrT.const, s_p.ll_ptrtype._defl())
- return SomePtr(ll_ptrtype=typeOf(cast_p))
- def length_of_simple_gcarray_from_opaque(opaque_ptr):
- CURTYPE = typeOf(opaque_ptr)
- if not isinstance(CURTYPE, Ptr):
- raise TypeError("can only cast pointers to other pointers")
- if not isinstance(CURTYPE.TO, GcOpaqueType):
- raise TypeError("expected a GcOpaqueType")
- try:
- c = opaque_ptr._obj.container
- except AttributeError:
- # if 'opaque_ptr' is already some _llgcopaque, hack its length
- # by casting it to a random GcArray type and hoping
- from rpython.rtyper.lltypesystem import rffi
- p = rffi.cast(Ptr(GcArray(Signed)), opaque_ptr)
- return len(p)
- else:
- return c.getlength()
- @analyzer_for(length_of_simple_gcarray_from_opaque)
- def ann_length_of_simple_gcarray_from_opaque(s_p):
- assert isinstance(s_p, SomePtr), "casting of non-pointer: %r" % s_p
- assert isinstance(s_p.ll_ptrtype.TO, GcOpaqueType)
- return SomeInteger(nonneg=True)
- def direct_fieldptr(structptr, fieldname):
- """Get a pointer to a field in the struct. The resulting
- pointer is actually of type Ptr(FixedSizeArray(FIELD, 1)).
- It can be used in a regular getarrayitem(0) or setarrayitem(0)
- to read or write to the field.
- """
- CURTYPE = typeOf(structptr).TO
- if not isinstance(CURTYPE, Struct):
- raise TypeError("direct_fieldptr: not a struct")
- if fieldname not in CURTYPE._flds:
- raise TypeError("%s has no field %r" % (CURTYPE, fieldname))
- if not structptr:
- raise RuntimeError("direct_fieldptr: NULL argument")
- return _subarray._makeptr(structptr._obj, fieldname, structptr._solid)
- @analyzer_for(direct_fieldptr)
- def ann_direct_fieldptr(s_p, s_fieldname):
- assert isinstance(s_p, SomePtr), "direct_* of non-pointer: %r" % s_p
- assert s_fieldname.is_constant()
- cast_p = direct_fieldptr(s_p.ll_ptrtype._example(),
- s_fieldname.const)
- return SomePtr(ll_ptrtype=typeOf(cast_p))
- def direct_arrayitems(arrayptr):
- """Get a pointer to the first item of the array. The resulting
- pointer is actually of type Ptr(FixedSizeArray(ITEM, 1)) but can
- be used in a regular getarrayitem(n) or direct_ptradd(n) to access
- further elements.
- """
- CURTYPE = typeOf(arrayptr).TO
- if not isinstance(CURTYPE, (Array, FixedSizeArray)):
- raise TypeError("direct_arrayitems: not an array")
- if not arrayptr:
- raise RuntimeError("direct_arrayitems: NULL argument")
- return _subarray._makeptr(arrayptr._obj, 0, arrayptr._solid)
- @analyzer_for(direct_arrayitems)
- def ann_direct_arrayitems(s_p):
- assert isinstance(s_p, SomePtr), "direct_* of non-pointer: %r" % s_p
- cast_p = direct_arrayitems(s_p.ll_ptrtype._example())
- return SomePtr(ll_ptrtype=typeOf(cast_p))
- def direct_ptradd(ptr, n):
- """Shift a pointer forward or backward by n items. The pointer must
- have been built by direct_arrayitems(), or it must be directly a
- pointer to a raw array with no length (handled by emulation with ctypes).
- """
- if not ptr:
- raise RuntimeError("direct_ptradd: NULL argument")
- if not isinstance(ptr._obj, _subarray):
- # special case: delegate barebone C-like array cases to rffi.ptradd()
- from rpython.rtyper.lltypesystem import rffi
- return rffi.ptradd(ptr, n)
- parent, base = parentlink(ptr._obj)
- return _subarray._makeptr(parent, base + n, ptr._solid)
- @analyzer_for(direct_ptradd)
- def ann_direct_ptradd(s_p, s_n):
- assert isinstance(s_p, SomePtr), "direct_* of non-pointer: %r" % s_p
- # don't bother with an example here: the resulting pointer is the same
- return s_p
- def parentlink(container):
- parent = container._parentstructure()
- if parent is not None:
- return parent, container._parent_index
- else:
- return None, None
- def top_container(container):
- top_parent = container
- while True:
- parent = top_parent._parentstructure()
- if parent is None:
- break
- top_parent = parent
- return top_parent
- def normalizeptr(p, check=True):
- # If p is a pointer, returns the same pointer casted to the largest
- # containing structure (for the cast where p points to the header part).
- # Also un-hides pointers to opaque. Null pointers become None.
- assert not isinstance(p, _container) # pointer or primitive
- T = typeOf(p)
- if not isinstance(T, Ptr):
- return p # primitive
- obj = p._getobj(check)
- if not obj:
- return None # null pointer
- if type(p._obj0) is int:
- return p # a pointer obtained by cast_int_to_ptr
- if getattr(p._obj0, '_carry_around_for_tests', False):
- return p # a pointer obtained by cast_instance_to_base_ptr
- container = obj._normalizedcontainer()
- if type(container) is int:
- # this must be an opaque ptr originating from an integer
- assert isinstance(obj, _opaque)
- return cast_int_to_ptr(obj.ORIGTYPE, container)
- if container is not obj:
- p = _ptr(Ptr(typeOf(container)), container, p._solid)
- return p
- class DelayedPointer(Exception):
- pass
- class UninitializedMemoryAccess(Exception):
- pass
- class _abstract_ptr(object):
- __slots__ = ('_T',)
- # assumes one can access _TYPE, _expose and _obj
- def _set_T(self, T):
- _ptr._T.__set__(self, T)
- def _togckind(self):
- return self._T._gckind
- def _needsgc(self):
- # XXX deprecated interface
- return self._TYPE._needsgc() # xxx other rules?
- def __eq__(self, other):
- if type(self) is not type(other):
- raise TypeError("comparing pointer with %r object" % (
- type(other).__name__,))
- if self._TYPE != other._TYPE:
- raise TypeError("comparing %r and %r" % (self._TYPE, other._TYPE))
- try:
- return self._obj == other._obj
- except DelayedPointer:
- # if one of the two pointers is delayed, they cannot
- # possibly be equal unless they are the same _ptr instance
- return self is other
- def __ne__(self, other):
- return not (self == other)
- def _same_obj(self, other):
- return self._obj == other._obj
- def __hash__(self):
- raise TypeError("pointer objects are not hashable")
- def __nonzero__(self):
- try:
- return self._obj is not None
- except DelayedPointer:
- return True # assume it's not a delayed null
- # _setobj, _getobj and _obj0 are really _internal_ implementations
- # details of _ptr, use _obj if necessary instead !
- def _setobj(self, pointing_to, solid=False):
- if pointing_to is None:
- obj0 = None
- elif (solid or self._T._gckind != 'raw' or
- isinstance(self._T, FuncType)):
- obj0 = pointing_to
- else:
- self._set_weak(True)
- obj0 = weakref.ref(pointing_to)
- self._set_solid(solid)
- self._set_obj0(obj0)
- def _getobj(self, check=True):
- obj = self._obj0
- if obj is not None:
- if self._weak:
- obj = obj()
- if obj is None:
- raise RuntimeError("accessing already garbage collected %r"
- % (self._T,))
- if isinstance(obj, _container):
- if check:
- obj._check()
- elif isinstance(obj, str) and obj.startswith("delayed!"):
- raise DelayedPointer
- return obj
- _obj = property(_getobj)
- def _was_freed(self):
- return (type(self._obj0) not in (type(None), int) and
- self._getobj(check=False)._was_freed())
- def _lookup_adtmeth(self, member_name):
- if isinstance(self._T, ContainerType):
- try:
- adtmember = self._T._adtmeths[member_name]
- except KeyError:
- pass
- else:
- try:
- getter = adtmember.__get__
- except AttributeError:
- return adtmember
- else:
- return getter(self)
- raise AttributeError
- def __getattr__(self, field_name): # ! can only return basic or ptr !
- if isinstance(self._T, Struct):
- if field_name in self._T._flds:
- o = self._obj._getattr(field_name)
- return self._expose(field_name, o)
- try:
- return self._lookup_adtmeth(field_name)
- except AttributeError:
- raise AttributeError("%r instance has no field %r" % (self._T,
- field_name))
- def __setattr__(self, field_name, val):
- if isinstance(self._T, Struct):
- if field_name in self._T._flds:
- T1 = self._T._flds[field_name]
- T2 = typeOf(val)
- if T1 == T2:
- setattr(self._obj, field_name, val)
- else:
- raise TypeError(
- "%r instance field %r:\nexpects %r\n got %r" %
- (self._T, field_name, T1, T2))
- return
- raise AttributeError("%r instance has no field %r" %
- (self._T, field_name))
- def __getitem__(self, i): # ! can only return basic or ptr !
- if isinstance(self._T, (Array, FixedSizeArray)):
- start, stop = self._obj.getbounds()
- if not (start <= i < stop):
- if isinstance(i, slice):
- raise TypeError("array slicing not supported")
- raise IndexError("array index out of bounds")
- o = self._obj.getitem(i)
- return self._expose(i, o)
- raise TypeError("%r instance is not an array" % (self._T,))
- def __setitem__(self, i, val):
- if isinstance(self._T, (Array, FixedSizeArray)):
- T1 = self._T.OF
- if isinstance(T1, ContainerType):
- raise TypeError("cannot directly assign to container array "
- "items")
- T2 = typeOf(val)
- if T2 != T1:
- from rpython.rtyper.lltypesystem import rffi
- if T1 is rffi.VOIDP and isinstance(T2, Ptr):
- # Any pointer is convertible to void*
- val = rffi.cast(rffi.VOIDP, val)
- else:
- raise TypeError("%r items:\n"
- "expect %r\n"
- " got %r" % (self._T, T1, T2))
- start, stop = self._obj.getbounds()
- if not (start <= i < stop):
- if isinstance(i, slice):
- raise TypeError("array slicing not supported")
- raise IndexError("array index out of bounds")
- self._obj.setitem(i, val)
- return
- raise TypeError("%r instance is not an array" % (self._T,))
- def __len__(self):
- if isinstance(self._T, (Array, FixedSizeArray)):
- if self._T._hints.get('nolength', False):
- raise TypeError("%r instance has no length attribute" %
- (self._T,))
- return self._obj.getlength()
- raise TypeError("%r instance is not an array" % (self._T,))
- def _fixedlength(self):
- length = len(self) # always do this, for the checking
- if isinstance(self._T, FixedSizeArray):
- return length
- else:
- return None
- def __repr__(self):
- return '<%s>' % (self,)
- def __str__(self):
- try:
- return '* %s' % (self._obj, )
- except RuntimeError:
- return '* DEAD %s' % self._T
- except DelayedPointer:
- return '* %s' % (self._obj0,)
- def __call__(self, *args):
- from rpython.rtyper.lltypesystem import rffi
- if isinstance(self._T, FuncType):
- if len(args) != len(self._T.ARGS):
- raise TypeError("calling %r with wrong argument number: %r" %
- (self._T, args))
- for i, a, ARG in zip(range(len(self._T.ARGS)), args, self._T.ARGS):
- if typeOf(a) != ARG:
- # ARG could be Void
- if ARG == Void:
- try:
- value = getattr(self._obj, '_void' + str(i))
- except AttributeError:
- pass
- else:
- assert a == value
- # None is acceptable for any pointer
- elif isinstance(ARG, Ptr) and a is None:
- pass
- # Any pointer is convertible to void*
- elif ARG is rffi.VOIDP and isinstance(typeOf(a), Ptr):
- pass
- # special case: ARG can be a container type, in which
- # case a should be a pointer to it. This must also be
- # special-cased in the backends.
- elif (isinstance(ARG, ContainerType) and
- typeOf(a) == Ptr(ARG)):
- pass
- else:
- args_repr = [typeOf(arg) for arg in args]
- raise TypeError("calling %r with wrong argument "
- "types: %r" % (self._T, args_repr))
- callb = self._obj._callable
- if callb is None:
- raise RuntimeError("calling undefined function")
- return callb(*args)
- raise TypeError("%r instance is not a function" % (self._T,))
- def _identityhash(self, cache=True):
- p = normalizeptr(self)
- try:
- return p._obj._hash_cache_
- except AttributeError:
- assert self._T._gckind == 'gc'
- assert self # not for NULL
- result = hash(p._obj)
- if cache:
- try:
- p._obj._hash_cache_ = result
- except AttributeError:
- pass
- return result
- class _ptr(_abstract_ptr):
- __slots__ = ('_TYPE',
- '_weak', '_solid',
- '_obj0', '__weakref__')
- def _set_TYPE(self, TYPE):
- _ptr._TYPE.__set__(self, TYPE)
- def _set_weak(self, weak):
- _ptr._weak.__set__(self, weak)
- def _set_solid(self, solid):
- _ptr._solid.__set__(self, solid)
- def _set_obj0(self, obj):
- _ptr._obj0.__set__(self, obj)
- def __init__(self, TYPE, pointing_to, solid=False):
- self._set_TYPE(TYPE)
- self._set_T(TYPE.TO)
- self._set_weak(False)
- self._setobj(pointing_to,…
Large files files are truncated, but you can click here to view the full file