PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/rlib/objectmodel.py

https://bitbucket.org/pypy/pypy/
Python | 628 lines | 573 code | 7 blank | 48 comment | 4 complexity | 4ca1ed4d30f7527ff3a398e12b59b15b MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. """
  2. This file defines utilities for manipulating objects in an
  3. RPython-compliant way.
  4. """
  5. import sys
  6. import types
  7. import math
  8. # specialize is a decorator factory for attaching _annspecialcase_
  9. # attributes to functions: for example
  10. #
  11. # f._annspecialcase_ = 'specialize:memo' can be expressed with:
  12. # @specialize.memo()
  13. # def f(...
  14. #
  15. # f._annspecialcase_ = 'specialize:arg(0)' can be expressed with:
  16. # @specialize.arg(0)
  17. # def f(...
  18. #
  19. from pypy.rpython.extregistry import ExtRegistryEntry
  20. class _Specialize(object):
  21. def memo(self):
  22. """ Specialize functions based on argument values. All arguments has
  23. to be constant at the compile time. The whole function call is replaced
  24. by a call result then.
  25. """
  26. def decorated_func(func):
  27. func._annspecialcase_ = 'specialize:memo'
  28. return func
  29. return decorated_func
  30. def arg(self, *args):
  31. """ Specialize function based on values of given positions of arguments.
  32. They must be compile-time constants in order to work.
  33. There will be a copy of provided function for each combination
  34. of given arguments on positions in args (that can lead to
  35. exponential behavior!).
  36. """
  37. def decorated_func(func):
  38. func._annspecialcase_ = 'specialize:arg' + self._wrap(args)
  39. return func
  40. return decorated_func
  41. def arg_or_var(self, *args):
  42. """ Same as arg, but additionally allow for a 'variable' annotation,
  43. that would simply be a situation where designated arg is not
  44. a constant
  45. """
  46. def decorated_func(func):
  47. func._annspecialcase_ = 'specialize:arg_or_var' + self._wrap(args)
  48. return func
  49. return decorated_func
  50. def argtype(self, *args):
  51. """ Specialize function based on types of arguments on given positions.
  52. There will be a copy of provided function for each combination
  53. of given arguments on positions in args (that can lead to
  54. exponential behavior!).
  55. """
  56. def decorated_func(func):
  57. func._annspecialcase_ = 'specialize:argtype' + self._wrap(args)
  58. return func
  59. return decorated_func
  60. def ll(self):
  61. """ This is version of argtypes that cares about low-level types
  62. (so it'll get additional copies for two different types of pointers
  63. for example). Same warnings about exponential behavior apply.
  64. """
  65. def decorated_func(func):
  66. func._annspecialcase_ = 'specialize:ll'
  67. return func
  68. return decorated_func
  69. def ll_and_arg(self, *args):
  70. """ This is like ll(), but instead of specializing on all arguments,
  71. specializes on only the arguments at the given positions
  72. """
  73. def decorated_func(func):
  74. func._annspecialcase_ = 'specialize:ll_and_arg' + self._wrap(args)
  75. return func
  76. return decorated_func
  77. def call_location(self):
  78. """ Specializes the function for each call site.
  79. """
  80. def decorated_func(func):
  81. func._annspecialcase_ = "specialize:call_location"
  82. return func
  83. return decorated_func
  84. def _wrap(self, args):
  85. return "("+','.join([repr(arg) for arg in args]) +")"
  86. specialize = _Specialize()
  87. def enforceargs(*args):
  88. """ Decorate a function with forcing of RPython-level types on arguments.
  89. None means no enforcing.
  90. XXX shouldn't we also add asserts in function body?
  91. """
  92. def decorator(f):
  93. f._annenforceargs_ = args
  94. return f
  95. return decorator
  96. # ____________________________________________________________
  97. class Symbolic(object):
  98. def annotation(self):
  99. return None
  100. def lltype(self):
  101. return None
  102. def __cmp__(self, other):
  103. if self is other:
  104. return 0
  105. else:
  106. raise TypeError("Symbolics cannot be compared! (%r, %r)"
  107. % (self, other))
  108. def __hash__(self):
  109. raise TypeError("Symbolics are not hashable! %r" % (self,))
  110. def __nonzero__(self):
  111. raise TypeError("Symbolics are not comparable! %r" % (self,))
  112. class ComputedIntSymbolic(Symbolic):
  113. def __init__(self, compute_fn):
  114. self.compute_fn = compute_fn
  115. def __repr__(self):
  116. # repr(self.compute_fn) can arrive back here in an
  117. # infinite recursion
  118. try:
  119. name = self.compute_fn.__name__
  120. except (AttributeError, TypeError):
  121. name = hex(id(self.compute_fn))
  122. return '%s(%r)' % (self.__class__.__name__, name)
  123. def annotation(self):
  124. from pypy.annotation import model
  125. return model.SomeInteger()
  126. def lltype(self):
  127. from pypy.rpython.lltypesystem import lltype
  128. return lltype.Signed
  129. class CDefinedIntSymbolic(Symbolic):
  130. def __init__(self, expr, default=0):
  131. self.expr = expr
  132. self.default = default
  133. def __repr__(self):
  134. return '%s(%r)' % (self.__class__.__name__, self.expr)
  135. def annotation(self):
  136. from pypy.annotation import model
  137. return model.SomeInteger()
  138. def lltype(self):
  139. from pypy.rpython.lltypesystem import lltype
  140. return lltype.Signed
  141. malloc_zero_filled = CDefinedIntSymbolic('MALLOC_ZERO_FILLED', default=0)
  142. running_on_llinterp = CDefinedIntSymbolic('RUNNING_ON_LLINTERP', default=1)
  143. # running_on_llinterp is meant to have the value 0 in all backends
  144. # ____________________________________________________________
  145. def instantiate(cls):
  146. "Create an empty instance of 'cls'."
  147. if isinstance(cls, type):
  148. return cls.__new__(cls)
  149. else:
  150. return types.InstanceType(cls)
  151. def we_are_translated():
  152. return False
  153. # annotation -> True (replaced by the flow objspace)
  154. def keepalive_until_here(*values):
  155. pass
  156. def is_annotation_constant(thing):
  157. """ Returns whether the annotator can prove that the argument is constant.
  158. For advanced usage only."""
  159. return True
  160. class Entry(ExtRegistryEntry):
  161. _about_ = is_annotation_constant
  162. def compute_result_annotation(self, s_arg):
  163. from pypy.annotation import model
  164. r = model.SomeBool()
  165. r.const = s_arg.is_constant()
  166. return r
  167. def specialize_call(self, hop):
  168. from pypy.rpython.lltypesystem import lltype
  169. return hop.inputconst(lltype.Bool, hop.s_result.const)
  170. # ____________________________________________________________
  171. class FREED_OBJECT(object):
  172. def __getattribute__(self, attr):
  173. raise RuntimeError("trying to access freed object")
  174. def __setattr__(self, attr, value):
  175. raise RuntimeError("trying to access freed object")
  176. def free_non_gc_object(obj):
  177. assert not getattr(obj.__class__, "_alloc_flavor_", 'gc').startswith('gc'), "trying to free gc object"
  178. obj.__dict__ = {}
  179. obj.__class__ = FREED_OBJECT
  180. # ____________________________________________________________
  181. def newlist(sizehint=0):
  182. """ Create a new list, but pass a hint how big the size should be
  183. preallocated
  184. """
  185. return []
  186. class Entry(ExtRegistryEntry):
  187. _about_ = newlist
  188. def compute_result_annotation(self, s_sizehint):
  189. from pypy.annotation.model import SomeInteger
  190. assert isinstance(s_sizehint, SomeInteger)
  191. return self.bookkeeper.newlist()
  192. def specialize_call(self, orig_hop, i_sizehint=None):
  193. from pypy.rpython.rlist import rtype_newlist
  194. # fish a bit hop
  195. hop = orig_hop.copy()
  196. v = hop.args_v[0]
  197. r, s = hop.r_s_popfirstarg()
  198. if s.is_constant():
  199. v = hop.inputconst(r, s.const)
  200. hop.exception_is_here()
  201. return rtype_newlist(hop, v_sizehint=v)
  202. # ____________________________________________________________
  203. #
  204. # id-like functions. The idea is that calling hash() or id() is not
  205. # allowed in RPython. You have to call one of the following more
  206. # precise functions.
  207. def compute_hash(x):
  208. """RPython equivalent of hash(x), where 'x' is an immutable
  209. RPython-level. For strings or unicodes it computes the hash as
  210. in Python. For tuples it calls compute_hash() recursively.
  211. For instances it uses compute_identity_hash().
  212. Note that this can return 0 or -1 too.
  213. Behavior across translation:
  214. * on lltypesystem, it always returns the same number, both
  215. before and after translation. Dictionaries don't need to
  216. be rehashed after translation.
  217. * on ootypesystem, the value changes because of translation.
  218. Dictionaries need to be rehashed.
  219. """
  220. if isinstance(x, (str, unicode)):
  221. return _hash_string(x)
  222. if isinstance(x, int):
  223. return x
  224. if isinstance(x, float):
  225. return _hash_float(x)
  226. if isinstance(x, tuple):
  227. return _hash_tuple(x)
  228. if x is None:
  229. return 0
  230. return compute_identity_hash(x)
  231. def compute_identity_hash(x):
  232. """RPython equivalent of object.__hash__(x). This returns the
  233. so-called 'identity hash', which is the non-overridable default hash
  234. of Python. Can be called for any RPython-level object that turns
  235. into a GC object, but not NULL. The value is not guaranteed to be the
  236. same before and after translation, except for RPython instances on the
  237. lltypesystem.
  238. """
  239. assert x is not None
  240. result = object.__hash__(x)
  241. try:
  242. x.__dict__['__precomputed_identity_hash'] = result
  243. except (TypeError, AttributeError):
  244. pass
  245. return result
  246. def compute_unique_id(x):
  247. """RPython equivalent of id(x). The 'x' must be an RPython-level
  248. object that turns into a GC object. This operation can be very
  249. costly depending on the garbage collector. To remind you of this
  250. fact, we don't support id(x) directly.
  251. (XXX not implemented on ootype, falls back to compute_identity_hash)
  252. """
  253. return id(x) # XXX need to return r_longlong on some platforms
  254. def current_object_addr_as_int(x):
  255. """A cheap version of id(x). The current memory location of an
  256. object can change over time for moving GCs. Also note that on
  257. ootypesystem this typically doesn't return the real address but
  258. just the same as compute_hash(x).
  259. """
  260. from pypy.rlib.rarithmetic import intmask
  261. return intmask(id(x))
  262. # ----------
  263. def _hash_string(s):
  264. """The algorithm behind compute_hash() for a string or a unicode."""
  265. from pypy.rlib.rarithmetic import intmask
  266. length = len(s)
  267. if length == 0:
  268. return -1
  269. x = ord(s[0]) << 7
  270. i = 0
  271. while i < length:
  272. x = intmask((1000003*x) ^ ord(s[i]))
  273. i += 1
  274. x ^= length
  275. return intmask(x)
  276. def _hash_float(f):
  277. """The algorithm behind compute_hash() for a float.
  278. This implementation is identical to the CPython implementation,
  279. except the fact that the integer case is not treated specially.
  280. In RPython, floats cannot be used with ints in dicts, anyway.
  281. """
  282. from pypy.rlib.rarithmetic import intmask
  283. from pypy.rlib.rfloat import isfinite, isinf
  284. if not isfinite(f):
  285. if isinf(f):
  286. if f < 0.0:
  287. return -271828
  288. else:
  289. return 314159
  290. else: #isnan(f):
  291. return 0
  292. v, expo = math.frexp(f)
  293. v *= TAKE_NEXT
  294. hipart = int(v)
  295. v = (v - float(hipart)) * TAKE_NEXT
  296. x = hipart + int(v) + (expo << 15)
  297. return intmask(x)
  298. TAKE_NEXT = float(2**31)
  299. def _hash_tuple(t):
  300. """NOT_RPYTHON. The algorithm behind compute_hash() for a tuple.
  301. It is modelled after the old algorithm of Python 2.3, which is
  302. a bit faster than the one introduced by Python 2.4. We assume
  303. that nested tuples are very uncommon in RPython, making the bad
  304. case unlikely.
  305. """
  306. from pypy.rlib.rarithmetic import intmask
  307. x = 0x345678
  308. for item in t:
  309. y = compute_hash(item)
  310. x = intmask((1000003 * x) ^ y)
  311. return x
  312. # ----------
  313. class Entry(ExtRegistryEntry):
  314. _about_ = compute_hash
  315. def compute_result_annotation(self, s_x):
  316. from pypy.annotation import model as annmodel
  317. return annmodel.SomeInteger()
  318. def specialize_call(self, hop):
  319. r_obj, = hop.args_r
  320. v_obj, = hop.inputargs(r_obj)
  321. ll_fn = r_obj.get_ll_hash_function()
  322. return hop.gendirectcall(ll_fn, v_obj)
  323. class Entry(ExtRegistryEntry):
  324. _about_ = compute_identity_hash
  325. def compute_result_annotation(self, s_x):
  326. from pypy.annotation import model as annmodel
  327. return annmodel.SomeInteger()
  328. def specialize_call(self, hop):
  329. from pypy.rpython.lltypesystem import lltype
  330. vobj, = hop.inputargs(hop.args_r[0])
  331. if hop.rtyper.type_system.name == 'lltypesystem':
  332. ok = (isinstance(vobj.concretetype, lltype.Ptr) and
  333. vobj.concretetype.TO._gckind == 'gc')
  334. else:
  335. from pypy.rpython.ootypesystem import ootype
  336. ok = isinstance(vobj.concretetype, ootype.OOType)
  337. if not ok:
  338. from pypy.rpython.error import TyperError
  339. raise TyperError("compute_identity_hash() cannot be applied to"
  340. " %r" % (vobj.concretetype,))
  341. return hop.genop('gc_identityhash', [vobj], resulttype=lltype.Signed)
  342. class Entry(ExtRegistryEntry):
  343. _about_ = compute_unique_id
  344. def compute_result_annotation(self, s_x):
  345. from pypy.annotation import model as annmodel
  346. return annmodel.SomeInteger()
  347. def specialize_call(self, hop):
  348. from pypy.rpython.lltypesystem import lltype
  349. vobj, = hop.inputargs(hop.args_r[0])
  350. if hop.rtyper.type_system.name == 'lltypesystem':
  351. ok = (isinstance(vobj.concretetype, lltype.Ptr) and
  352. vobj.concretetype.TO._gckind == 'gc')
  353. else:
  354. from pypy.rpython.ootypesystem import ootype
  355. ok = isinstance(vobj.concretetype, (ootype.Instance, ootype.BuiltinType))
  356. if not ok:
  357. from pypy.rpython.error import TyperError
  358. raise TyperError("compute_unique_id() cannot be applied to"
  359. " %r" % (vobj.concretetype,))
  360. return hop.genop('gc_id', [vobj], resulttype=lltype.Signed)
  361. class Entry(ExtRegistryEntry):
  362. _about_ = current_object_addr_as_int
  363. def compute_result_annotation(self, s_x):
  364. from pypy.annotation import model as annmodel
  365. return annmodel.SomeInteger()
  366. def specialize_call(self, hop):
  367. vobj, = hop.inputargs(hop.args_r[0])
  368. if hop.rtyper.type_system.name == 'lltypesystem':
  369. from pypy.rpython.lltypesystem import lltype
  370. if isinstance(vobj.concretetype, lltype.Ptr):
  371. return hop.genop('cast_ptr_to_int', [vobj],
  372. resulttype = lltype.Signed)
  373. elif hop.rtyper.type_system.name == 'ootypesystem':
  374. from pypy.rpython.ootypesystem import ootype
  375. if isinstance(vobj.concretetype, ootype.Instance):
  376. return hop.genop('gc_identityhash', [vobj],
  377. resulttype = ootype.Signed)
  378. from pypy.rpython.error import TyperError
  379. raise TyperError("current_object_addr_as_int() cannot be applied to"
  380. " %r" % (vobj.concretetype,))
  381. # ____________________________________________________________
  382. def hlinvoke(repr, llcallable, *args):
  383. raise TypeError, "hlinvoke is meant to be rtyped and not called direclty"
  384. def invoke_around_extcall(before, after):
  385. """Call before() before any external function call, and after() after.
  386. At the moment only one pair before()/after() can be registered at a time.
  387. """
  388. # NOTE: the hooks are cleared during translation! To be effective
  389. # in a compiled program they must be set at run-time.
  390. from pypy.rpython.lltypesystem import rffi
  391. rffi.aroundstate.before = before
  392. rffi.aroundstate.after = after
  393. # the 'aroundstate' contains regular function and not ll pointers to them,
  394. # but let's call llhelper() anyway to force their annotation
  395. from pypy.rpython.annlowlevel import llhelper
  396. llhelper(rffi.AroundFnPtr, before)
  397. llhelper(rffi.AroundFnPtr, after)
  398. def is_in_callback():
  399. from pypy.rpython.lltypesystem import rffi
  400. return rffi.stackcounter.stacks_counter > 1
  401. class UnboxedValue(object):
  402. """A mixin class to use for classes that have exactly one field which
  403. is an integer. They are represented as a tagged pointer, if the
  404. translation.taggedpointers config option is used."""
  405. _mixin_ = True
  406. def __new__(cls, value):
  407. assert '__init__' not in cls.__dict__ # won't be called anyway
  408. assert isinstance(cls.__slots__, str) or len(cls.__slots__) == 1
  409. return super(UnboxedValue, cls).__new__(cls)
  410. def __init__(self, value):
  411. # this funtion is annotated but not included in the translated program
  412. int_as_pointer = value * 2 + 1 # XXX for now
  413. if -sys.maxint-1 <= int_as_pointer <= sys.maxint:
  414. if isinstance(self.__class__.__slots__, str):
  415. setattr(self, self.__class__.__slots__, value)
  416. else:
  417. setattr(self, self.__class__.__slots__[0], value)
  418. else:
  419. raise OverflowError("UnboxedValue: argument out of range")
  420. def __repr__(self):
  421. return '<unboxed %d>' % (self.get_untagged_value(),)
  422. def get_untagged_value(self): # helper, equivalent to reading the custom field
  423. if isinstance(self.__class__.__slots__, str):
  424. return getattr(self, self.__class__.__slots__)
  425. else:
  426. return getattr(self, self.__class__.__slots__[0])
  427. # ____________________________________________________________
  428. class r_dict(object):
  429. """An RPython dict-like object.
  430. Only provides the interface supported by RPython.
  431. The functions key_eq() and key_hash() are used by the key comparison
  432. algorithm."""
  433. def __init__(self, key_eq, key_hash, force_non_null=False):
  434. self._dict = {}
  435. self.key_eq = key_eq
  436. self.key_hash = key_hash
  437. self.force_non_null = force_non_null
  438. def __getitem__(self, key):
  439. return self._dict[_r_dictkey(self, key)]
  440. def __setitem__(self, key, value):
  441. self._dict[_r_dictkey(self, key)] = value
  442. def __delitem__(self, key):
  443. del self._dict[_r_dictkey(self, key)]
  444. def __len__(self):
  445. return len(self._dict)
  446. def __iter__(self):
  447. for dk in self._dict:
  448. yield dk.key
  449. def __contains__(self, key):
  450. return _r_dictkey(self, key) in self._dict
  451. def get(self, key, default):
  452. return self._dict.get(_r_dictkey(self, key), default)
  453. def setdefault(self, key, default):
  454. return self._dict.setdefault(_r_dictkey(self, key), default)
  455. def popitem(self):
  456. dk, value = self._dict.popitem()
  457. return dk.key, value
  458. def copy(self):
  459. result = r_dict(self.key_eq, self.key_hash)
  460. result.update(self)
  461. return result
  462. def update(self, other):
  463. for key, value in other.items():
  464. self[key] = value
  465. def keys(self):
  466. return [dk.key for dk in self._dict]
  467. def values(self):
  468. return self._dict.values()
  469. def items(self):
  470. return [(dk.key, value) for dk, value in self._dict.items()]
  471. iterkeys = __iter__
  472. def itervalues(self):
  473. return self._dict.itervalues()
  474. def iteritems(self):
  475. for dk, value in self._dict.items():
  476. yield dk.key, value
  477. def clear(self):
  478. self._dict.clear()
  479. def __repr__(self):
  480. "Representation for debugging purposes."
  481. return 'r_dict(%r)' % (self._dict,)
  482. def __hash__(self):
  483. raise TypeError("cannot hash r_dict instances")
  484. class _r_dictkey(object):
  485. __slots__ = ['dic', 'key', 'hash']
  486. def __init__(self, dic, key):
  487. self.dic = dic
  488. self.key = key
  489. self.hash = dic.key_hash(key)
  490. def __eq__(self, other):
  491. if not isinstance(other, _r_dictkey):
  492. return NotImplemented
  493. return self.dic.key_eq(self.key, other.key)
  494. def __ne__(self, other):
  495. if not isinstance(other, _r_dictkey):
  496. return NotImplemented
  497. return not self.dic.key_eq(self.key, other.key)
  498. def __hash__(self):
  499. return self.hash
  500. def __repr__(self):
  501. return repr(self.key)
  502. class _r_dictkey_with_hash(_r_dictkey):
  503. def __init__(self, dic, key, hash):
  504. self.dic = dic
  505. self.key = key
  506. self.hash = hash