PageRenderTime 51ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/rtyper/lltypesystem/llmemory.py

https://bitbucket.org/pypy/pypy/
Python | 1073 lines | 976 code | 75 blank | 22 comment | 61 complexity | f5fbfeae0d516be8d68d243239540a70 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. # this file contains the definitions and most extremely faked
  2. # implementations of things relating to the description of the layout
  3. # of objects in memeory.
  4. # sizeof, offsetof
  5. import weakref
  6. from rpython.annotator.bookkeeper import analyzer_for
  7. from rpython.annotator.model import SomeInteger, SomeObject, SomeString, s_Bool
  8. from rpython.rlib.objectmodel import Symbolic, specialize
  9. from rpython.rtyper.lltypesystem import lltype
  10. from rpython.rtyper.lltypesystem.lltype import SomePtr
  11. from rpython.tool.uid import uid
  12. from rpython.rlib.rarithmetic import is_valid_int
  13. from rpython.rtyper.extregistry import ExtRegistryEntry
  14. class AddressOffset(Symbolic):
  15. def annotation(self):
  16. from rpython.annotator import model
  17. return model.SomeInteger()
  18. def lltype(self):
  19. return lltype.Signed
  20. def __add__(self, other):
  21. if not isinstance(other, AddressOffset):
  22. return NotImplemented
  23. return CompositeOffset(self, other)
  24. # special-casing: only for '>= 0' and '< 0' and only when the
  25. # symbolic offset is known to be non-negative
  26. def __ge__(self, other):
  27. if self is other:
  28. return True
  29. elif (is_valid_int(other) and other == 0 and
  30. self.known_nonneg()):
  31. return True
  32. else:
  33. raise TypeError("Symbolics cannot be compared! (%r, %r)"
  34. % (self, other))
  35. def __lt__(self, other):
  36. return not self.__ge__(other)
  37. def known_nonneg(self):
  38. return False
  39. def _raw_malloc(self, rest, zero):
  40. raise NotImplementedError("_raw_malloc(%r, %r)" % (self, rest))
  41. def raw_memcopy(self, srcadr, dstadr):
  42. raise NotImplementedError("raw_memcopy(%r)" % (self,))
  43. class ItemOffset(AddressOffset):
  44. def __init__(self, TYPE, repeat=1):
  45. self.TYPE = TYPE
  46. self.repeat = repeat
  47. def __repr__(self):
  48. return "<ItemOffset %r %r>" % (self.TYPE, self.repeat)
  49. def __mul__(self, other):
  50. if not is_valid_int(other):
  51. return NotImplemented
  52. return ItemOffset(self.TYPE, self.repeat * other)
  53. __rmul__ = __mul__
  54. def __neg__(self):
  55. return ItemOffset(self.TYPE, -self.repeat)
  56. def known_nonneg(self):
  57. return self.repeat >= 0
  58. def ref(self, firstitemptr):
  59. A = lltype.typeOf(firstitemptr).TO
  60. if A == self.TYPE:
  61. # for array of containers
  62. parent, index = lltype.parentlink(firstitemptr._obj)
  63. assert parent, "%r is not within a container" % (firstitemptr,)
  64. assert isinstance(lltype.typeOf(parent),
  65. (lltype.Array, lltype.FixedSizeArray)), (
  66. "%r is not within an array" % (firstitemptr,))
  67. if isinstance(index, str):
  68. assert index.startswith('item') # itemN => N
  69. index = int(index[4:])
  70. index += self.repeat
  71. if index == parent.getlength():
  72. # for references exactly to the end of the array
  73. try:
  74. endmarker = _end_markers[parent]
  75. except KeyError:
  76. endmarker = _endmarker_struct(A, parent=parent,
  77. parentindex=index)
  78. _end_markers[parent] = endmarker
  79. return endmarker._as_ptr()
  80. else:
  81. return parent.getitem(index)._as_ptr()
  82. elif ((isinstance(A, lltype.FixedSizeArray)
  83. or (isinstance(A, lltype.Array) and A._hints.get('nolength',
  84. False)))
  85. and array_item_type_match(A.OF, self.TYPE)):
  86. # for array of primitives or pointers
  87. return lltype.direct_ptradd(firstitemptr, self.repeat)
  88. else:
  89. raise TypeError('got %r, expected %r' % (A, self.TYPE))
  90. def _raw_malloc(self, rest, zero):
  91. assert not rest
  92. if (isinstance(self.TYPE, lltype.ContainerType)
  93. and self.TYPE._gckind == 'gc'):
  94. assert self.repeat == 1
  95. p = lltype.malloc(self.TYPE, flavor='raw', zero=zero,
  96. track_allocation=False)
  97. return cast_ptr_to_adr(p)
  98. else:
  99. T = lltype.FixedSizeArray(self.TYPE, self.repeat)
  100. p = lltype.malloc(T, flavor='raw', zero=zero,
  101. track_allocation=False)
  102. array_adr = cast_ptr_to_adr(p)
  103. return array_adr + ArrayItemsOffset(T)
  104. def raw_memcopy(self, srcadr, dstadr):
  105. repeat = self.repeat
  106. if repeat == 0:
  107. return
  108. if isinstance(self.TYPE, lltype.ContainerType):
  109. PTR = lltype.Ptr(self.TYPE)
  110. elif self.TYPE == GCREF:
  111. self._raw_memcopy_gcrefs(srcadr, dstadr)
  112. return
  113. else:
  114. PTR = lltype.Ptr(lltype.FixedSizeArray(self.TYPE, 1))
  115. while True:
  116. src = cast_adr_to_ptr(srcadr, PTR)
  117. dst = cast_adr_to_ptr(dstadr, PTR)
  118. _reccopy(src, dst)
  119. repeat -= 1
  120. if repeat <= 0:
  121. break
  122. srcadr += ItemOffset(self.TYPE)
  123. dstadr += ItemOffset(self.TYPE)
  124. def _raw_memcopy_gcrefs(self, srcadr, dstadr):
  125. # special case to handle arrays of any GC pointers
  126. repeat = self.repeat
  127. while True:
  128. data = srcadr.address[0]
  129. dstadr.address[0] = data
  130. repeat -= 1
  131. if repeat <= 0:
  132. break
  133. srcadr += ItemOffset(self.TYPE)
  134. dstadr += ItemOffset(self.TYPE)
  135. _end_markers = weakref.WeakKeyDictionary() # <array of STRUCT> -> _endmarker
  136. class _endmarker_struct(lltype._struct):
  137. __slots__ = ()
  138. def __new__(self, *args, **kwds):
  139. return object.__new__(self)
  140. def __init__(self, *args, **kwds):
  141. lltype._struct.__init__(self, *args, **kwds)
  142. self._storage = False
  143. def __getattr__(self, name):
  144. raise AttributeError("cannot access fields in the endmarker "
  145. "structure at the end of the array")
  146. def __setattr__(self, name, value):
  147. if name.startswith('_'):
  148. object.__setattr__(self, name, value) # '_xxx' attributes
  149. elif self._storage is False:
  150. raise AttributeError("cannot access fields in the endmarker "
  151. "structure at the end of the array")
  152. class FieldOffset(AddressOffset):
  153. def __init__(self, TYPE, fldname):
  154. self.TYPE = TYPE
  155. self.fldname = fldname
  156. def __repr__(self):
  157. return "<FieldOffset %r %r>" % (self.TYPE, self.fldname)
  158. def known_nonneg(self):
  159. return True
  160. def ref(self, struct):
  161. if lltype.typeOf(struct).TO != self.TYPE:
  162. struct = lltype.cast_pointer(lltype.Ptr(self.TYPE), struct)
  163. FIELD = getattr(self.TYPE, self.fldname)
  164. if isinstance(FIELD, lltype.ContainerType):
  165. substruct = struct._obj._getattr(self.fldname)
  166. return substruct._as_ptr()
  167. else:
  168. return lltype.direct_fieldptr(struct, self.fldname)
  169. def _raw_malloc(self, rest, parenttype=None, zero=False):
  170. if self.fldname != self.TYPE._arrayfld:
  171. # for the error msg
  172. return AddressOffset._raw_malloc(self, rest, zero=zero)
  173. assert rest
  174. return rest[0]._raw_malloc(rest[1:], parenttype=parenttype or self.TYPE,
  175. zero=zero)
  176. def raw_memcopy(self, srcadr, dstadr):
  177. if self.fldname != self.TYPE._arrayfld:
  178. return AddressOffset.raw_memcopy(srcadr, dstadr) #for the error msg
  179. PTR = lltype.Ptr(self.TYPE)
  180. src = cast_adr_to_ptr(srcadr, PTR)
  181. dst = cast_adr_to_ptr(dstadr, PTR)
  182. _reccopy(src, dst)
  183. class CompositeOffset(AddressOffset):
  184. def __new__(cls, *offsets):
  185. lst = []
  186. for item in offsets:
  187. if isinstance(item, CompositeOffset):
  188. lst.extend(item.offsets)
  189. else:
  190. lst.append(item)
  191. for i in range(len(lst)-2, -1, -1):
  192. if (isinstance(lst[i], ItemOffset) and
  193. isinstance(lst[i+1], ItemOffset) and
  194. lst[i].TYPE == lst[i+1].TYPE):
  195. lst[i:i+2] = [ItemOffset(lst[i].TYPE,
  196. lst[i].repeat + lst[i+1].repeat)]
  197. if len(lst) == 1:
  198. return lst[0]
  199. else:
  200. self = object.__new__(cls)
  201. self.offsets = lst
  202. return self
  203. def __repr__(self):
  204. return '< %s >' % (' + '.join([repr(item) for item in self.offsets]),)
  205. def __neg__(self):
  206. ofs = [-item for item in self.offsets]
  207. ofs.reverse()
  208. return CompositeOffset(*ofs)
  209. def known_nonneg(self):
  210. for item in self.offsets:
  211. if not item.known_nonneg():
  212. return False
  213. return True
  214. def ref(self, ptr):
  215. for item in self.offsets:
  216. ptr = item.ref(ptr)
  217. return ptr
  218. def _raw_malloc(self, rest, zero):
  219. return self.offsets[0]._raw_malloc(self.offsets[1:] + rest, zero=zero)
  220. def raw_memcopy(self, srcadr, dstadr):
  221. for o in self.offsets[:-1]:
  222. o.raw_memcopy(srcadr, dstadr)
  223. srcadr += o
  224. dstadr += o
  225. o = self.offsets[-1]
  226. o.raw_memcopy(srcadr, dstadr)
  227. class ArrayItemsOffset(AddressOffset):
  228. def __init__(self, TYPE):
  229. self.TYPE = TYPE
  230. def __repr__(self):
  231. return '< ArrayItemsOffset %r >' % (self.TYPE,)
  232. def known_nonneg(self):
  233. return True
  234. def ref(self, arrayptr):
  235. assert array_type_match(lltype.typeOf(arrayptr).TO, self.TYPE)
  236. if isinstance(self.TYPE.OF, lltype.ContainerType):
  237. # XXX this doesn't support empty arrays
  238. # XXX it's also missing 'solid' support, probably
  239. o = arrayptr._obj.getitem(0)
  240. return o._as_ptr()
  241. else:
  242. return lltype.direct_arrayitems(arrayptr)
  243. def _raw_malloc(self, rest, parenttype=None, zero=False):
  244. if rest:
  245. assert len(rest) == 1
  246. assert isinstance(rest[0], ItemOffset)
  247. assert self.TYPE.OF == rest[0].TYPE
  248. count = rest[0].repeat
  249. else:
  250. count = 0
  251. p = lltype.malloc(parenttype or self.TYPE, count,
  252. immortal = self.TYPE._gckind == 'raw',
  253. zero = zero,
  254. track_allocation = False)
  255. return cast_ptr_to_adr(p)
  256. def raw_memcopy(self, srcadr, dstadr):
  257. # copy the length field, if we can
  258. srclen = srcadr.ptr._obj.getlength()
  259. dstlen = dstadr.ptr._obj.getlength()
  260. if dstlen != srclen:
  261. assert dstlen > srclen, "can't increase the length"
  262. # a decrease in length occurs in the GC tests when copying a STR:
  263. # the copy is initially allocated with really one extra char,
  264. # the 'extra_item_after_alloc', and must be fixed.
  265. dstadr.ptr._obj.shrinklength(srclen)
  266. class ArrayLengthOffset(AddressOffset):
  267. def __init__(self, TYPE):
  268. self.TYPE = TYPE
  269. def __repr__(self):
  270. return '< ArrayLengthOffset %r >' % (self.TYPE,)
  271. def known_nonneg(self):
  272. return True
  273. def ref(self, arrayptr):
  274. assert array_type_match(lltype.typeOf(arrayptr).TO, self.TYPE)
  275. return lltype._arraylenref._makeptr(arrayptr._obj, arrayptr._solid)
  276. class GCHeaderOffset(AddressOffset):
  277. def __init__(self, gcheaderbuilder):
  278. self.gcheaderbuilder = gcheaderbuilder
  279. def __repr__(self):
  280. return '< GCHeaderOffset >'
  281. def __neg__(self):
  282. return GCHeaderAntiOffset(self.gcheaderbuilder)
  283. def known_nonneg(self):
  284. return True
  285. def ref(self, headerptr):
  286. gcptr = self.gcheaderbuilder.object_from_header(headerptr)
  287. return gcptr
  288. def _raw_malloc(self, rest, zero):
  289. assert rest
  290. if isinstance(rest[0], GCHeaderAntiOffset):
  291. return rest[1]._raw_malloc(rest[2:], zero=zero) # just for fun
  292. gcobjadr = rest[0]._raw_malloc(rest[1:], zero=zero)
  293. headerptr = self.gcheaderbuilder.new_header(gcobjadr.ptr)
  294. return cast_ptr_to_adr(headerptr)
  295. def raw_memcopy(self, srcadr, dstadr):
  296. _reccopy(srcadr.ptr, dstadr.ptr)
  297. class GCHeaderAntiOffset(AddressOffset):
  298. def __init__(self, gcheaderbuilder):
  299. self.gcheaderbuilder = gcheaderbuilder
  300. def __repr__(self):
  301. return '< GCHeaderAntiOffset >'
  302. def __neg__(self):
  303. return GCHeaderOffset(self.gcheaderbuilder)
  304. def ref(self, gcptr):
  305. headerptr = self.gcheaderbuilder.header_of_object(gcptr)
  306. return headerptr
  307. def _raw_malloc(self, rest, zero):
  308. assert len(rest) >= 2
  309. assert isinstance(rest[0], GCHeaderOffset)
  310. return rest[1]._raw_malloc(rest[2:], zero=zero)
  311. # ____________________________________________________________
  312. @specialize.memo()
  313. def _sizeof_none(TYPE):
  314. assert not TYPE._is_varsize()
  315. return ItemOffset(TYPE)
  316. _sizeof_none._annspecialcase_ = 'specialize:memo'
  317. @specialize.memo()
  318. def _internal_array_field(TYPE):
  319. return TYPE._arrayfld, TYPE._flds[TYPE._arrayfld]
  320. def _sizeof_int(TYPE, n):
  321. if isinstance(TYPE, lltype.Struct):
  322. fldname, ARRAY = _internal_array_field(TYPE)
  323. return offsetof(TYPE, fldname) + sizeof(ARRAY, n)
  324. else:
  325. raise Exception("don't know how to take the size of a %r"%TYPE)
  326. @specialize.memo()
  327. def extra_item_after_alloc(ARRAY):
  328. assert isinstance(ARRAY, lltype.Array)
  329. return ARRAY._hints.get('extra_item_after_alloc', 0)
  330. @specialize.arg(0)
  331. def sizeof(TYPE, n=None):
  332. """Return the symbolic size of TYPE.
  333. For a Struct with no varsized part, it must be called with n=None.
  334. For an Array or a Struct with a varsized part, it is the number of items.
  335. There is a special case to return 1 more than requested if the array
  336. has the hint 'extra_item_after_alloc' set to 1.
  337. """
  338. if n is None:
  339. return _sizeof_none(TYPE)
  340. elif isinstance(TYPE, lltype.Array):
  341. n += extra_item_after_alloc(TYPE)
  342. return itemoffsetof(TYPE) + _sizeof_none(TYPE.OF) * n
  343. else:
  344. return _sizeof_int(TYPE, n)
  345. @specialize.memo()
  346. def offsetof(TYPE, fldname):
  347. assert fldname in TYPE._flds
  348. return FieldOffset(TYPE, fldname)
  349. @analyzer_for(offsetof)
  350. def ann_offsetof(TYPE, fldname):
  351. return SomeInteger()
  352. @specialize.memo()
  353. def itemoffsetof(TYPE, n=0):
  354. result = ArrayItemsOffset(TYPE)
  355. if n != 0:
  356. result += ItemOffset(TYPE.OF) * n
  357. return result
  358. @specialize.memo()
  359. def arraylengthoffset(TYPE):
  360. return ArrayLengthOffset(TYPE)
  361. # -------------------------------------------------------------
  362. class fakeaddress(object):
  363. __slots__ = ['ptr']
  364. # NOTE: the 'ptr' in the addresses must be normalized.
  365. # Use cast_ptr_to_adr() instead of directly fakeaddress() if unsure.
  366. def __init__(self, ptr):
  367. if ptr is not None and ptr._obj0 is None:
  368. ptr = None # null ptr => None
  369. self.ptr = ptr
  370. def __repr__(self):
  371. if self.ptr is None:
  372. s = 'NULL'
  373. else:
  374. #try:
  375. # s = hex(self.ptr._cast_to_int())
  376. #except:
  377. s = str(self.ptr)
  378. return '<fakeaddr %s>' % (s,)
  379. def __add__(self, other):
  380. if isinstance(other, AddressOffset):
  381. if self.ptr is None:
  382. raise NullAddressError("offset from NULL address")
  383. return fakeaddress(other.ref(self.ptr))
  384. if other == 0:
  385. return self
  386. return NotImplemented
  387. def __sub__(self, other):
  388. if isinstance(other, AddressOffset):
  389. return self + (-other)
  390. if isinstance(other, fakeaddress):
  391. if self == other:
  392. return 0
  393. else:
  394. raise TypeError("cannot subtract fakeaddresses in general")
  395. if other == 0:
  396. return self
  397. return NotImplemented
  398. def __nonzero__(self):
  399. return self.ptr is not None
  400. #def __hash__(self):
  401. # raise TypeError("don't put addresses in a prebuilt dictionary")
  402. def __eq__(self, other):
  403. if isinstance(other, fakeaddress):
  404. try:
  405. obj1 = self._fixup().ptr
  406. obj2 = other._fixup().ptr
  407. if obj1 is not None: obj1 = obj1._obj
  408. if obj2 is not None: obj2 = obj2._obj
  409. return obj1 == obj2
  410. except lltype.DelayedPointer:
  411. return self.ptr is other.ptr
  412. else:
  413. return NotImplemented
  414. def __ne__(self, other):
  415. if isinstance(other, fakeaddress):
  416. return not (self == other)
  417. else:
  418. return NotImplemented
  419. def __lt__(self, other):
  420. # for the convenience of debugging the GCs, NULL compares as the
  421. # smallest address even when compared with a non-fakearenaaddress
  422. if not isinstance(other, fakeaddress):
  423. raise TypeError("cannot compare fakeaddress and %r" % (
  424. other.__class__.__name__,))
  425. if not other:
  426. return False # self < NULL => False
  427. if not self:
  428. return True # NULL < non-null-other => True
  429. raise TypeError("cannot compare non-NULL fakeaddresses with '<'")
  430. def __le__(self, other):
  431. return self == other or self < other
  432. def __gt__(self, other):
  433. return not (self == other or self < other)
  434. def __ge__(self, other):
  435. return not (self < other)
  436. def ref(self):
  437. if not self:
  438. raise NullAddressError
  439. return self.ptr
  440. def _cast_to_ptr(self, EXPECTED_TYPE):
  441. addr = self._fixup()
  442. if addr:
  443. return cast_any_ptr(EXPECTED_TYPE, addr.ptr)
  444. else:
  445. return lltype.nullptr(EXPECTED_TYPE.TO)
  446. def _cast_to_int(self, symbolic=False):
  447. if self:
  448. if isinstance(self.ptr._obj0, int): # tagged integer
  449. return self.ptr._obj0
  450. if symbolic:
  451. return AddressAsInt(self)
  452. else:
  453. # This is a bit annoying. We want this method to still work
  454. # when the pointed-to object is dead
  455. return self.ptr._cast_to_int(False)
  456. else:
  457. return 0
  458. def _fixup(self):
  459. if self.ptr is not None and self.ptr._was_freed():
  460. # hack to support llarena.test_replace_object_with_stub()
  461. from rpython.rtyper.lltypesystem import llarena
  462. return llarena.getfakearenaaddress(self)
  463. else:
  464. return self
  465. class fakeaddressEntry(ExtRegistryEntry):
  466. _type_ = fakeaddress
  467. def compute_annotation(self):
  468. from rpython.rtyper.llannotation import SomeAddress
  469. return SomeAddress()
  470. class SomeAddress(SomeObject):
  471. immutable = True
  472. def can_be_none(self):
  473. return False
  474. def is_null_address(self):
  475. return self.is_immutable_constant() and not self.const
  476. def getattr(self, s_attr):
  477. assert s_attr.is_constant()
  478. assert isinstance(s_attr, SomeString)
  479. assert s_attr.const in supported_access_types
  480. return SomeTypedAddressAccess(supported_access_types[s_attr.const])
  481. getattr.can_only_throw = []
  482. def bool(self):
  483. return s_Bool
  484. class SomeTypedAddressAccess(SomeObject):
  485. """This class is used to annotate the intermediate value that
  486. appears in expressions of the form:
  487. addr.signed[offset] and addr.signed[offset] = value
  488. """
  489. def __init__(self, type):
  490. self.type = type
  491. def can_be_none(self):
  492. return False
  493. # ____________________________________________________________
  494. class AddressAsInt(Symbolic):
  495. # a symbolic, rendered as an address cast to an integer.
  496. def __init__(self, adr):
  497. self.adr = adr
  498. def annotation(self):
  499. from rpython.annotator import model
  500. return model.SomeInteger()
  501. def lltype(self):
  502. return lltype.Signed
  503. def __eq__(self, other):
  504. return self.adr == cast_int_to_adr(other)
  505. def __ne__(self, other):
  506. return self.adr != cast_int_to_adr(other)
  507. def __nonzero__(self):
  508. return bool(self.adr)
  509. def __add__(self, ofs):
  510. if (isinstance(ofs, int) and
  511. getattr(self.adr.ptr._TYPE.TO, 'OF', None) == lltype.Char):
  512. return AddressAsInt(self.adr + ItemOffset(lltype.Char, ofs))
  513. if isinstance(ofs, FieldOffset) and ofs.TYPE is self.adr.ptr._TYPE.TO:
  514. fieldadr = getattr(self.adr.ptr, ofs.fldname)
  515. return AddressAsInt(cast_ptr_to_adr(fieldadr))
  516. if (isinstance(ofs, ItemOffset) and
  517. isinstance(self.adr.ptr._TYPE.TO, lltype.Array) and
  518. self.adr.ptr._TYPE.TO._hints.get('nolength') is True and
  519. ofs.TYPE is self.adr.ptr._TYPE.TO.OF):
  520. itemadr = self.adr.ptr[ofs.repeat]
  521. return AddressAsInt(cast_ptr_to_adr(itemadr))
  522. return NotImplemented
  523. def __repr__(self):
  524. try:
  525. return '<AddressAsInt %s>' % (self.adr.ptr,)
  526. except AttributeError:
  527. return '<AddressAsInt at 0x%x>' % (uid(self),)
  528. # ____________________________________________________________
  529. class NullAddressError(Exception):
  530. pass
  531. class DanglingPointerError(Exception):
  532. pass
  533. NULL = fakeaddress(None)
  534. Address = lltype.Primitive("Address", NULL)
  535. # GCREF is similar to Address but it is GC-aware
  536. GCREF = lltype.Ptr(lltype.GcOpaqueType('GCREF'))
  537. # A placeholder for any type that is a GcArray of pointers.
  538. # This can be used in the symbolic offsets above to access such arrays
  539. # in a generic way.
  540. GCARRAY_OF_PTR = lltype.GcArray(GCREF, hints={'placeholder': True})
  541. gcarrayofptr_lengthoffset = ArrayLengthOffset(GCARRAY_OF_PTR)
  542. gcarrayofptr_itemsoffset = ArrayItemsOffset(GCARRAY_OF_PTR)
  543. gcarrayofptr_singleitemoffset = ItemOffset(GCARRAY_OF_PTR.OF)
  544. def array_type_match(A1, A2):
  545. return A1 == A2 or (A2 == GCARRAY_OF_PTR and
  546. isinstance(A1, lltype.GcArray) and
  547. isinstance(A1.OF, lltype.Ptr) and
  548. not A1._hints.get('nolength'))
  549. def array_item_type_match(T1, T2):
  550. return T1 == T2 or (T2 == GCREF and isinstance(T1, lltype.Ptr))
  551. class _fakeaccessor(object):
  552. def __init__(self, addr):
  553. self.addr = addr
  554. def __getitem__(self, index):
  555. ptr = self.addr.ref()
  556. if index != 0:
  557. ptr = lltype.direct_ptradd(ptr, index)
  558. return self.read_from_ptr(ptr)
  559. def __setitem__(self, index, value):
  560. assert lltype.typeOf(value) == self.TYPE
  561. ptr = self.addr.ref()
  562. if index != 0:
  563. ptr = lltype.direct_ptradd(ptr, index)
  564. self.write_into_ptr(ptr, value)
  565. def read_from_ptr(self, ptr):
  566. value = ptr[0]
  567. assert lltype.typeOf(value) == self.TYPE
  568. return value
  569. def write_into_ptr(self, ptr, value):
  570. ptr[0] = value
  571. class _signed_fakeaccessor(_fakeaccessor):
  572. TYPE = lltype.Signed
  573. class _unsigned_fakeaccessor(_fakeaccessor):
  574. TYPE = lltype.Unsigned
  575. class _float_fakeaccessor(_fakeaccessor):
  576. TYPE = lltype.Float
  577. class _char_fakeaccessor(_fakeaccessor):
  578. TYPE = lltype.Char
  579. class _address_fakeaccessor(_fakeaccessor):
  580. TYPE = Address
  581. def read_from_ptr(self, ptr):
  582. value = ptr[0]
  583. if isinstance(value, lltype._ptr):
  584. return value._cast_to_adr()
  585. elif lltype.typeOf(value) == Address:
  586. return value
  587. else:
  588. raise TypeError(value)
  589. def write_into_ptr(self, ptr, value):
  590. TARGETTYPE = lltype.typeOf(ptr).TO.OF
  591. if TARGETTYPE == Address:
  592. pass
  593. elif isinstance(TARGETTYPE, lltype.Ptr):
  594. value = cast_adr_to_ptr(value, TARGETTYPE)
  595. else:
  596. raise TypeError(TARGETTYPE)
  597. ptr[0] = value
  598. supported_access_types = {"signed": lltype.Signed,
  599. "unsigned": lltype.Unsigned,
  600. "char": lltype.Char,
  601. "address": Address,
  602. "float": lltype.Float,
  603. }
  604. fakeaddress.signed = property(_signed_fakeaccessor)
  605. fakeaddress.unsigned = property(_unsigned_fakeaccessor)
  606. fakeaddress.float = property(_float_fakeaccessor)
  607. fakeaddress.char = property(_char_fakeaccessor)
  608. fakeaddress.address = property(_address_fakeaccessor)
  609. fakeaddress._TYPE = Address
  610. # the obtained address will not keep the object alive. e.g. if the object is
  611. # only reachable through an address, it might get collected
  612. def cast_ptr_to_adr(obj):
  613. assert isinstance(lltype.typeOf(obj), lltype.Ptr)
  614. return obj._cast_to_adr()
  615. @analyzer_for(cast_ptr_to_adr)
  616. def ann_cast_ptr_to_adr(s):
  617. from rpython.rtyper.llannotation import SomeInteriorPtr
  618. assert not isinstance(s, SomeInteriorPtr)
  619. return SomeAddress()
  620. def cast_adr_to_ptr(adr, EXPECTED_TYPE):
  621. return adr._cast_to_ptr(EXPECTED_TYPE)
  622. @analyzer_for(cast_adr_to_ptr)
  623. def ann_cast_adr_to_ptr(s, s_type):
  624. assert s_type.is_constant()
  625. return SomePtr(s_type.const)
  626. def cast_adr_to_int(adr, mode="emulated"):
  627. # The following modes are supported before translation (after
  628. # translation, it's all just a cast):
  629. # * mode="emulated": goes via lltype.cast_ptr_to_int(), which returns some
  630. # number based on id(). The difference is that it works even if the
  631. # address is that of a dead object.
  632. # * mode="symbolic": returns an AddressAsInt instance, which can only be
  633. # cast back to an address later.
  634. # * mode="forced": uses rffi.cast() to return a real number.
  635. assert mode in ("emulated", "symbolic", "forced")
  636. res = adr._cast_to_int(symbolic = (mode != "emulated"))
  637. if mode == "forced":
  638. from rpython.rtyper.lltypesystem.rffi import cast
  639. res = cast(lltype.Signed, res)
  640. return res
  641. @analyzer_for(cast_adr_to_int)
  642. def ann_cast_adr_to_int(s, s_mode=None):
  643. return SomeInteger() # xxx
  644. _NONGCREF = lltype.Ptr(lltype.OpaqueType('NONGCREF'))
  645. def cast_int_to_adr(int):
  646. if isinstance(int, AddressAsInt):
  647. return int.adr
  648. try:
  649. ptr = lltype.cast_int_to_ptr(_NONGCREF, int)
  650. except ValueError:
  651. from rpython.rtyper.lltypesystem import ll2ctypes
  652. ptr = ll2ctypes._int2obj[int]._as_ptr()
  653. return cast_ptr_to_adr(ptr)
  654. @analyzer_for(cast_int_to_adr)
  655. def ann_cast_int_to_adr(s):
  656. return SomeAddress()
  657. # ____________________________________________________________
  658. # Weakrefs.
  659. #
  660. # An object of type WeakRef is a small GC-managed object that contains
  661. # a weak reference to another GC-managed object, as in regular Python.
  662. #
  663. class _WeakRefType(lltype.ContainerType):
  664. _gckind = 'gc'
  665. def __str__(self):
  666. return "WeakRef"
  667. WeakRef = _WeakRefType()
  668. WeakRefPtr = lltype.Ptr(WeakRef)
  669. def weakref_create(ptarget):
  670. # ptarget should not be a nullptr
  671. PTRTYPE = lltype.typeOf(ptarget)
  672. assert isinstance(PTRTYPE, lltype.Ptr)
  673. assert PTRTYPE.TO._gckind == 'gc'
  674. assert ptarget
  675. return _wref(ptarget)._as_ptr()
  676. @analyzer_for(weakref_create)
  677. def ann_weakref_create(s_obj):
  678. if (not isinstance(s_obj, SomePtr) or
  679. s_obj.ll_ptrtype.TO._gckind != 'gc'):
  680. raise Exception("bad type for argument to weakref_create(): %r" % (
  681. s_obj,))
  682. return SomePtr(WeakRefPtr)
  683. def weakref_deref(PTRTYPE, pwref):
  684. # pwref should not be a nullptr
  685. assert isinstance(PTRTYPE, lltype.Ptr)
  686. assert PTRTYPE.TO._gckind == 'gc'
  687. assert lltype.typeOf(pwref) == WeakRefPtr
  688. p = pwref._obj._dereference()
  689. if p is None:
  690. return lltype.nullptr(PTRTYPE.TO)
  691. else:
  692. return cast_any_ptr(PTRTYPE, p)
  693. @analyzer_for(weakref_deref)
  694. def ann_weakref_deref(s_ptrtype, s_wref):
  695. if not (s_ptrtype.is_constant() and
  696. isinstance(s_ptrtype.const, lltype.Ptr) and
  697. s_ptrtype.const.TO._gckind == 'gc'):
  698. raise Exception("weakref_deref() arg 1 must be a constant "
  699. "ptr type, got %s" % (s_ptrtype,))
  700. if not (isinstance(s_wref, SomePtr) and
  701. s_wref.ll_ptrtype == WeakRefPtr):
  702. raise Exception("weakref_deref() arg 2 must be a WeakRefPtr, "
  703. "got %s" % (s_wref,))
  704. return SomePtr(s_ptrtype.const)
  705. class _wref(lltype._container):
  706. _gckind = 'gc'
  707. _TYPE = WeakRef
  708. def __init__(self, ptarget):
  709. if ptarget is None:
  710. self._obref = lambda: None
  711. else:
  712. obj = lltype.normalizeptr(ptarget)._obj
  713. self._obref = weakref.ref(obj)
  714. def _dereference(self):
  715. obj = self._obref()
  716. # in combination with a GC like the SemiSpace, the 'obj' can be
  717. # still alive in the CPython sense but freed by the arena logic.
  718. if obj is None or obj._was_freed():
  719. return None
  720. else:
  721. return obj._as_ptr()
  722. def __repr__(self):
  723. return '<%s>' % (self,)
  724. def __str__(self):
  725. return 'wref -> %s' % (self._obref(),)
  726. # a prebuilt pointer to a dead low-level weakref
  727. dead_wref = _wref(None)._as_ptr()
  728. # The rest is to support the GC transformers: they can use it to build
  729. # an explicit weakref object with some structure and then "hide" the
  730. # result by casting it to a WeakRefPtr, and "reveal" it again. In other
  731. # words, weakref_create and weakref_deref are operations that exist only
  732. # before the GC transformation, whereas the two cast operations below
  733. # exist only after. They are implemented here only to allow GC
  734. # transformers to be tested on top of the llinterpreter.
  735. def cast_ptr_to_weakrefptr(ptr):
  736. if ptr:
  737. return _gctransformed_wref(ptr)._as_ptr()
  738. else:
  739. return lltype.nullptr(WeakRef)
  740. @analyzer_for(cast_ptr_to_weakrefptr)
  741. def llcast_ptr_to_weakrefptr(s_ptr):
  742. assert isinstance(s_ptr, SomePtr)
  743. return SomePtr(WeakRefPtr)
  744. def cast_weakrefptr_to_ptr(PTRTYPE, pwref):
  745. assert lltype.typeOf(pwref) == WeakRefPtr
  746. if pwref:
  747. assert isinstance(pwref._obj, _gctransformed_wref)
  748. if PTRTYPE is not None:
  749. assert PTRTYPE == lltype.typeOf(pwref._obj._ptr)
  750. return pwref._obj._ptr
  751. else:
  752. return lltype.nullptr(PTRTYPE.TO)
  753. @analyzer_for(cast_weakrefptr_to_ptr)
  754. def llcast_weakrefptr_to_ptr(s_ptrtype, s_wref):
  755. if not (s_ptrtype.is_constant() and
  756. isinstance(s_ptrtype.const, lltype.Ptr)):
  757. raise Exception("cast_weakrefptr_to_ptr() arg 1 must be a constant "
  758. "ptr type, got %s" % (s_ptrtype,))
  759. if not (isinstance(s_wref, SomePtr) and s_wref.ll_ptrtype == WeakRefPtr):
  760. raise Exception("cast_weakrefptr_to_ptr() arg 2 must be a WeakRefPtr, "
  761. "got %s" % (s_wref,))
  762. return SomePtr(s_ptrtype.const)
  763. class _gctransformed_wref(lltype._container):
  764. _gckind = 'gc'
  765. _TYPE = WeakRef
  766. def __init__(self, ptr):
  767. self._ptr = ptr
  768. def __repr__(self):
  769. return '<%s>' % (self,)
  770. def __str__(self):
  771. return 'gctransformed_wref(%s)' % (self._ptr,)
  772. def _normalizedcontainer(self, check=True):
  773. return self._ptr._getobj(check=check)._normalizedcontainer(check=check)
  774. def _was_freed(self):
  775. return self._ptr._was_freed()
  776. # ____________________________________________________________
  777. def raw_malloc(size):
  778. if not isinstance(size, AddressOffset):
  779. raise NotImplementedError(size)
  780. return size._raw_malloc([], zero=False)
  781. @analyzer_for(raw_malloc)
  782. def ann_raw_malloc(s_size):
  783. assert isinstance(s_size, SomeInteger) # XXX add noneg...?
  784. return SomeAddress()
  785. def raw_free(adr):
  786. # try to free the whole object if 'adr' is the address of the header
  787. from rpython.memory.gcheader import GCHeaderBuilder
  788. try:
  789. objectptr = GCHeaderBuilder.object_from_header(adr.ptr)
  790. except KeyError:
  791. pass
  792. else:
  793. raw_free(cast_ptr_to_adr(objectptr))
  794. assert isinstance(adr.ref()._obj, lltype._parentable)
  795. adr.ptr._as_obj()._free()
  796. @analyzer_for(raw_free)
  797. def ann_raw_free(s_addr):
  798. assert isinstance(s_addr, SomeAddress)
  799. def raw_malloc_usage(size):
  800. if isinstance(size, AddressOffset):
  801. # ouah
  802. from rpython.memory.lltypelayout import convert_offset_to_int
  803. size = convert_offset_to_int(size)
  804. return size
  805. @analyzer_for(raw_malloc_usage)
  806. def ann_raw_malloc_usage(s_size):
  807. assert isinstance(s_size, SomeInteger) # XXX add noneg...?
  808. return SomeInteger(nonneg=True)
  809. def raw_memclear(adr, size):
  810. if not isinstance(size, AddressOffset):
  811. raise NotImplementedError(size)
  812. assert lltype.typeOf(adr) == Address
  813. zeroadr = size._raw_malloc([], zero=True)
  814. size.raw_memcopy(zeroadr, adr)
  815. @analyzer_for(raw_memclear)
  816. def ann_raw_memclear(s_addr, s_int):
  817. assert isinstance(s_addr, SomeAddress)
  818. assert isinstance(s_int, SomeInteger)
  819. def raw_memcopy(source, dest, size):
  820. assert lltype.typeOf(source) == Address
  821. assert lltype.typeOf(dest) == Address
  822. size.raw_memcopy(source, dest)
  823. @analyzer_for(raw_memcopy)
  824. def ann_raw_memcopy(s_addr1, s_addr2, s_int):
  825. assert isinstance(s_addr1, SomeAddress)
  826. assert isinstance(s_addr2, SomeAddress)
  827. assert isinstance(s_int, SomeInteger) # XXX add noneg...?
  828. def raw_memmove(source, dest, size):
  829. # for now let's assume that raw_memmove is the same as raw_memcopy,
  830. # when run on top of fake addresses, but we _free the source object
  831. raw_memcopy(source, dest, size)
  832. source.ptr._as_obj()._free()
  833. class RawMemmoveEntry(ExtRegistryEntry):
  834. _about_ = raw_memmove
  835. def compute_result_annotation(self, s_from, s_to, s_size):
  836. assert isinstance(s_from, SomeAddress)
  837. assert isinstance(s_to, SomeAddress)
  838. assert isinstance(s_size, SomeInteger)
  839. def specialize_call(self, hop):
  840. hop.exception_cannot_occur()
  841. v_list = hop.inputargs(Address, Address, lltype.Signed)
  842. return hop.genop('raw_memmove', v_list)
  843. def cast_any_ptr(EXPECTED_TYPE, ptr):
  844. # this is a generalization of the various cast_xxx_ptr() functions.
  845. PTRTYPE = lltype.typeOf(ptr)
  846. if PTRTYPE == EXPECTED_TYPE:
  847. return ptr
  848. elif EXPECTED_TYPE == WeakRefPtr:
  849. return cast_ptr_to_weakrefptr(ptr)
  850. elif PTRTYPE == WeakRefPtr:
  851. ptr = cast_weakrefptr_to_ptr(None, ptr)
  852. return cast_any_ptr(EXPECTED_TYPE, ptr)
  853. elif (isinstance(EXPECTED_TYPE.TO, lltype.OpaqueType) or
  854. isinstance(PTRTYPE.TO, lltype.OpaqueType)):
  855. return lltype.cast_opaque_ptr(EXPECTED_TYPE, ptr)
  856. else:
  857. # regular case
  858. return lltype.cast_pointer(EXPECTED_TYPE, ptr)
  859. def _reccopy(source, dest):
  860. # copy recursively a structure or array onto another.
  861. T = lltype.typeOf(source).TO
  862. assert T == lltype.typeOf(dest).TO
  863. if isinstance(T, (lltype.Array, lltype.FixedSizeArray)):
  864. sourcelgt = source._obj.getlength()
  865. destlgt = dest._obj.getlength()
  866. lgt = min(sourcelgt, destlgt)
  867. ITEMTYPE = T.OF
  868. for i in range(lgt):
  869. if isinstance(ITEMTYPE, lltype.ContainerType):
  870. subsrc = source._obj.getitem(i)._as_ptr()
  871. subdst = dest._obj.getitem(i)._as_ptr()
  872. _reccopy(subsrc, subdst)
  873. else:
  874. # this is a hack XXX de-hack this
  875. llvalue = source._obj.getitem(i, uninitialized_ok=2)
  876. if not isinstance(llvalue, lltype._uninitialized):
  877. dest._obj.setitem(i, llvalue)
  878. elif isinstance(T, lltype.Struct):
  879. for name in T._names:
  880. FIELDTYPE = getattr(T, name)
  881. if isinstance(FIELDTYPE, lltype.ContainerType):
  882. subsrc = source._obj._getattr(name)._as_ptr()
  883. subdst = dest._obj._getattr(name)._as_ptr()
  884. _reccopy(subsrc, subdst)
  885. else:
  886. # this is a hack XXX de-hack this
  887. llvalue = source._obj._getattr(name, uninitialized_ok=True)
  888. setattr(dest._obj, name, llvalue)
  889. else:
  890. raise TypeError(T)