PageRenderTime 45ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/rlib/rgc.py

https://bitbucket.org/pypy/pypy/
Python | 1293 lines | 1091 code | 116 blank | 86 comment | 82 complexity | a07bb9df184acaba857f19faaf161806 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from __future__ import absolute_import
  2. import gc
  3. import types
  4. from rpython.rlib import jit
  5. from rpython.rlib.objectmodel import we_are_translated, enforceargs, specialize
  6. from rpython.rlib.objectmodel import CDefinedIntSymbolic
  7. from rpython.rtyper.extregistry import ExtRegistryEntry
  8. from rpython.rtyper.lltypesystem import lltype, llmemory
  9. # ____________________________________________________________
  10. # General GC features
  11. collect = gc.collect
  12. def set_max_heap_size(nbytes):
  13. """Limit the heap size to n bytes.
  14. """
  15. pass
  16. # for test purposes we allow objects to be pinned and use
  17. # the following list to keep track of the pinned objects
  18. _pinned_objects = []
  19. def pin(obj):
  20. """If 'obj' can move, then attempt to temporarily fix it. This
  21. function returns True if and only if 'obj' could be pinned; this is
  22. a special state in the GC. Note that can_move(obj) still returns
  23. True even on pinned objects, because once unpinned it will indeed be
  24. able to move again. In other words, the code that succeeded in
  25. pinning 'obj' can assume that it won't move until the corresponding
  26. call to unpin(obj), despite can_move(obj) still being True. (This
  27. is important if multiple threads try to os.write() the same string:
  28. only one of them will succeed in pinning the string.)
  29. It is expected that the time between pinning and unpinning an object
  30. is short. Therefore the expected use case is a single function
  31. invoking pin(obj) and unpin(obj) only a few lines of code apart.
  32. Note that this can return False for any reason, e.g. if the 'obj' is
  33. already non-movable or already pinned, if the GC doesn't support
  34. pinning, or if there are too many pinned objects.
  35. Note further that pinning an object does not prevent it from being
  36. collected if it is not used anymore.
  37. """
  38. _pinned_objects.append(obj)
  39. return True
  40. class PinEntry(ExtRegistryEntry):
  41. _about_ = pin
  42. def compute_result_annotation(self, s_obj):
  43. from rpython.annotator import model as annmodel
  44. return annmodel.SomeBool()
  45. def specialize_call(self, hop):
  46. hop.exception_cannot_occur()
  47. return hop.genop('gc_pin', hop.args_v, resulttype=hop.r_result)
  48. def unpin(obj):
  49. """Unpin 'obj', allowing it to move again.
  50. Must only be called after a call to pin(obj) returned True.
  51. """
  52. for i in range(len(_pinned_objects)):
  53. try:
  54. if _pinned_objects[i] == obj:
  55. del _pinned_objects[i]
  56. return
  57. except TypeError:
  58. pass
  59. class UnpinEntry(ExtRegistryEntry):
  60. _about_ = unpin
  61. def compute_result_annotation(self, s_obj):
  62. pass
  63. def specialize_call(self, hop):
  64. hop.exception_cannot_occur()
  65. hop.genop('gc_unpin', hop.args_v)
  66. def _is_pinned(obj):
  67. """Method to check if 'obj' is pinned."""
  68. for i in range(len(_pinned_objects)):
  69. try:
  70. if _pinned_objects[i] == obj:
  71. return True
  72. except TypeError:
  73. pass
  74. return False
  75. class IsPinnedEntry(ExtRegistryEntry):
  76. _about_ = _is_pinned
  77. def compute_result_annotation(self, s_obj):
  78. from rpython.annotator import model as annmodel
  79. return annmodel.SomeBool()
  80. def specialize_call(self, hop):
  81. hop.exception_cannot_occur()
  82. return hop.genop('gc__is_pinned', hop.args_v, resulttype=hop.r_result)
  83. # ____________________________________________________________
  84. # Annotation and specialization
  85. # Support for collection.
  86. class CollectEntry(ExtRegistryEntry):
  87. _about_ = gc.collect
  88. def compute_result_annotation(self, s_gen=None):
  89. from rpython.annotator import model as annmodel
  90. return annmodel.s_None
  91. def specialize_call(self, hop):
  92. hop.exception_cannot_occur()
  93. args_v = []
  94. if len(hop.args_s) == 1:
  95. args_v = hop.inputargs(lltype.Signed)
  96. return hop.genop('gc__collect', args_v, resulttype=hop.r_result)
  97. class SetMaxHeapSizeEntry(ExtRegistryEntry):
  98. _about_ = set_max_heap_size
  99. def compute_result_annotation(self, s_nbytes):
  100. from rpython.annotator import model as annmodel
  101. return annmodel.s_None
  102. def specialize_call(self, hop):
  103. [v_nbytes] = hop.inputargs(lltype.Signed)
  104. hop.exception_cannot_occur()
  105. return hop.genop('gc_set_max_heap_size', [v_nbytes],
  106. resulttype=lltype.Void)
  107. def can_move(p):
  108. """Check if the GC object 'p' is at an address that can move.
  109. Must not be called with None. With non-moving GCs, it is always False.
  110. With some moving GCs like the SemiSpace GC, it is always True.
  111. With other moving GCs like the MiniMark GC, it can be True for some
  112. time, then False for the same object, when we are sure that it won't
  113. move any more.
  114. """
  115. return True
  116. class CanMoveEntry(ExtRegistryEntry):
  117. _about_ = can_move
  118. def compute_result_annotation(self, s_p):
  119. from rpython.annotator import model as annmodel
  120. return annmodel.SomeBool()
  121. def specialize_call(self, hop):
  122. hop.exception_cannot_occur()
  123. return hop.genop('gc_can_move', hop.args_v, resulttype=hop.r_result)
  124. def _make_sure_does_not_move(p):
  125. """'p' is a non-null GC object. This (tries to) make sure that the
  126. object does not move any more, by forcing collections if needed.
  127. Warning: should ideally only be used with the minimark GC, and only
  128. on objects that are already a bit old, so have a chance to be
  129. already non-movable."""
  130. assert p
  131. if not we_are_translated():
  132. # for testing purpose
  133. return not _is_pinned(p)
  134. #
  135. if _is_pinned(p):
  136. # although a pinned object can't move we must return 'False'. A pinned
  137. # object can be unpinned any time and becomes movable.
  138. return False
  139. i = -1
  140. while can_move(p):
  141. if i > 6:
  142. raise NotImplementedError("can't make object non-movable!")
  143. collect(i)
  144. i += 1
  145. return True
  146. def needs_write_barrier(obj):
  147. """ We need to emit write barrier if the right hand of assignment
  148. is in nursery, used by the JIT for handling set*_gc(Const)
  149. """
  150. if not obj:
  151. return False
  152. # XXX returning can_move() here might acidentally work for the use
  153. # cases (see issue #2212), but this is not really safe. Now we
  154. # just return True for any non-NULL pointer, and too bad for the
  155. # few extra 'cond_call_gc_wb'. It could be improved e.g. to return
  156. # False if 'obj' is a static prebuilt constant, or if we're not
  157. # running incminimark...
  158. return True #can_move(obj)
  159. def _heap_stats():
  160. raise NotImplementedError # can't be run directly
  161. class DumpHeapEntry(ExtRegistryEntry):
  162. _about_ = _heap_stats
  163. def compute_result_annotation(self):
  164. from rpython.rtyper.llannotation import SomePtr
  165. from rpython.memory.gc.base import ARRAY_TYPEID_MAP
  166. return SomePtr(lltype.Ptr(ARRAY_TYPEID_MAP))
  167. def specialize_call(self, hop):
  168. hop.exception_is_here()
  169. return hop.genop('gc_heap_stats', [], resulttype=hop.r_result)
  170. def copy_struct_item(source, dest, si, di):
  171. TP = lltype.typeOf(source).TO.OF
  172. i = 0
  173. while i < len(TP._names):
  174. setattr(dest[di], TP._names[i], getattr(source[si], TP._names[i]))
  175. i += 1
  176. class CopyStructEntry(ExtRegistryEntry):
  177. _about_ = copy_struct_item
  178. def compute_result_annotation(self, s_source, s_dest, si, di):
  179. pass
  180. def specialize_call(self, hop):
  181. v_source, v_dest, v_si, v_di = hop.inputargs(hop.args_r[0],
  182. hop.args_r[1],
  183. lltype.Signed,
  184. lltype.Signed)
  185. hop.exception_cannot_occur()
  186. TP = v_source.concretetype.TO.OF
  187. for name, TP in TP._flds.iteritems():
  188. c_name = hop.inputconst(lltype.Void, name)
  189. v_fld = hop.genop('getinteriorfield', [v_source, v_si, c_name],
  190. resulttype=TP)
  191. hop.genop('setinteriorfield', [v_dest, v_di, c_name, v_fld])
  192. @specialize.ll()
  193. def copy_item(source, dest, si, di):
  194. TP = lltype.typeOf(source)
  195. if isinstance(TP.TO.OF, lltype.Struct):
  196. copy_struct_item(source, dest, si, di)
  197. else:
  198. dest[di] = source[si]
  199. @specialize.memo()
  200. def _contains_gcptr(TP):
  201. if not isinstance(TP, lltype.Struct):
  202. if isinstance(TP, lltype.Ptr) and TP.TO._gckind == 'gc':
  203. return True
  204. return False
  205. for TP in TP._flds.itervalues():
  206. if _contains_gcptr(TP):
  207. return True
  208. return False
  209. @jit.oopspec('list.ll_arraycopy(source, dest, source_start, dest_start, length)')
  210. @enforceargs(None, None, int, int, int)
  211. @specialize.ll()
  212. def ll_arraycopy(source, dest, source_start, dest_start, length):
  213. from rpython.rtyper.lltypesystem.lloperation import llop
  214. from rpython.rlib.objectmodel import keepalive_until_here
  215. # XXX: Hack to ensure that we get a proper effectinfo.write_descrs_arrays
  216. # and also, maybe, speed up very small cases
  217. if length <= 1:
  218. if length == 1:
  219. copy_item(source, dest, source_start, dest_start)
  220. return
  221. # supports non-overlapping copies only
  222. if not we_are_translated():
  223. if source == dest:
  224. assert (source_start + length <= dest_start or
  225. dest_start + length <= source_start)
  226. TP = lltype.typeOf(source).TO
  227. assert TP == lltype.typeOf(dest).TO
  228. if _contains_gcptr(TP.OF):
  229. # perform a write barrier that copies necessary flags from
  230. # source to dest
  231. if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest,
  232. source_start, dest_start,
  233. length):
  234. # if the write barrier is not supported, copy by hand
  235. i = 0
  236. while i < length:
  237. copy_item(source, dest, i + source_start, i + dest_start)
  238. i += 1
  239. return
  240. source_addr = llmemory.cast_ptr_to_adr(source)
  241. dest_addr = llmemory.cast_ptr_to_adr(dest)
  242. cp_source_addr = (source_addr + llmemory.itemoffsetof(TP, 0) +
  243. llmemory.sizeof(TP.OF) * source_start)
  244. cp_dest_addr = (dest_addr + llmemory.itemoffsetof(TP, 0) +
  245. llmemory.sizeof(TP.OF) * dest_start)
  246. llmemory.raw_memcopy(cp_source_addr, cp_dest_addr,
  247. llmemory.sizeof(TP.OF) * length)
  248. keepalive_until_here(source)
  249. keepalive_until_here(dest)
  250. @jit.oopspec('rgc.ll_shrink_array(p, smallerlength)')
  251. @enforceargs(None, int)
  252. @specialize.ll()
  253. def ll_shrink_array(p, smallerlength):
  254. from rpython.rtyper.lltypesystem.lloperation import llop
  255. from rpython.rlib.objectmodel import keepalive_until_here
  256. if llop.shrink_array(lltype.Bool, p, smallerlength):
  257. return p # done by the GC
  258. # XXX we assume for now that the type of p is GcStruct containing a
  259. # variable array, with no further pointers anywhere, and exactly one
  260. # field in the fixed part -- like STR and UNICODE.
  261. TP = lltype.typeOf(p).TO
  262. newp = lltype.malloc(TP, smallerlength)
  263. assert len(TP._names) == 2
  264. field = getattr(p, TP._names[0])
  265. setattr(newp, TP._names[0], field)
  266. ARRAY = getattr(TP, TP._arrayfld)
  267. offset = (llmemory.offsetof(TP, TP._arrayfld) +
  268. llmemory.itemoffsetof(ARRAY, 0))
  269. source_addr = llmemory.cast_ptr_to_adr(p) + offset
  270. dest_addr = llmemory.cast_ptr_to_adr(newp) + offset
  271. llmemory.raw_memcopy(source_addr, dest_addr,
  272. llmemory.sizeof(ARRAY.OF) * smallerlength)
  273. keepalive_until_here(p)
  274. keepalive_until_here(newp)
  275. return newp
  276. @jit.dont_look_inside
  277. @specialize.ll()
  278. def ll_arrayclear(p):
  279. # Equivalent to memset(array, 0). Only for GcArray(primitive-type) for now.
  280. from rpython.rlib.objectmodel import keepalive_until_here
  281. length = len(p)
  282. ARRAY = lltype.typeOf(p).TO
  283. offset = llmemory.itemoffsetof(ARRAY, 0)
  284. dest_addr = llmemory.cast_ptr_to_adr(p) + offset
  285. llmemory.raw_memclear(dest_addr, llmemory.sizeof(ARRAY.OF) * length)
  286. keepalive_until_here(p)
  287. def no_release_gil(func):
  288. func._dont_inline_ = True
  289. func._no_release_gil_ = True
  290. return func
  291. def no_collect(func):
  292. func._dont_inline_ = True
  293. func._gc_no_collect_ = True
  294. return func
  295. def must_be_light_finalizer(func):
  296. """Mark a __del__ method as being a destructor, calling only a limited
  297. set of operations. See pypy/doc/discussion/finalizer-order.rst.
  298. If you use the same decorator on a class, this class and all its
  299. subclasses are only allowed to have __del__ methods which are
  300. similarly decorated (or no __del__ at all). It prevents a class
  301. hierarchy from having destructors in some parent classes, which are
  302. overridden in subclasses with (non-light, old-style) finalizers.
  303. (This case is the original motivation for FinalizerQueue.)
  304. """
  305. func._must_be_light_finalizer_ = True
  306. return func
  307. class FinalizerQueue(object):
  308. """A finalizer queue. See pypy/doc/discussion/finalizer-order.rst.
  309. Note: only works with the framework GCs (like minimark). It is
  310. ignored with Boehm or with refcounting (used by tests).
  311. """
  312. # Must be subclassed, and the subclass needs these attributes:
  313. #
  314. # Class:
  315. # the class (or base class) of finalized objects
  316. #
  317. # def finalizer_trigger(self):
  318. # called to notify that new items have been put in the queue
  319. def _freeze_(self):
  320. return True
  321. @specialize.arg(0)
  322. @jit.dont_look_inside
  323. def next_dead(self):
  324. if we_are_translated():
  325. from rpython.rtyper.lltypesystem.lloperation import llop
  326. from rpython.rtyper.rclass import OBJECTPTR
  327. from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance
  328. tag = FinalizerQueue._get_tag(self)
  329. ptr = llop.gc_fq_next_dead(OBJECTPTR, tag)
  330. return cast_base_ptr_to_instance(self.Class, ptr)
  331. try:
  332. return self._queue.popleft()
  333. except (AttributeError, IndexError):
  334. return None
  335. @specialize.arg(0)
  336. @jit.dont_look_inside
  337. def register_finalizer(self, obj):
  338. assert isinstance(obj, self.Class)
  339. if we_are_translated():
  340. from rpython.rtyper.lltypesystem.lloperation import llop
  341. from rpython.rtyper.rclass import OBJECTPTR
  342. from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr
  343. tag = FinalizerQueue._get_tag(self)
  344. ptr = cast_instance_to_base_ptr(obj)
  345. llop.gc_fq_register(lltype.Void, tag, ptr)
  346. return
  347. else:
  348. self._untranslated_register_finalizer(obj)
  349. def _get_tag(self):
  350. "NOT_RPYTHON: special-cased below"
  351. def _reset(self):
  352. import collections
  353. self._weakrefs = set()
  354. self._queue = collections.deque()
  355. def _already_registered(self, obj):
  356. return hasattr(obj, '__enable_del_for_id')
  357. def _untranslated_register_finalizer(self, obj):
  358. assert not self._already_registered(obj)
  359. if not hasattr(self, '_queue'):
  360. self._reset()
  361. # Fetch and check the type of 'obj'
  362. objtyp = obj.__class__
  363. assert isinstance(objtyp, type), (
  364. "%r: to run register_finalizer() untranslated, "
  365. "the object's class must be new-style" % (obj,))
  366. assert hasattr(obj, '__dict__'), (
  367. "%r: to run register_finalizer() untranslated, "
  368. "the object must have a __dict__" % (obj,))
  369. assert (not hasattr(obj, '__slots__') or
  370. type(obj).__slots__ == () or
  371. type(obj).__slots__ == ('__weakref__',)), (
  372. "%r: to run register_finalizer() untranslated, "
  373. "the object must not have __slots__" % (obj,))
  374. # The first time, patch the method __del__ of the class, if
  375. # any, so that we can disable it on the original 'obj' and
  376. # enable it only on the 'newobj'
  377. _fq_patch_class(objtyp)
  378. # Build a new shadow object with the same class and dict
  379. newobj = object.__new__(objtyp)
  380. obj.__dict__ = obj.__dict__.copy() #PyPy: break the dict->obj dependency
  381. newobj.__dict__ = obj.__dict__
  382. # A callback that is invoked when (or after) 'obj' is deleted;
  383. # 'newobj' is still kept alive here
  384. def callback(wr):
  385. self._weakrefs.discard(wr)
  386. self._queue.append(newobj)
  387. self.finalizer_trigger()
  388. import weakref
  389. wr = weakref.ref(obj, callback)
  390. self._weakrefs.add(wr)
  391. # Disable __del__ on the original 'obj' and enable it only on
  392. # the 'newobj'. Use id() and not a regular reference, because
  393. # that would make a cycle between 'newobj' and 'obj.__dict__'
  394. # (which is 'newobj.__dict__' too).
  395. setattr(obj, '__enable_del_for_id', id(newobj))
  396. def _fq_patch_class(Cls):
  397. if Cls in _fq_patched_classes:
  398. return
  399. if '__del__' in Cls.__dict__:
  400. def __del__(self):
  401. if not we_are_translated():
  402. try:
  403. if getattr(self, '__enable_del_for_id') != id(self):
  404. return
  405. except AttributeError:
  406. pass
  407. original_del(self)
  408. original_del = Cls.__del__
  409. Cls.__del__ = __del__
  410. _fq_patched_classes.add(Cls)
  411. for BaseCls in Cls.__bases__:
  412. _fq_patch_class(BaseCls)
  413. _fq_patched_classes = set()
  414. class FqTagEntry(ExtRegistryEntry):
  415. _about_ = FinalizerQueue._get_tag.im_func
  416. def compute_result_annotation(self, s_fq):
  417. assert s_fq.is_constant()
  418. fq = s_fq.const
  419. s_func = self.bookkeeper.immutablevalue(fq.finalizer_trigger)
  420. self.bookkeeper.emulate_pbc_call(self.bookkeeper.position_key,
  421. s_func, [])
  422. if not hasattr(fq, '_fq_tag'):
  423. fq._fq_tag = CDefinedIntSymbolic(
  424. '0 /*FinalizerQueue TAG for %s*/' % fq.__class__.__name__,
  425. default=fq)
  426. return self.bookkeeper.immutablevalue(fq._fq_tag)
  427. def specialize_call(self, hop):
  428. from rpython.rtyper.rclass import InstanceRepr
  429. translator = hop.rtyper.annotator.translator
  430. fq = hop.args_s[0].const
  431. graph = translator._graphof(fq.finalizer_trigger.im_func)
  432. InstanceRepr.check_graph_of_del_does_not_call_too_much(hop.rtyper,
  433. graph)
  434. hop.exception_cannot_occur()
  435. return hop.inputconst(lltype.Signed, hop.s_result.const)
  436. # ____________________________________________________________
  437. def get_rpy_roots():
  438. "NOT_RPYTHON"
  439. # Return the 'roots' from the GC.
  440. # The gc typically returns a list that ends with a few NULL_GCREFs.
  441. return [_GcRef(x) for x in gc.get_objects()]
  442. def get_rpy_referents(gcref):
  443. "NOT_RPYTHON"
  444. x = gcref._x
  445. if isinstance(x, list):
  446. d = x
  447. elif isinstance(x, dict):
  448. d = x.keys() + x.values()
  449. else:
  450. d = []
  451. if hasattr(x, '__dict__'):
  452. d = x.__dict__.values()
  453. if hasattr(type(x), '__slots__'):
  454. for slot in type(x).__slots__:
  455. try:
  456. d.append(getattr(x, slot))
  457. except AttributeError:
  458. pass
  459. # discard objects that are too random or that are _freeze_=True
  460. return [_GcRef(x) for x in d if _keep_object(x)]
  461. def _keep_object(x):
  462. if isinstance(x, type) or type(x) is types.ClassType:
  463. return False # don't keep any type
  464. if isinstance(x, (list, dict, str)):
  465. return True # keep lists and dicts and strings
  466. if hasattr(x, '_freeze_'):
  467. return False
  468. return type(x).__module__ != '__builtin__' # keep non-builtins
  469. def add_memory_pressure(estimate):
  470. """Add memory pressure for OpaquePtrs."""
  471. pass
  472. class AddMemoryPressureEntry(ExtRegistryEntry):
  473. _about_ = add_memory_pressure
  474. def compute_result_annotation(self, s_nbytes):
  475. from rpython.annotator import model as annmodel
  476. return annmodel.s_None
  477. def specialize_call(self, hop):
  478. [v_size] = hop.inputargs(lltype.Signed)
  479. hop.exception_cannot_occur()
  480. return hop.genop('gc_add_memory_pressure', [v_size],
  481. resulttype=lltype.Void)
  482. def get_rpy_memory_usage(gcref):
  483. "NOT_RPYTHON"
  484. # approximate implementation using CPython's type info
  485. Class = type(gcref._x)
  486. size = Class.__basicsize__
  487. if Class.__itemsize__ > 0:
  488. size += Class.__itemsize__ * len(gcref._x)
  489. return size
  490. def get_rpy_type_index(gcref):
  491. "NOT_RPYTHON"
  492. from rpython.rlib.rarithmetic import intmask
  493. Class = gcref._x.__class__
  494. return intmask(id(Class))
  495. def cast_gcref_to_int(gcref):
  496. # This is meant to be used on cast_instance_to_gcref results.
  497. # Don't use this on regular gcrefs obtained e.g. with
  498. # lltype.cast_opaque_ptr().
  499. if we_are_translated():
  500. return lltype.cast_ptr_to_int(gcref)
  501. else:
  502. return id(gcref._x)
  503. def dump_rpy_heap(fd):
  504. "NOT_RPYTHON"
  505. raise NotImplementedError
  506. def get_typeids_z():
  507. "NOT_RPYTHON"
  508. raise NotImplementedError
  509. def get_typeids_list():
  510. "NOT_RPYTHON"
  511. raise NotImplementedError
  512. def has_gcflag_extra():
  513. "NOT_RPYTHON"
  514. return True
  515. has_gcflag_extra._subopnum = 1
  516. _gcflag_extras = set()
  517. def get_gcflag_extra(gcref):
  518. "NOT_RPYTHON"
  519. assert gcref # not NULL!
  520. return gcref in _gcflag_extras
  521. get_gcflag_extra._subopnum = 2
  522. def toggle_gcflag_extra(gcref):
  523. "NOT_RPYTHON"
  524. assert gcref # not NULL!
  525. try:
  526. _gcflag_extras.remove(gcref)
  527. except KeyError:
  528. _gcflag_extras.add(gcref)
  529. toggle_gcflag_extra._subopnum = 3
  530. def assert_no_more_gcflags():
  531. if not we_are_translated():
  532. assert not _gcflag_extras
  533. ARRAY_OF_CHAR = lltype.Array(lltype.Char)
  534. NULL_GCREF = lltype.nullptr(llmemory.GCREF.TO)
  535. class _GcRef(object):
  536. # implementation-specific: there should not be any after translation
  537. __slots__ = ['_x', '_handle']
  538. _TYPE = llmemory.GCREF
  539. def __init__(self, x):
  540. self._x = x
  541. def __hash__(self):
  542. return object.__hash__(self._x)
  543. def __eq__(self, other):
  544. if isinstance(other, lltype._ptr):
  545. assert other == NULL_GCREF, (
  546. "comparing a _GcRef with a non-NULL lltype ptr")
  547. return False
  548. assert isinstance(other, _GcRef)
  549. return self._x is other._x
  550. def __ne__(self, other):
  551. return not self.__eq__(other)
  552. def __repr__(self):
  553. return "_GcRef(%r)" % (self._x, )
  554. def _freeze_(self):
  555. raise Exception("instances of rlib.rgc._GcRef cannot be translated")
  556. def cast_instance_to_gcref(x):
  557. # Before translation, casts an RPython instance into a _GcRef.
  558. # After translation, it is a variant of cast_object_to_ptr(GCREF).
  559. if we_are_translated():
  560. from rpython.rtyper import annlowlevel
  561. x = annlowlevel.cast_instance_to_base_ptr(x)
  562. return lltype.cast_opaque_ptr(llmemory.GCREF, x)
  563. else:
  564. return _GcRef(x)
  565. cast_instance_to_gcref._annspecialcase_ = 'specialize:argtype(0)'
  566. def try_cast_gcref_to_instance(Class, gcref):
  567. # Before translation, unwraps the RPython instance contained in a _GcRef.
  568. # After translation, it is a type-check performed by the GC.
  569. if we_are_translated():
  570. from rpython.rtyper.rclass import OBJECTPTR, ll_isinstance
  571. from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance
  572. if _is_rpy_instance(gcref):
  573. objptr = lltype.cast_opaque_ptr(OBJECTPTR, gcref)
  574. if objptr.typeptr: # may be NULL, e.g. in rdict's dummykeyobj
  575. clsptr = _get_llcls_from_cls(Class)
  576. if ll_isinstance(objptr, clsptr):
  577. return cast_base_ptr_to_instance(Class, objptr)
  578. return None
  579. else:
  580. if isinstance(gcref._x, Class):
  581. return gcref._x
  582. return None
  583. try_cast_gcref_to_instance._annspecialcase_ = 'specialize:arg(0)'
  584. _ffi_cache = None
  585. def _fetch_ffi():
  586. global _ffi_cache
  587. if _ffi_cache is None:
  588. try:
  589. import _cffi_backend
  590. _ffi_cache = _cffi_backend.FFI()
  591. except (ImportError, AttributeError):
  592. import py
  593. py.test.skip("need CFFI >= 1.0")
  594. return _ffi_cache
  595. @jit.dont_look_inside
  596. def hide_nonmovable_gcref(gcref):
  597. from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
  598. if we_are_translated():
  599. assert lltype.typeOf(gcref) == llmemory.GCREF
  600. assert not can_move(gcref)
  601. return rffi.cast(llmemory.Address, gcref)
  602. else:
  603. assert isinstance(gcref, _GcRef)
  604. x = gcref._x
  605. ffi = _fetch_ffi()
  606. if not hasattr(x, '__handle'):
  607. x.__handle = ffi.new_handle(x)
  608. addr = int(ffi.cast("intptr_t", x.__handle))
  609. return rffi.cast(llmemory.Address, addr)
  610. @jit.dont_look_inside
  611. def reveal_gcref(addr):
  612. from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
  613. assert lltype.typeOf(addr) == llmemory.Address
  614. if we_are_translated():
  615. return rffi.cast(llmemory.GCREF, addr)
  616. else:
  617. addr = rffi.cast(lltype.Signed, addr)
  618. if addr == 0:
  619. return lltype.nullptr(llmemory.GCREF.TO)
  620. ffi = _fetch_ffi()
  621. x = ffi.from_handle(ffi.cast("void *", addr))
  622. return _GcRef(x)
  623. # ------------------- implementation -------------------
  624. _cache_s_list_of_gcrefs = None
  625. def s_list_of_gcrefs():
  626. global _cache_s_list_of_gcrefs
  627. if _cache_s_list_of_gcrefs is None:
  628. from rpython.annotator import model as annmodel
  629. from rpython.rtyper.llannotation import SomePtr
  630. from rpython.annotator.listdef import ListDef
  631. s_gcref = SomePtr(llmemory.GCREF)
  632. _cache_s_list_of_gcrefs = annmodel.SomeList(
  633. ListDef(None, s_gcref, mutated=True, resized=False))
  634. return _cache_s_list_of_gcrefs
  635. class Entry(ExtRegistryEntry):
  636. _about_ = get_rpy_roots
  637. def compute_result_annotation(self):
  638. return s_list_of_gcrefs()
  639. def specialize_call(self, hop):
  640. hop.exception_cannot_occur()
  641. return hop.genop('gc_get_rpy_roots', [], resulttype = hop.r_result)
  642. class Entry(ExtRegistryEntry):
  643. _about_ = get_rpy_referents
  644. def compute_result_annotation(self, s_gcref):
  645. from rpython.rtyper.llannotation import SomePtr
  646. assert SomePtr(llmemory.GCREF).contains(s_gcref)
  647. return s_list_of_gcrefs()
  648. def specialize_call(self, hop):
  649. vlist = hop.inputargs(hop.args_r[0])
  650. hop.exception_cannot_occur()
  651. return hop.genop('gc_get_rpy_referents', vlist,
  652. resulttype=hop.r_result)
  653. class Entry(ExtRegistryEntry):
  654. _about_ = get_rpy_memory_usage
  655. def compute_result_annotation(self, s_gcref):
  656. from rpython.annotator import model as annmodel
  657. return annmodel.SomeInteger()
  658. def specialize_call(self, hop):
  659. vlist = hop.inputargs(hop.args_r[0])
  660. hop.exception_cannot_occur()
  661. return hop.genop('gc_get_rpy_memory_usage', vlist,
  662. resulttype = hop.r_result)
  663. class Entry(ExtRegistryEntry):
  664. _about_ = get_rpy_type_index
  665. def compute_result_annotation(self, s_gcref):
  666. from rpython.annotator import model as annmodel
  667. return annmodel.SomeInteger()
  668. def specialize_call(self, hop):
  669. vlist = hop.inputargs(hop.args_r[0])
  670. hop.exception_cannot_occur()
  671. return hop.genop('gc_get_rpy_type_index', vlist,
  672. resulttype = hop.r_result)
  673. def _is_rpy_instance(gcref):
  674. "NOT_RPYTHON"
  675. raise NotImplementedError
  676. def _get_llcls_from_cls(Class):
  677. "NOT_RPYTHON"
  678. raise NotImplementedError
  679. class Entry(ExtRegistryEntry):
  680. _about_ = _is_rpy_instance
  681. def compute_result_annotation(self, s_gcref):
  682. from rpython.annotator import model as annmodel
  683. return annmodel.SomeBool()
  684. def specialize_call(self, hop):
  685. vlist = hop.inputargs(hop.args_r[0])
  686. hop.exception_cannot_occur()
  687. return hop.genop('gc_is_rpy_instance', vlist,
  688. resulttype = hop.r_result)
  689. class Entry(ExtRegistryEntry):
  690. _about_ = _get_llcls_from_cls
  691. def compute_result_annotation(self, s_Class):
  692. from rpython.rtyper.llannotation import SomePtr
  693. from rpython.rtyper.rclass import CLASSTYPE
  694. assert s_Class.is_constant()
  695. return SomePtr(CLASSTYPE)
  696. def specialize_call(self, hop):
  697. from rpython.rtyper.rclass import getclassrepr, CLASSTYPE
  698. from rpython.flowspace.model import Constant
  699. Class = hop.args_s[0].const
  700. classdef = hop.rtyper.annotator.bookkeeper.getuniqueclassdef(Class)
  701. classrepr = getclassrepr(hop.rtyper, classdef)
  702. vtable = classrepr.getvtable()
  703. assert lltype.typeOf(vtable) == CLASSTYPE
  704. hop.exception_cannot_occur()
  705. return Constant(vtable, concretetype=CLASSTYPE)
  706. class Entry(ExtRegistryEntry):
  707. _about_ = dump_rpy_heap
  708. def compute_result_annotation(self, s_fd):
  709. from rpython.annotator.model import s_Bool
  710. return s_Bool
  711. def specialize_call(self, hop):
  712. vlist = hop.inputargs(lltype.Signed)
  713. hop.exception_is_here()
  714. return hop.genop('gc_dump_rpy_heap', vlist, resulttype = hop.r_result)
  715. class Entry(ExtRegistryEntry):
  716. _about_ = get_typeids_z
  717. def compute_result_annotation(self):
  718. from rpython.rtyper.llannotation import SomePtr
  719. return SomePtr(lltype.Ptr(ARRAY_OF_CHAR))
  720. def specialize_call(self, hop):
  721. hop.exception_is_here()
  722. return hop.genop('gc_typeids_z', [], resulttype = hop.r_result)
  723. class Entry(ExtRegistryEntry):
  724. _about_ = get_typeids_list
  725. def compute_result_annotation(self):
  726. from rpython.rtyper.llannotation import SomePtr
  727. from rpython.rtyper.lltypesystem import llgroup
  728. return SomePtr(lltype.Ptr(lltype.Array(llgroup.HALFWORD)))
  729. def specialize_call(self, hop):
  730. hop.exception_is_here()
  731. return hop.genop('gc_typeids_list', [], resulttype = hop.r_result)
  732. class Entry(ExtRegistryEntry):
  733. _about_ = (has_gcflag_extra, get_gcflag_extra, toggle_gcflag_extra)
  734. def compute_result_annotation(self, s_arg=None):
  735. from rpython.annotator.model import s_Bool
  736. return s_Bool
  737. def specialize_call(self, hop):
  738. subopnum = self.instance._subopnum
  739. vlist = [hop.inputconst(lltype.Signed, subopnum)]
  740. vlist += hop.inputargs(*hop.args_r)
  741. hop.exception_cannot_occur()
  742. return hop.genop('gc_gcflag_extra', vlist, resulttype = hop.r_result)
  743. def lltype_is_gc(TP):
  744. return getattr(getattr(TP, "TO", None), "_gckind", "?") == 'gc'
  745. def register_custom_trace_hook(TP, lambda_func):
  746. """ This function does not do anything, but called from any annotated
  747. place, will tell that "func" is used to trace GC roots inside any instance
  748. of the type TP. The func must be specified as "lambda: func" in this
  749. call, for internal reasons. Note that the func will be automatically
  750. specialized on the 'callback' argument value. Example:
  751. def customtrace(gc, obj, callback, arg):
  752. gc._trace_callback(callback, arg, obj + offset_of_x)
  753. lambda_customtrace = lambda: customtrace
  754. """
  755. @specialize.ll()
  756. def ll_writebarrier(gc_obj):
  757. """Use together with custom tracers. When you update some object pointer
  758. stored in raw memory, you must call this function on 'gc_obj', which must
  759. be the object of type TP with the custom tracer (*not* the value stored!).
  760. This makes sure that the custom hook will be called again."""
  761. from rpython.rtyper.lltypesystem.lloperation import llop
  762. llop.gc_writebarrier(lltype.Void, gc_obj)
  763. class RegisterGcTraceEntry(ExtRegistryEntry):
  764. _about_ = register_custom_trace_hook
  765. def compute_result_annotation(self, s_tp, s_lambda_func):
  766. pass
  767. def specialize_call(self, hop):
  768. TP = hop.args_s[0].const
  769. lambda_func = hop.args_s[1].const
  770. hop.exception_cannot_occur()
  771. hop.rtyper.custom_trace_funcs.append((TP, lambda_func()))
  772. def register_custom_light_finalizer(TP, lambda_func):
  773. """ This function does not do anything, but called from any annotated
  774. place, will tell that "func" is used as a lightweight finalizer for TP.
  775. The func must be specified as "lambda: func" in this call, for internal
  776. reasons.
  777. """
  778. @specialize.arg(0)
  779. def do_get_objects(callback):
  780. """ Get all the objects that satisfy callback(gcref) -> obj
  781. """
  782. roots = get_rpy_roots()
  783. if not roots: # is always None on translations using Boehm or None GCs
  784. return []
  785. roots = [gcref for gcref in roots if gcref]
  786. result_w = []
  787. #
  788. if not we_are_translated(): # fast path before translation
  789. seen = set()
  790. while roots:
  791. gcref = roots.pop()
  792. if gcref not in seen:
  793. seen.add(gcref)
  794. w_obj = callback(gcref)
  795. if w_obj is not None:
  796. result_w.append(w_obj)
  797. roots.extend(get_rpy_referents(gcref))
  798. return result_w
  799. #
  800. pending = roots[:]
  801. while pending:
  802. gcref = pending.pop()
  803. if not get_gcflag_extra(gcref):
  804. toggle_gcflag_extra(gcref)
  805. w_obj = callback(gcref)
  806. if w_obj is not None:
  807. result_w.append(w_obj)
  808. pending.extend(get_rpy_referents(gcref))
  809. clear_gcflag_extra(roots)
  810. assert_no_more_gcflags()
  811. return result_w
  812. class RegisterCustomLightFinalizer(ExtRegistryEntry):
  813. _about_ = register_custom_light_finalizer
  814. def compute_result_annotation(self, s_tp, s_lambda_func):
  815. pass
  816. def specialize_call(self, hop):
  817. from rpython.rtyper.llannotation import SomePtr
  818. TP = hop.args_s[0].const
  819. lambda_func = hop.args_s[1].const
  820. ll_func = lambda_func()
  821. args_s = [SomePtr(lltype.Ptr(TP))]
  822. funcptr = hop.rtyper.annotate_helper_fn(ll_func, args_s)
  823. hop.exception_cannot_occur()
  824. lltype.attachRuntimeTypeInfo(TP, destrptr=funcptr)
  825. def clear_gcflag_extra(fromlist):
  826. pending = fromlist[:]
  827. while pending:
  828. gcref = pending.pop()
  829. if get_gcflag_extra(gcref):
  830. toggle_gcflag_extra(gcref)
  831. pending.extend(get_rpy_referents(gcref))
  832. all_typeids = {}
  833. def get_typeid(obj):
  834. raise Exception("does not work untranslated")
  835. class GetTypeidEntry(ExtRegistryEntry):
  836. _about_ = get_typeid
  837. def compute_result_annotation(self, s_obj):
  838. from rpython.annotator import model as annmodel
  839. return annmodel.SomeInteger()
  840. def specialize_call(self, hop):
  841. hop.exception_cannot_occur()
  842. return hop.genop('gc_gettypeid', hop.args_v, resulttype=lltype.Signed)
  843. # ____________________________________________________________
  844. class _rawptr_missing_item(object):
  845. pass
  846. _rawptr_missing_item = _rawptr_missing_item()
  847. class _ResizableListSupportingRawPtr(list):
  848. """Calling this class is a no-op after translation.
  849. Before translation, it returns a new instance of
  850. _ResizableListSupportingRawPtr, on which
  851. rgc.nonmoving_raw_ptr_for_resizable_list() might be
  852. used if needed. For now, only supports lists of chars.
  853. """
  854. __slots__ = ('_raw_items',) # either None or a rffi.CCHARP
  855. def __init__(self, lst):
  856. self._raw_items = None
  857. self.__from_list(lst)
  858. def __resize(self):
  859. """Called before an operation changes the size of the list"""
  860. if self._raw_items is not None:
  861. list.__init__(self, self.__as_list())
  862. self._raw_items = None
  863. def __from_list(self, lst):
  864. """Initialize the list from a copy of the list 'lst'."""
  865. assert isinstance(lst, list)
  866. for x in lst:
  867. assert isinstance(x, str) and len(x) == 1
  868. if self is lst:
  869. return
  870. if len(self) != len(lst):
  871. self.__resize()
  872. if self._raw_items is None:
  873. list.__init__(self, lst)
  874. else:
  875. assert len(self) == self._raw_items._obj.getlength() == len(lst)
  876. for i in range(len(self)):
  877. self._raw_items[i] = lst[i]
  878. def __as_list(self):
  879. """Return a list (the same or a different one) which contains the
  880. items in the regular way."""
  881. if self._raw_items is None:
  882. return self
  883. length = self._raw_items._obj.getlength()
  884. assert length == len(self)
  885. return [self._raw_items[i] for i in range(length)]
  886. def __getitem__(self, index):
  887. if self._raw_items is None:
  888. return list.__getitem__(self, index)
  889. if index < 0:
  890. index += len(self)
  891. if not (0 <= index < len(self)):
  892. raise IndexError
  893. return self._raw_items[index]
  894. def __setitem__(self, index, new):
  895. if self._raw_items is None:
  896. return list.__setitem__(self, index, new)
  897. if index < 0:
  898. index += len(self)
  899. if not (0 <= index < len(self)):
  900. raise IndexError
  901. self._raw_items[index] = new
  902. def __delitem__(self, index):
  903. self.__resize()
  904. list.__delitem__(self, index)
  905. def __getslice__(self, i, j):
  906. return list.__getslice__(self.__as_list(), i, j)
  907. def __setslice__(self, i, j, new):
  908. lst = self.__as_list()
  909. list.__setslice__(lst, i, j, new)
  910. self.__from_list(lst)
  911. def __delslice__(self, i, j):
  912. lst = self.__as_list()
  913. list.__delslice__(lst, i, j)
  914. self.__from_list(lst)
  915. def __iter__(self):
  916. try:
  917. i = 0
  918. while True:
  919. yield self[i]
  920. i += 1
  921. except IndexError:
  922. pass
  923. def __reversed__(self):
  924. i = len(self)
  925. while i > 0:
  926. i -= 1
  927. yield self[i]
  928. def __contains__(self, item):
  929. return list.__contains__(self.__as_list(), item)
  930. def __add__(self, other):
  931. if isinstance(other, _ResizableListSupportingRawPtr):
  932. other = other.__as_list()
  933. return list.__add__(self.__as_list(), other)
  934. def __radd__(self, other):
  935. if isinstance(other, _ResizableListSupportingRawPtr):
  936. other = other.__as_list()
  937. return list.__add__(other, self.__as_list())
  938. def __iadd__(self, other):
  939. self.__resize()
  940. return list.__iadd__(self, other)
  941. def __eq__(self, other):
  942. return list.__eq__(self.__as_list(), other)
  943. def __ne__(self, other):
  944. return list.__ne__(self.__as_list(), other)
  945. def __ge__(self, other):
  946. return list.__ge__(self.__as_list(), other)
  947. def __gt__(self, other):
  948. return list.__gt__(self.__as_list(), other)
  949. def __le__(self, other):
  950. return list.__le__(self.__as_list(), other)
  951. def __lt__(self, other):
  952. return list.__lt__(self.__as_list(), other)
  953. def __mul__(self, other):
  954. return list.__mul__(self.__as_list(), other)
  955. def __rmul__(self, other):
  956. return list.__mul__(self.__as_list(), other)
  957. def __imul__(self, other):
  958. self.__resize()
  959. return list.__imul__(self, other)
  960. def __repr__(self):
  961. return '_ResizableListSupportingRawPtr(%s)' % (
  962. list.__repr__(self.__as_list()),)
  963. def append(self, object):
  964. self.__resize()
  965. return list.append(self, object)
  966. def count(self, value):
  967. return list.count(self.__as_list(), value)
  968. def extend(self, iterable):
  969. self.__resize()
  970. return list.extend(self, iterable)
  971. def index(self, value, *start_stop):
  972. return list.index(self.__as_list(), value, *start_stop)
  973. def insert(self, index, object):
  974. self.__resize()
  975. return list.insert(self, index, object)
  976. def pop(self, *opt_index):
  977. self.__resize()
  978. return list.pop(self, *opt_index)
  979. def remove(self, value):
  980. self.__resize()
  981. return list.remove(self, value)
  982. def reverse(self):
  983. lst = self.__as_list()
  984. list.reverse(lst)
  985. self.__from_list(lst)
  986. def sort(self, *args, **kwds):
  987. lst = self.__as_list()
  988. list.sort(lst, *args, **kwds)
  989. self.__from_list(lst)
  990. def _nonmoving_raw_ptr_for_resizable_list(self):
  991. if self._raw_items is None:
  992. existing_items = list(self)
  993. from rpython.rtyper.lltypesystem import lltype, rffi
  994. self._raw_items = lltype.malloc(rffi.CCHARP.TO, len(self),
  995. flavor='raw', immortal=True)
  996. self.__from_list(existing_items)
  997. assert self._raw_items is not None
  998. return self._raw_items
  999. def resizable_list_supporting_raw_ptr(lst):
  1000. return _ResizableListSupportingRawPtr(lst)
  1001. def nonmoving_raw_ptr_for_resizable_list(lst):
  1002. assert isinstance(lst, _ResizableListSupportingRawPtr)
  1003. return lst._nonmoving_raw_ptr_for_resizable_list()
  1004. def _check_resizable_list_of_chars(s_list):
  1005. from rpython.annotator import model as annmodel
  1006. from rpython.rlib import debug
  1007. if annmodel.s_None.contains(s_list):
  1008. return # "None", will likely be generalized later
  1009. if not isinstance(s_list, annmodel.SomeList):
  1010. raise Exception("not a list, got %r" % (s_list,))
  1011. if not isinstance(s_list.listdef.listitem.s_value,
  1012. (annmodel.SomeChar, annmodel.SomeImpossibleValue)):
  1013. raise debug.NotAListOfChars
  1014. s_list.listdef.resize() # must be resizable
  1015. class Entry(ExtRegistryEntry):
  1016. _about_ = resizable_list_supporting_raw_ptr
  1017. def compute_result_annotation(self, s_list):
  1018. _check_resizable_list_of_chars(s_list)
  1019. return s_list
  1020. def specialize_call(self, hop):
  1021. hop.exception_cannot_occur()
  1022. return hop.inputarg(hop.args_r[0], 0)
  1023. class Entry(ExtRegistryEntry):
  1024. _about_ = nonmoving_raw_ptr_for_resizable_list
  1025. def compute_result_annotation(self, s_list):
  1026. from rpython.rtyper.lltypesystem import lltype, rffi
  1027. from rpython.rtyper.llannotation import SomePtr
  1028. _check_resizable_list_of_chars(s_list)
  1029. return SomePtr(rffi.CCHARP)
  1030. def specialize_call(self, hop):
  1031. v_list = hop.inputarg(hop.args_r[0], 0)
  1032. hop.exception_cannot_occur() # ignoring MemoryError
  1033. return hop.gendirectcall(ll_nonmovable_raw_ptr_for_resizable_list,
  1034. v_list)
  1035. @jit.dont_look_inside
  1036. def ll_nonmovable_raw_ptr_for_resizable_list(ll_list):
  1037. """
  1038. WARNING: dragons ahead.
  1039. Return the address of the internal char* buffer of 'll_list', which
  1040. must be a resizable list of chars.
  1041. This makes sure that the list items are non-moving, if necessary by
  1042. first copying the GcArray inside 'll_list.items' outside the GC
  1043. nursery. The returned 'char *' pointer is guaranteed to be valid
  1044. until one of these occurs:
  1045. * 'll_list' gets garbage-collected; or
  1046. * you do an operation on 'll_list' that changes its size.
  1047. """
  1048. from rpython.rtyper.lltypesystem import lltype, rffi
  1049. array = ll_list.items
  1050. if can_move(array):
  1051. length = ll_list.length
  1052. new_array = lltype.malloc(lltype.typeOf(ll_list).TO.items.TO, length,
  1053. nonmovable=True)
  1054. ll_arraycopy(array, new_array, 0, 0, length)
  1055. ll_list.items = new_array
  1056. array = new_array
  1057. ptr = lltype.direct_arrayitems(array)
  1058. # ptr is a Ptr(FixedSizeArray(Char, 1)). Cast it to a rffi.CCHARP
  1059. return rffi.cast(rffi.CCHARP, ptr)
  1060. @jit.dont_look_inside
  1061. @no_collect
  1062. @specialize.ll()
  1063. def ll_write_final_null_char(s):
  1064. """'s' is a low-level STR; writes a terminating NULL character after
  1065. the other characters in 's'. Warning, this only works because of
  1066. the 'extra_item_after_alloc' hack inside the definition of STR.
  1067. """
  1068. from rpython.rtyper.lltypesystem import rffi
  1069. PSTR = lltype.typeOf(s)
  1070. assert has_final_null_char(PSTR) == 1
  1071. n = llmemory.offsetof(PSTR.TO, 'chars')
  1072. n += llmemory.itemoffsetof(PSTR.TO.chars, 0)
  1073. n = llmemory.raw_malloc_usage(n)
  1074. n += len(s.chars)
  1075. # no GC operation from here!
  1076. ptr = rffi.cast(rffi.CCHARP, s)
  1077. ptr[n] = '\x00'
  1078. @specialize.memo()
  1079. def has_final_null_char(PSTR):
  1080. return PSTR.TO.chars._hints.get('extra_item_after_alloc', 0)