PageRenderTime 30ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/rpython/translator/c/test/test_newgc.py

https://bitbucket.org/pypy/pypy/
Python | 1805 lines | 1728 code | 68 blank | 9 comment | 52 complexity | 832adc069a2a234526c9a751d6488820 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import gc
  2. import inspect
  3. import os
  4. import sys
  5. import subprocess
  6. import random
  7. import py
  8. from rpython.conftest import option
  9. from rpython.rlib import rgc
  10. from rpython.rlib.objectmodel import keepalive_until_here, compute_hash, compute_identity_hash
  11. from rpython.rlib.rstring import StringBuilder
  12. from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
  13. from rpython.rtyper.lltypesystem.lloperation import llop
  14. from rpython.memory.test import snippet
  15. from rpython.tool.udir import udir
  16. from rpython.translator.interactive import Translation
  17. class UsingFrameworkTest(object):
  18. #gcpolicy = ... specified by subclasses
  19. should_be_moving = False
  20. removetypeptr = False
  21. taggedpointers = False
  22. GC_CAN_MOVE = False
  23. GC_CAN_SHRINK_ARRAY = False
  24. _isolated_func = None
  25. c_allfuncs = None
  26. @classmethod
  27. def _makefunc_str_int(cls, f):
  28. def main(argv):
  29. arg0 = argv[1]
  30. arg1 = int(argv[2])
  31. try:
  32. res = f(arg0, arg1)
  33. except MemoryError:
  34. print "MEMORY-ERROR"
  35. else:
  36. print res
  37. return 0
  38. t = Translation(main, gc=cls.gcpolicy,
  39. taggedpointers=cls.taggedpointers,
  40. gcremovetypeptr=cls.removetypeptr)
  41. t.disable(['backendopt'])
  42. t.set_backend_extra_options(c_debug_defines=True)
  43. t.rtype()
  44. if option.view:
  45. t.viewcg()
  46. exename = t.compile()
  47. def run(s, i, runner=subprocess.check_output):
  48. data = runner([str(exename), str(s), str(i)])
  49. data = data.strip()
  50. if data == 'MEMORY-ERROR':
  51. raise MemoryError
  52. return data
  53. return run
  54. def setup_class(cls):
  55. funcs0 = []
  56. funcs1 = []
  57. funcsstr = []
  58. name_to_func = {}
  59. for fullname in dir(cls):
  60. if not fullname.startswith('define'):
  61. continue
  62. keyword = option.keyword
  63. if keyword.startswith('test_') and not keyword.endswith(':'):
  64. keyword = keyword[len('test_'):]
  65. if keyword not in fullname:
  66. continue
  67. prefix, name = fullname.split('_', 1)
  68. definefunc = getattr(cls, fullname)
  69. func = definefunc.im_func(cls)
  70. func.func_name = 'f_' + name
  71. if prefix == 'definestr':
  72. funcsstr.append(func)
  73. funcs0.append(None)
  74. funcs1.append(None)
  75. else:
  76. numargs = len(inspect.getargspec(func)[0])
  77. funcsstr.append(None)
  78. if numargs == 0:
  79. funcs0.append(func)
  80. funcs1.append(None)
  81. else:
  82. assert numargs == 1
  83. funcs0.append(None)
  84. funcs1.append(func)
  85. assert name not in name_to_func
  86. name_to_func[name] = len(name_to_func)
  87. assert name_to_func
  88. def allfuncs(name, arg):
  89. num = name_to_func[name]
  90. func0 = funcs0[num]
  91. if func0:
  92. return str(func0())
  93. func1 = funcs1[num]
  94. if func1:
  95. return str(func1(arg))
  96. funcstr = funcsstr[num]
  97. if funcstr:
  98. return funcstr(arg)
  99. assert 0, 'unreachable'
  100. cls.funcsstr = funcsstr
  101. cls.c_allfuncs = staticmethod(cls._makefunc_str_int(allfuncs))
  102. cls.allfuncs = staticmethod(allfuncs)
  103. cls.name_to_func = name_to_func
  104. def teardown_class(cls):
  105. if hasattr(cls.c_allfuncs, 'close_isolate'):
  106. cls.c_allfuncs.close_isolate()
  107. cls.c_allfuncs = None
  108. def run(self, name, *args, **kwds):
  109. if not args:
  110. args = (-1, )
  111. print 'Running %r)' % name
  112. res = self.c_allfuncs(name, *args, **kwds)
  113. num = self.name_to_func[name]
  114. if self.funcsstr[num]:
  115. return res
  116. return int(res)
  117. def run_orig(self, name, *args):
  118. if not args:
  119. args = (-1, )
  120. res = self.allfuncs(name, *args)
  121. num = self.name_to_func[name]
  122. if self.funcsstr[num]:
  123. return res
  124. return int(res)
  125. def define_empty_collect(cls):
  126. def f():
  127. llop.gc__collect(lltype.Void)
  128. return 41
  129. return f
  130. def test_empty_collect(self):
  131. res = self.run('empty_collect')
  132. assert res == 41
  133. def define_framework_simple(cls):
  134. def g(x): # cannot cause a collect
  135. return x + 1
  136. class A(object):
  137. pass
  138. def make():
  139. a = A()
  140. a.b = g(1)
  141. return a
  142. make._dont_inline_ = True
  143. def f():
  144. a = make()
  145. llop.gc__collect(lltype.Void)
  146. return a.b
  147. return f
  148. def test_framework_simple(self):
  149. res = self.run('framework_simple')
  150. assert res == 2
  151. def define_framework_safe_pushpop(cls):
  152. class A(object):
  153. pass
  154. class B(object):
  155. pass
  156. def g(x): # cause a collect
  157. llop.gc__collect(lltype.Void)
  158. g._dont_inline_ = True
  159. global_a = A()
  160. global_a.b = B()
  161. global_a.b.a = A()
  162. global_a.b.a.b = B()
  163. global_a.b.a.b.c = 1
  164. def make():
  165. global_a.b.a.b.c = 40
  166. a = global_a.b.a
  167. b = a.b
  168. b.c = 41
  169. g(1)
  170. b0 = a.b
  171. b0.c = b.c = 42
  172. make._dont_inline_ = True
  173. def f():
  174. make()
  175. llop.gc__collect(lltype.Void)
  176. return global_a.b.a.b.c
  177. return f
  178. def test_framework_safe_pushpop(self):
  179. res = self.run('framework_safe_pushpop')
  180. assert res == 42
  181. def define_framework_protect_getfield(cls):
  182. class A(object):
  183. pass
  184. class B(object):
  185. pass
  186. def prepare(b, n):
  187. a = A()
  188. a.value = n
  189. b.a = a
  190. b.othervalue = 5
  191. def g(a):
  192. llop.gc__collect(lltype.Void)
  193. for i in range(1000):
  194. prepare(B(), -1) # probably overwrites collected memory
  195. return a.value
  196. g._dont_inline_ = True
  197. def f():
  198. b = B()
  199. prepare(b, 123)
  200. a = b.a
  201. b.a = None
  202. return g(a) + b.othervalue
  203. return f
  204. def test_framework_protect_getfield(self):
  205. res = self.run('framework_protect_getfield')
  206. assert res == 128
  207. def define_framework_varsized(cls):
  208. S = lltype.GcStruct("S", ('x', lltype.Signed))
  209. T = lltype.GcStruct("T", ('y', lltype.Signed),
  210. ('s', lltype.Ptr(S)))
  211. ARRAY_Ts = lltype.GcArray(lltype.Ptr(T))
  212. def f():
  213. r = 0
  214. for i in range(30):
  215. a = lltype.malloc(ARRAY_Ts, i)
  216. for j in range(i):
  217. a[j] = lltype.malloc(T)
  218. a[j].y = i
  219. a[j].s = lltype.malloc(S)
  220. a[j].s.x = 2 * i
  221. r += a[j].y + a[j].s.x
  222. a[j].s = lltype.malloc(S)
  223. a[j].s.x = 3 * i
  224. r -= a[j].s.x
  225. for j in range(i):
  226. r += a[j].y
  227. return r
  228. return f
  229. def test_framework_varsized(self):
  230. res = self.run('framework_varsized')
  231. assert res == self.run_orig('framework_varsized')
  232. def define_framework_using_lists(cls):
  233. class A(object):
  234. pass
  235. N = 1000
  236. def f():
  237. static_list = []
  238. for i in range(N):
  239. a = A()
  240. a.x = i
  241. static_list.append(a)
  242. r = 0
  243. for a in static_list:
  244. r += a.x
  245. return r
  246. return f
  247. def test_framework_using_lists(self):
  248. N = 1000
  249. res = self.run('framework_using_lists')
  250. assert res == N * (N - 1) / 2
  251. def define_framework_static_roots(cls):
  252. class A(object):
  253. def __init__(self, y):
  254. self.y = y
  255. a = A(0)
  256. a.x = None
  257. def make():
  258. a.x = A(42)
  259. make._dont_inline_ = True
  260. def f():
  261. make()
  262. llop.gc__collect(lltype.Void)
  263. return a.x.y
  264. return f
  265. def test_framework_static_roots(self):
  266. res = self.run('framework_static_roots')
  267. assert res == 42
  268. def define_framework_nongc_static_root(cls):
  269. S = lltype.GcStruct("S", ('x', lltype.Signed))
  270. T = lltype.Struct("T", ('p', lltype.Ptr(S)))
  271. t = lltype.malloc(T, immortal=True)
  272. def f():
  273. t.p = lltype.malloc(S)
  274. t.p.x = 43
  275. for i in range(2500000):
  276. s = lltype.malloc(S)
  277. s.x = i
  278. return t.p.x
  279. return f
  280. def test_framework_nongc_static_root(self):
  281. res = self.run('framework_nongc_static_root')
  282. assert res == 43
  283. def define_framework_void_array(cls):
  284. A = lltype.GcArray(lltype.Void)
  285. a = lltype.malloc(A, 44)
  286. def f():
  287. return len(a)
  288. return f
  289. def test_framework_void_array(self):
  290. res = self.run('framework_void_array')
  291. assert res == 44
  292. def define_framework_malloc_failure(cls):
  293. def f():
  294. a = [1] * (sys.maxint // 2)
  295. return len(a) + a[0]
  296. return f
  297. def test_framework_malloc_failure(self):
  298. py.test.raises(MemoryError, self.run, 'framework_malloc_failure')
  299. def define_framework_array_of_void(cls):
  300. def f():
  301. a = [None] * 43
  302. b = []
  303. for i in range(1000000):
  304. a.append(None)
  305. b.append(len(a))
  306. return b[-1]
  307. return f
  308. def test_framework_array_of_void(self):
  309. res = self.run('framework_array_of_void')
  310. assert res == 43 + 1000000
  311. def define_framework_opaque(cls):
  312. A = lltype.GcStruct('A', ('value', lltype.Signed))
  313. O = lltype.GcOpaqueType('test.framework')
  314. def gethidden(n):
  315. a = lltype.malloc(A)
  316. a.value = -n * 7
  317. return lltype.cast_opaque_ptr(lltype.Ptr(O), a)
  318. gethidden._dont_inline_ = True
  319. def reveal(o):
  320. return lltype.cast_opaque_ptr(lltype.Ptr(A), o)
  321. def overwrite(a, i):
  322. a.value = i
  323. overwrite._dont_inline_ = True
  324. def f():
  325. o = gethidden(10)
  326. llop.gc__collect(lltype.Void)
  327. for i in range(1000): # overwrite freed memory
  328. overwrite(lltype.malloc(A), i)
  329. a = reveal(o)
  330. return a.value
  331. return f
  332. def test_framework_opaque(self):
  333. res = self.run('framework_opaque')
  334. assert res == -70
  335. def define_framework_finalizer(cls):
  336. class B(object):
  337. pass
  338. b = B()
  339. b.nextid = 0
  340. b.num_deleted = 0
  341. class A(object):
  342. def __init__(self):
  343. self.id = b.nextid
  344. b.nextid += 1
  345. def __del__(self):
  346. b.num_deleted += 1
  347. def f():
  348. a = A()
  349. i = 0
  350. while i < 5:
  351. i += 1
  352. a = A()
  353. llop.gc__collect(lltype.Void)
  354. llop.gc__collect(lltype.Void)
  355. return b.num_deleted
  356. return f
  357. def test_framework_finalizer(self):
  358. res = self.run('framework_finalizer')
  359. assert res == 6
  360. def define_del_catches(cls):
  361. def g():
  362. pass
  363. class A(object):
  364. def __del__(self):
  365. try:
  366. g()
  367. except:
  368. pass #os.write(1, "hallo")
  369. def f1(i):
  370. if i:
  371. raise TypeError
  372. def f(i):
  373. a = A()
  374. f1(i)
  375. a.b = 1
  376. llop.gc__collect(lltype.Void)
  377. return a.b
  378. def h(x):
  379. try:
  380. return f(x)
  381. except TypeError:
  382. return 42
  383. return h
  384. def test_del_catches(self):
  385. res = self.run('del_catches', 0)
  386. assert res == 1
  387. res = self.run('del_catches', 1)
  388. assert res == 42
  389. def define_del_raises(cls):
  390. class B(object):
  391. def __del__(self):
  392. raise TypeError
  393. def func():
  394. b = B()
  395. return 0
  396. return func
  397. def test_del_raises(self):
  398. self.run('del_raises') # does not raise
  399. def define_custom_trace(cls):
  400. from rpython.rtyper.annlowlevel import llhelper
  401. #
  402. S = lltype.GcStruct('S', ('x', llmemory.Address))
  403. offset_of_x = llmemory.offsetof(S, 'x')
  404. def customtrace(gc, obj, callback, arg):
  405. gc._trace_callback(callback, arg, obj + offset_of_x)
  406. lambda_customtrace = lambda: customtrace
  407. #
  408. def setup():
  409. rgc.register_custom_trace_hook(S, lambda_customtrace)
  410. s = lltype.nullptr(S)
  411. for i in range(10000):
  412. t = lltype.malloc(S)
  413. t.x = llmemory.cast_ptr_to_adr(s)
  414. s = t
  415. return s
  416. def measure_length(s):
  417. res = 0
  418. while s:
  419. res += 1
  420. s = llmemory.cast_adr_to_ptr(s.x, lltype.Ptr(S))
  421. return res
  422. def f(n):
  423. s1 = setup()
  424. llop.gc__collect(lltype.Void)
  425. return measure_length(s1)
  426. return f
  427. def test_custom_trace(self):
  428. res = self.run('custom_trace', 0)
  429. assert res == 10000
  430. def define_custom_light_finalizer(cls):
  431. from rpython.rtyper.annlowlevel import llhelper
  432. #
  433. T = lltype.Struct('T', ('count', lltype.Signed))
  434. t = lltype.malloc(T, zero=True, immortal=True, flavor='raw')
  435. #
  436. S = lltype.GcStruct('S', rtti=True)
  437. def customlightfinlz(addr):
  438. t.count += 1
  439. lambda_customlightfinlz = lambda: customlightfinlz
  440. #
  441. def setup():
  442. rgc.register_custom_light_finalizer(S, lambda_customlightfinlz)
  443. for i in range(10000):
  444. lltype.malloc(S)
  445. def f(n):
  446. setup()
  447. llop.gc__collect(lltype.Void)
  448. return t.count
  449. return f
  450. def test_custom_light_finalizer(self):
  451. res = self.run('custom_light_finalizer', 0)
  452. assert res == 10000
  453. def define_weakref(cls):
  454. import weakref
  455. class A:
  456. pass
  457. keepalive = []
  458. def fn():
  459. n = 7000
  460. weakrefs = []
  461. a = None
  462. for i in range(n):
  463. if i & 1 == 0:
  464. a = A()
  465. a.index = i
  466. assert a is not None
  467. weakrefs.append(weakref.ref(a))
  468. if i % 7 == 6:
  469. keepalive.append(a)
  470. rgc.collect()
  471. count_free = 0
  472. for i in range(n):
  473. a = weakrefs[i]()
  474. if i % 7 == 6:
  475. assert a is not None
  476. if a is not None:
  477. assert a.index == i & ~1
  478. else:
  479. count_free += 1
  480. return count_free
  481. return fn
  482. def test_weakref(self):
  483. res = self.run('weakref')
  484. # more than half of them should have been freed, ideally up to 6000
  485. assert 3500 <= res <= 6000
  486. def define_prebuilt_weakref(cls):
  487. import weakref
  488. class A:
  489. pass
  490. a = A()
  491. a.hello = 42
  492. refs = [weakref.ref(a), weakref.ref(A())]
  493. rgc.collect()
  494. def fn():
  495. result = 0
  496. for i in range(2):
  497. a = refs[i]()
  498. rgc.collect()
  499. if a is None:
  500. result += (i + 1)
  501. else:
  502. result += a.hello * (i + 1)
  503. return result
  504. return fn
  505. def test_prebuilt_weakref(self):
  506. res = self.run('prebuilt_weakref')
  507. assert res == self.run_orig('prebuilt_weakref')
  508. def define_framework_malloc_raw(cls):
  509. A = lltype.Struct('A', ('value', lltype.Signed))
  510. def f():
  511. p = lltype.malloc(A, flavor='raw')
  512. p.value = 123
  513. llop.gc__collect(lltype.Void)
  514. res = p.value
  515. lltype.free(p, flavor='raw')
  516. return res
  517. return f
  518. def test_framework_malloc_raw(self):
  519. res = self.run('framework_malloc_raw')
  520. assert res == 123
  521. def define_framework_del_seeing_new_types(cls):
  522. class B(object):
  523. pass
  524. class A(object):
  525. def __del__(self):
  526. B()
  527. def f():
  528. A()
  529. return 42
  530. return f
  531. def test_framework_del_seeing_new_types(self):
  532. res = self.run('framework_del_seeing_new_types')
  533. assert res == 42
  534. def define_framework_late_filling_pointers(cls):
  535. A = lltype.GcStruct('A', ('x', lltype.Signed))
  536. B = lltype.GcStruct('B', ('a', lltype.Ptr(A)))
  537. def f():
  538. p = lltype.malloc(B)
  539. llop.gc__collect(lltype.Void)
  540. p.a = lltype.malloc(A)
  541. return p.a.x
  542. return f
  543. def test_framework_late_filling_pointers(self):
  544. # the point is just not to segfault
  545. self.run('framework_late_filling_pointers')
  546. def define_zero_raw_malloc(cls):
  547. S = lltype.Struct('S', ('x', lltype.Signed), ('y', lltype.Signed))
  548. def f():
  549. for i in range(100):
  550. p = lltype.malloc(S, flavor='raw', zero=True)
  551. if p.x != 0 or p.y != 0:
  552. return -1
  553. p.x = i
  554. p.y = i
  555. lltype.free(p, flavor='raw')
  556. return 42
  557. return f
  558. def test_zero_raw_malloc(self):
  559. res = self.run('zero_raw_malloc')
  560. assert res == 42
  561. def define_object_alignment(cls):
  562. # all objects returned by the GC should be properly aligned.
  563. from rpython.rtyper.lltypesystem import rffi
  564. mylist = ['a', 'bc', '84139871', 'ajkdh', '876']
  565. def f():
  566. result = 0
  567. buffer = ""
  568. for j in range(100):
  569. for s in mylist:
  570. buffer += s
  571. addr = rffi.cast(lltype.Signed, buffer)
  572. result |= addr
  573. return result
  574. return f
  575. def test_object_alignment(self):
  576. res = self.run('object_alignment')
  577. from rpython.rtyper.tool import rffi_platform
  578. expected_alignment = rffi_platform.memory_alignment()
  579. assert (res & (expected_alignment - 1)) == 0
  580. def define_void_list(cls):
  581. class E:
  582. def __init__(self):
  583. self.l = []
  584. def f():
  585. e = E()
  586. return len(e.l)
  587. return f
  588. def test_void_list(self):
  589. assert self.run('void_list') == 0
  590. filename = str(udir.join('test_open_read_write_close.txt'))
  591. def define_open_read_write_seek_close(cls):
  592. filename = cls.filename
  593. def does_stuff():
  594. fd = os.open(filename, os.O_WRONLY | os.O_CREAT, 0777)
  595. count = os.write(fd, "hello world\n")
  596. assert count == len("hello world\n")
  597. os.close(fd)
  598. fd = os.open(filename, os.O_RDONLY, 0777)
  599. result = os.lseek(fd, 1, 0)
  600. assert result == 1
  601. data = os.read(fd, 500)
  602. assert data == "ello world\n"
  603. os.close(fd)
  604. return 0
  605. return does_stuff
  606. def test_open_read_write_seek_close(self):
  607. self.run('open_read_write_seek_close')
  608. with open(self.filename, 'r') as fid:
  609. assert fid.read() == "hello world\n"
  610. os.unlink(self.filename)
  611. def define_callback_with_collect(cls):
  612. from rpython.rlib.clibffi import ffi_type_pointer, cast_type_to_ffitype,\
  613. CDLL, ffi_type_void, CallbackFuncPtr, ffi_type_sint
  614. ffi_size_t = cast_type_to_ffitype(rffi.SIZE_T)
  615. from rpython.rlib.clibffi import get_libc_name
  616. def callback(ll_args, ll_res, stuff):
  617. gc.collect()
  618. p_a1 = rffi.cast(rffi.VOIDPP, ll_args[0])[0]
  619. p_a2 = rffi.cast(rffi.VOIDPP, ll_args[1])[0]
  620. a1 = rffi.cast(rffi.SIGNEDP, p_a1)[0]
  621. a2 = rffi.cast(rffi.SIGNEDP, p_a2)[0]
  622. # related to libffi issue on s390x, we MUST
  623. # overwrite the full ffi result which is 64 bit
  624. # if not, this leaves garbage in the return value
  625. # and qsort does not sort correctly
  626. res = rffi.cast(rffi.SIGNEDP, ll_res)
  627. if a1 > a2:
  628. res[0] = 1
  629. else:
  630. res[0] = -1
  631. def f():
  632. libc = CDLL(get_libc_name())
  633. qsort = libc.getpointer('qsort', [ffi_type_pointer, ffi_size_t,
  634. ffi_size_t, ffi_type_pointer],
  635. ffi_type_void)
  636. ptr = CallbackFuncPtr([ffi_type_pointer, ffi_type_pointer, ffi_type_pointer],
  637. ffi_type_sint, callback)
  638. TP = rffi.CArray(lltype.Signed)
  639. to_sort = lltype.malloc(TP, 4, flavor='raw')
  640. to_sort[0] = 4
  641. to_sort[1] = 3
  642. to_sort[2] = 1
  643. to_sort[3] = 2
  644. qsort.push_arg(rffi.cast(rffi.VOIDP, to_sort))
  645. qsort.push_arg(rffi.cast(rffi.SIZE_T, 4))
  646. qsort.push_arg(rffi.cast(rffi.SIZE_T, rffi.sizeof(lltype.Signed)))
  647. qsort.push_arg(rffi.cast(rffi.VOIDP, ptr.ll_closure))
  648. qsort.call(lltype.Void)
  649. result = [to_sort[i] for i in range(4)] == [1, 2, 3, 4]
  650. lltype.free(to_sort, flavor='raw')
  651. keepalive_until_here(ptr)
  652. return int(result)
  653. return f
  654. def test_callback_with_collect(self):
  655. assert self.run('callback_with_collect')
  656. def define_can_move(cls):
  657. class A:
  658. pass
  659. def fn():
  660. return rgc.can_move(A())
  661. return fn
  662. def test_can_move(self):
  663. assert self.run('can_move') == self.GC_CAN_MOVE
  664. def define_resizable_buffer(cls):
  665. from rpython.rtyper.lltypesystem.rstr import STR
  666. def f():
  667. ptr = lltype.malloc(STR, 3)
  668. ptr.hash = 0x62
  669. ptr.chars[0] = '0'
  670. ptr.chars[1] = 'B'
  671. ptr.chars[2] = 'C'
  672. ptr2 = rgc.ll_shrink_array(ptr, 2)
  673. return ((ptr == ptr2) +
  674. ord(ptr2.chars[0]) +
  675. (ord(ptr2.chars[1]) << 8) +
  676. (len(ptr2.chars) << 16) +
  677. (ptr2.hash << 24))
  678. return f
  679. def test_resizable_buffer(self):
  680. res = self.run('resizable_buffer')
  681. if self.GC_CAN_SHRINK_ARRAY:
  682. expected = 0x62024231
  683. else:
  684. expected = 0x62024230
  685. assert res == expected
  686. def define_hash_preservation(cls):
  687. class C:
  688. pass
  689. class D(C):
  690. pass
  691. c = C()
  692. d = D()
  693. h_d = compute_hash(d) # force to be cached on 'd', but not on 'c'
  694. h_t = compute_hash(("Hi", None, (7.5, 2, d)))
  695. S = lltype.GcStruct('S', ('x', lltype.Signed),
  696. ('a', lltype.Array(lltype.Signed)))
  697. s = lltype.malloc(S, 15, zero=True)
  698. h_s = compute_identity_hash(s) # varsized: hash not saved/restored
  699. #
  700. def f():
  701. if compute_hash(c) != compute_identity_hash(c):
  702. return 12
  703. if compute_hash(d) != h_d:
  704. return 13
  705. if compute_hash(("Hi", None, (7.5, 2, d))) != h_t:
  706. return 14
  707. c2 = C()
  708. h_c2 = compute_hash(c2)
  709. if compute_hash(c2) != h_c2:
  710. return 15
  711. if compute_identity_hash(s) == h_s:
  712. return 16 # unlikely
  713. i = 0
  714. while i < 6:
  715. rgc.collect()
  716. if compute_hash(c2) != h_c2:
  717. return i
  718. i += 1
  719. return 42
  720. return f
  721. def test_hash_preservation(self):
  722. res = self.run('hash_preservation')
  723. assert res == 42
  724. def define_hash_overflow(self):
  725. class X(object):
  726. pass
  727. def g(n):
  728. "Make a chain of n objects."
  729. x1 = None
  730. i = 0
  731. while i < n:
  732. x2 = X()
  733. x2.prev = x1
  734. x1 = x2
  735. i += 1
  736. return x1
  737. def build(xr, n):
  738. "Build the identity hashes of all n objects of the chain."
  739. i = 0
  740. while i < n:
  741. xr.hash = compute_identity_hash(xr)
  742. # ^^^ likely to trigger a collection
  743. xr = xr.prev
  744. i += 1
  745. assert xr is None
  746. def check(xr, n, step):
  747. "Check that the identity hashes are still correct."
  748. i = 0
  749. while i < n:
  750. if xr.hash != compute_identity_hash(xr):
  751. os.write(2, "wrong hash! i=%d, n=%d, step=%d\n" % (i, n,
  752. step))
  753. raise ValueError
  754. xr = xr.prev
  755. i += 1
  756. assert xr is None
  757. def h(n):
  758. x3 = g(3)
  759. x4 = g(3)
  760. x1 = g(n)
  761. build(x1, n) # can collect!
  762. check(x1, n, 1)
  763. build(x3, 3)
  764. x2 = g(n // 2) # allocate more and try again
  765. build(x2, n // 2)
  766. check(x1, n, 11)
  767. check(x2, n // 2, 12)
  768. build(x4, 3)
  769. check(x3, 3, 13) # check these old objects too
  770. check(x4, 3, 14) # check these old objects too
  771. rgc.collect()
  772. check(x1, n, 21)
  773. check(x2, n // 2, 22)
  774. check(x3, 3, 23)
  775. check(x4, 3, 24)
  776. def f():
  777. # numbers optimized for a 8MB space
  778. for n in [100000, 225000, 250000, 300000, 380000,
  779. 460000, 570000, 800000]:
  780. os.write(2, 'case %d\n' % n)
  781. rgc.collect()
  782. h(n)
  783. return -42
  784. return f
  785. def test_hash_overflow(self):
  786. res = self.run('hash_overflow')
  787. assert res == -42
  788. def define_hash_varsized(self):
  789. S = lltype.GcStruct('S', ('abc', lltype.Signed),
  790. ('def', lltype.Array(lltype.Signed)))
  791. s = lltype.malloc(S, 3, zero=True)
  792. h_s = lltype.identityhash(s)
  793. def f():
  794. return lltype.identityhash(s) - h_s # != 0 (so far),
  795. # because S is a varsized structure.
  796. return f
  797. def test_hash_varsized(self):
  798. res = self.run('hash_varsized')
  799. assert res != 0
  800. def define_arraycopy_writebarrier_int(cls):
  801. TP = lltype.GcArray(lltype.Signed)
  802. S = lltype.GcStruct('S')
  803. def fn():
  804. l = lltype.malloc(TP, 100)
  805. for i in range(100):
  806. l[i] = i * 3
  807. l2 = lltype.malloc(TP, 50)
  808. rgc.ll_arraycopy(l, l2, 40, 0, 50)
  809. # force a nursery collect
  810. x = []
  811. for i in range(20):
  812. x.append((1, lltype.malloc(S)))
  813. for i in range(50):
  814. assert l2[i] == (40 + i) * 3
  815. return 0
  816. return fn
  817. def test_arraycopy_writebarrier_int(self):
  818. self.run("arraycopy_writebarrier_int")
  819. def define_arraycopy_writebarrier_ptr(cls):
  820. TP = lltype.GcArray(lltype.Ptr(lltype.GcArray(lltype.Signed)))
  821. def fn():
  822. l = lltype.malloc(TP, 100)
  823. for i in range(100):
  824. l[i] = lltype.malloc(TP.OF.TO, i)
  825. l2 = lltype.malloc(TP, 50)
  826. rgc.ll_arraycopy(l, l2, 40, 0, 50)
  827. rgc.collect()
  828. for i in range(50):
  829. assert l2[i] == l[40 + i]
  830. return 0
  831. return fn
  832. def test_arraycopy_writebarrier_ptr(self):
  833. self.run("arraycopy_writebarrier_ptr")
  834. def define_get_rpy_roots(self):
  835. U = lltype.GcStruct('U', ('x', lltype.Signed))
  836. S = lltype.GcStruct('S', ('u', lltype.Ptr(U)))
  837. def g(s):
  838. lst = rgc.get_rpy_roots()
  839. found = False
  840. for x in lst:
  841. if x == lltype.cast_opaque_ptr(llmemory.GCREF, s):
  842. found = True
  843. if x == lltype.cast_opaque_ptr(llmemory.GCREF, s.u):
  844. os.write(2, "s.u should not be found!\n")
  845. assert False
  846. return found == 1
  847. def fn():
  848. s = lltype.malloc(S)
  849. s.u = lltype.malloc(U)
  850. found = g(s)
  851. if not found:
  852. os.write(2, "not found!\n")
  853. assert False
  854. s.u.x = 42
  855. return 0
  856. return fn
  857. def test_get_rpy_roots(self):
  858. self.run("get_rpy_roots")
  859. def define_get_rpy_referents(self):
  860. U = lltype.GcStruct('U', ('x', lltype.Signed))
  861. S = lltype.GcStruct('S', ('u', lltype.Ptr(U)))
  862. def fn():
  863. s = lltype.malloc(S)
  864. s.u = lltype.malloc(U)
  865. gcref1 = lltype.cast_opaque_ptr(llmemory.GCREF, s)
  866. gcref2 = lltype.cast_opaque_ptr(llmemory.GCREF, s.u)
  867. lst = rgc.get_rpy_referents(gcref1)
  868. assert gcref2 in lst
  869. assert gcref1 not in lst
  870. s.u.x = 42
  871. return 0
  872. return fn
  873. def test_get_rpy_referents(self):
  874. self.run("get_rpy_referents")
  875. def define_is_rpy_instance(self):
  876. class Foo:
  877. pass
  878. S = lltype.GcStruct('S', ('x', lltype.Signed))
  879. def check(gcref, expected):
  880. result = rgc._is_rpy_instance(gcref)
  881. assert result == expected
  882. def fn():
  883. s = lltype.malloc(S)
  884. gcref1 = lltype.cast_opaque_ptr(llmemory.GCREF, s)
  885. check(gcref1, False)
  886. f = Foo()
  887. gcref3 = rgc.cast_instance_to_gcref(f)
  888. check(gcref3, True)
  889. return 0
  890. return fn
  891. def test_is_rpy_instance(self):
  892. self.run("is_rpy_instance")
  893. def define_try_cast_gcref_to_instance(self):
  894. class Foo:
  895. pass
  896. class FooBar(Foo):
  897. pass
  898. class Biz(object):
  899. pass
  900. S = lltype.GcStruct('S', ('x', lltype.Signed))
  901. def fn():
  902. foo = Foo()
  903. gcref1 = rgc.cast_instance_to_gcref(foo)
  904. assert rgc.try_cast_gcref_to_instance(Foo, gcref1) is foo
  905. assert rgc.try_cast_gcref_to_instance(FooBar, gcref1) is None
  906. assert rgc.try_cast_gcref_to_instance(Biz, gcref1) is None
  907. foobar = FooBar()
  908. gcref2 = rgc.cast_instance_to_gcref(foobar)
  909. assert rgc.try_cast_gcref_to_instance(Foo, gcref2) is foobar
  910. assert rgc.try_cast_gcref_to_instance(FooBar, gcref2) is foobar
  911. assert rgc.try_cast_gcref_to_instance(Biz, gcref2) is None
  912. s = lltype.malloc(S)
  913. gcref3 = lltype.cast_opaque_ptr(llmemory.GCREF, s)
  914. assert rgc.try_cast_gcref_to_instance(Foo, gcref3) is None
  915. assert rgc.try_cast_gcref_to_instance(FooBar, gcref3) is None
  916. assert rgc.try_cast_gcref_to_instance(Biz, gcref3) is None
  917. return 0
  918. return fn
  919. def test_try_cast_gcref_to_instance(self):
  920. self.run("try_cast_gcref_to_instance")
  921. def define_get_rpy_memory_usage(self):
  922. U = lltype.GcStruct('U', ('x1', lltype.Signed),
  923. ('x2', lltype.Signed),
  924. ('x3', lltype.Signed),
  925. ('x4', lltype.Signed),
  926. ('x5', lltype.Signed),
  927. ('x6', lltype.Signed),
  928. ('x7', lltype.Signed),
  929. ('x8', lltype.Signed))
  930. S = lltype.GcStruct('S', ('u', lltype.Ptr(U)))
  931. A = lltype.GcArray(lltype.Ptr(S))
  932. def fn():
  933. s = lltype.malloc(S)
  934. s.u = lltype.malloc(U)
  935. a = lltype.malloc(A, 1000)
  936. gcref1 = lltype.cast_opaque_ptr(llmemory.GCREF, s)
  937. int1 = rgc.get_rpy_memory_usage(gcref1)
  938. assert 8 <= int1 <= 32
  939. gcref2 = lltype.cast_opaque_ptr(llmemory.GCREF, s.u)
  940. int2 = rgc.get_rpy_memory_usage(gcref2)
  941. assert 4 * 9 <= int2 <= 8 * 12
  942. gcref3 = lltype.cast_opaque_ptr(llmemory.GCREF, a)
  943. int3 = rgc.get_rpy_memory_usage(gcref3)
  944. assert 4 * 1001 <= int3 <= 8 * 1010
  945. return 0
  946. return fn
  947. def test_get_rpy_memory_usage(self):
  948. self.run("get_rpy_memory_usage")
  949. def define_get_rpy_type_index(self):
  950. U = lltype.GcStruct('U', ('x', lltype.Signed))
  951. S = lltype.GcStruct('S', ('u', lltype.Ptr(U)))
  952. A = lltype.GcArray(lltype.Ptr(S))
  953. def fn():
  954. s = lltype.malloc(S)
  955. s.u = lltype.malloc(U)
  956. a = lltype.malloc(A, 1000)
  957. s2 = lltype.malloc(S)
  958. gcref1 = lltype.cast_opaque_ptr(llmemory.GCREF, s)
  959. int1 = rgc.get_rpy_type_index(gcref1)
  960. gcref2 = lltype.cast_opaque_ptr(llmemory.GCREF, s.u)
  961. int2 = rgc.get_rpy_type_index(gcref2)
  962. gcref3 = lltype.cast_opaque_ptr(llmemory.GCREF, a)
  963. int3 = rgc.get_rpy_type_index(gcref3)
  964. gcref4 = lltype.cast_opaque_ptr(llmemory.GCREF, s2)
  965. int4 = rgc.get_rpy_type_index(gcref4)
  966. assert int1 != int2
  967. assert int1 != int3
  968. assert int2 != int3
  969. assert int1 == int4
  970. return 0
  971. return fn
  972. def test_get_rpy_type_index(self):
  973. self.run("get_rpy_type_index")
  974. filename1_dump = str(udir.join('test_dump_rpy_heap.1'))
  975. filename2_dump = str(udir.join('test_dump_rpy_heap.2'))
  976. def define_dump_rpy_heap(self):
  977. U = lltype.GcForwardReference()
  978. U.become(lltype.GcStruct('U', ('next', lltype.Ptr(U)),
  979. ('x', lltype.Signed)))
  980. S = lltype.GcStruct('S', ('u', lltype.Ptr(U)))
  981. A = lltype.GcArray(lltype.Ptr(S))
  982. filename1 = self.filename1_dump
  983. filename2 = self.filename2_dump
  984. def fn():
  985. s = lltype.malloc(S)
  986. s.u = lltype.malloc(U)
  987. s.u.next = lltype.malloc(U)
  988. s.u.next.next = lltype.malloc(U)
  989. a = lltype.malloc(A, 1000)
  990. s2 = lltype.malloc(S)
  991. #
  992. fd1 = os.open(filename1, os.O_WRONLY | os.O_CREAT, 0666)
  993. fd2 = os.open(filename2, os.O_WRONLY | os.O_CREAT, 0666)
  994. # try to ensure we get twice the exact same output below
  995. gc.collect(); gc.collect(); gc.collect()
  996. rgc.dump_rpy_heap(fd1)
  997. rgc.dump_rpy_heap(fd2) # try twice in a row
  998. keepalive_until_here(s2)
  999. keepalive_until_here(s)
  1000. keepalive_until_here(a)
  1001. os.close(fd1)
  1002. os.close(fd2)
  1003. return 0
  1004. return fn
  1005. def test_dump_rpy_heap(self):
  1006. self.run("dump_rpy_heap")
  1007. for fn in [self.filename1_dump, self.filename2_dump]:
  1008. assert os.path.exists(fn)
  1009. assert os.path.getsize(fn) > 64
  1010. f = open(self.filename1_dump)
  1011. data1 = f.read()
  1012. f.close()
  1013. f = open(self.filename2_dump)
  1014. data2 = f.read()
  1015. f.close()
  1016. assert data1 == data2
  1017. filename_dump_typeids_z = str(udir.join('test_typeids_z'))
  1018. def define_write_typeids_z(self):
  1019. U = lltype.GcForwardReference()
  1020. U.become(lltype.GcStruct('U', ('next', lltype.Ptr(U)),
  1021. ('x', lltype.Signed)))
  1022. S = lltype.GcStruct('S', ('u', lltype.Ptr(U)))
  1023. A = lltype.GcArray(lltype.Ptr(S))
  1024. filename = self.filename_dump_typeids_z
  1025. open_flags = os.O_WRONLY | os.O_CREAT | getattr(os, 'O_BINARY', 0)
  1026. def fn():
  1027. s = lltype.malloc(S)
  1028. s.u = lltype.malloc(U)
  1029. s.u.next = lltype.malloc(U)
  1030. s.u.next.next = lltype.malloc(U)
  1031. a = lltype.malloc(A, 1000)
  1032. s2 = lltype.malloc(S)
  1033. #
  1034. p = rgc.get_typeids_z()
  1035. s = ''.join([p[i] for i in range(len(p))])
  1036. fd = os.open(filename, open_flags, 0666)
  1037. os.write(fd, s)
  1038. os.close(fd)
  1039. #
  1040. a = rgc.get_typeids_list()
  1041. assert len(a) > 1
  1042. assert 0 < rffi.cast(lltype.Signed, a[1]) < 10000
  1043. return 0
  1044. return fn
  1045. def test_write_typeids_z(self):
  1046. self.run("write_typeids_z")
  1047. f = open(self.filename_dump_typeids_z, 'rb')
  1048. data_z = f.read()
  1049. f.close()
  1050. import zlib
  1051. data = zlib.decompress(data_z)
  1052. assert data.startswith('member0')
  1053. assert 'GcArray of * GcStruct S {' in data
  1054. def define_gcflag_extra(self):
  1055. class A:
  1056. pass
  1057. a1 = A()
  1058. def fn():
  1059. a2 = A()
  1060. if not rgc.has_gcflag_extra():
  1061. return 0 # cannot test it then
  1062. assert rgc.get_gcflag_extra(a1) == False
  1063. assert rgc.get_gcflag_extra(a2) == False
  1064. rgc.toggle_gcflag_extra(a1)
  1065. assert rgc.get_gcflag_extra(a1) == True
  1066. assert rgc.get_gcflag_extra(a2) == False
  1067. rgc.toggle_gcflag_extra(a2)
  1068. assert rgc.get_gcflag_extra(a1) == True
  1069. assert rgc.get_gcflag_extra(a2) == True
  1070. rgc.toggle_gcflag_extra(a1)
  1071. assert rgc.get_gcflag_extra(a1) == False
  1072. assert rgc.get_gcflag_extra(a2) == True
  1073. rgc.toggle_gcflag_extra(a2)
  1074. assert rgc.get_gcflag_extra(a1) == False
  1075. assert rgc.get_gcflag_extra(a2) == False
  1076. return 0
  1077. return fn
  1078. def test_gcflag_extra(self):
  1079. self.run("gcflag_extra")
  1080. def define_check_zero_works(self):
  1081. S = lltype.GcStruct("s", ('x', lltype.Signed))
  1082. S2 = lltype.GcStruct("s2", ('parent',
  1083. lltype.Struct("s1", ("x", lltype.Signed))),
  1084. ('y', lltype.Signed))
  1085. A = lltype.GcArray(lltype.Signed)
  1086. B = lltype.GcStruct("b", ('x', lltype.Signed),
  1087. ('y', lltype.Array(lltype.Signed)))
  1088. def fn():
  1089. s = lltype.malloc(S, zero=True)
  1090. assert s.x == 0
  1091. s2 = lltype.malloc(S2, zero=True)
  1092. assert s2.parent.x == 0
  1093. a = lltype.malloc(A, 3, zero=True)
  1094. assert a[2] == 0
  1095. # XXX not supported right now in gctransform/framework.py:
  1096. #b = lltype.malloc(B, 3, zero=True)
  1097. #assert len(b.y) == 3
  1098. #assert b.x == 0
  1099. #assert b.y[0] == b.y[1] == b.y[2] == 0
  1100. return 0
  1101. return fn
  1102. def test_check_zero_works(self):
  1103. self.run("check_zero_works")
  1104. def define_long_chain_of_instances(self):
  1105. class A(object):
  1106. def __init__(self, next):
  1107. self.next = next
  1108. a = None
  1109. for i in range(1500):
  1110. a = A(a)
  1111. def fn():
  1112. i = 0
  1113. x = a
  1114. while x is not None:
  1115. i += 1
  1116. x = x.next
  1117. return i
  1118. return fn
  1119. def test_long_chain_of_instances(self):
  1120. res = self.run("long_chain_of_instances")
  1121. assert res == 1500
  1122. class TestSemiSpaceGC(UsingFrameworkTest, snippet.SemiSpaceGCTestDefines):
  1123. gcpolicy = "semispace"
  1124. should_be_moving = True
  1125. GC_CAN_MOVE = True
  1126. GC_CAN_SHRINK_ARRAY = True
  1127. # for snippets
  1128. large_tests_ok = True
  1129. def define_many_ids(cls):
  1130. from rpython.rlib.objectmodel import compute_unique_id
  1131. class A(object):
  1132. pass
  1133. def f():
  1134. from rpython.rtyper.lltypesystem import lltype, rffi
  1135. alist = [A() for i in range(50000)]
  1136. idarray = lltype.malloc(rffi.SIGNEDP.TO, len(alist), flavor='raw')
  1137. # Compute the id of all elements of the list. The goal is
  1138. # to not allocate memory, so that if the GC needs memory to
  1139. # remember the ids, it will trigger some collections itself
  1140. i = 0
  1141. while i < len(alist):
  1142. idarray[i] = compute_unique_id(alist[i])
  1143. i += 1
  1144. j = 0
  1145. while j < 2:
  1146. if j == 1: # allocate some stuff between the two iterations
  1147. [A() for i in range(20000)]
  1148. i = 0
  1149. while i < len(alist):
  1150. if idarray[i] != compute_unique_id(alist[i]):
  1151. return j * 1000000 + i
  1152. i += 1
  1153. j += 1
  1154. lltype.free(idarray, flavor='raw')
  1155. return -2
  1156. return f
  1157. def test_many_ids(self):
  1158. res = self.run('many_ids')
  1159. assert res == -2
  1160. def define_gc_set_max_heap_size(cls):
  1161. def g(n):
  1162. return 'x' * n
  1163. def fn():
  1164. # the semispace size starts at 8MB for now, so setting a
  1165. # smaller limit has no effect
  1166. # set to more than 32MB -- which should be rounded down to 32MB
  1167. rgc.set_max_heap_size(32 * 1024 * 1024 + 20000)
  1168. s1 = s2 = s3 = None
  1169. try:
  1170. s1 = g(400000) # ~ 400 KB
  1171. s2 = g(4000000) # ~ 4 MB
  1172. s3 = g(40000000) # ~ 40 MB
  1173. except MemoryError:
  1174. pass
  1175. return (s1 is not None) + (s2 is not None) + (s3 is not None)
  1176. return fn
  1177. def test_gc_set_max_heap_size(self):
  1178. res = self.run('gc_set_max_heap_size')
  1179. assert res == 2
  1180. def define_gc_heap_stats(cls):
  1181. S = lltype.GcStruct('S', ('x', lltype.Signed))
  1182. l1 = []
  1183. l2 = []
  1184. l3 = []
  1185. def f():
  1186. for i in range(10):
  1187. s = lltype.malloc(S)
  1188. l1.append(s)
  1189. l2.append(s)
  1190. l3.append(s)
  1191. tb = rgc._heap_stats()
  1192. a = 0
  1193. nr = 0
  1194. b = 0
  1195. c = 0
  1196. for i in range(len(tb)):
  1197. if tb[i].count == 10: # the type of S
  1198. a += 1
  1199. nr = i
  1200. for i in range(len(tb)):
  1201. if tb[i].count == 3: # the type GcArray(Ptr(S))
  1202. b += 1
  1203. c += tb[i].links[nr]
  1204. # b can be 1 or 2 here since _heap_stats() is free to return or
  1205. # ignore the three GcStructs that point to the GcArray(Ptr(S)).
  1206. # important one is c, a is for check
  1207. return c * 100 + b * 10 + a
  1208. return f
  1209. def test_gc_heap_stats(self):
  1210. res = self.run("gc_heap_stats")
  1211. assert res == 3011 or res == 3021
  1212. def definestr_string_builder(cls):
  1213. def fn(_):
  1214. s = StringBuilder()
  1215. s.append("a")
  1216. s.append("abc")
  1217. s.append_slice("abc", 1, 2)
  1218. s.append_multiple_char('d', 4)
  1219. return s.build()
  1220. return fn
  1221. def test_string_builder(self):
  1222. res = self.run('string_builder')
  1223. assert res == "aabcbdddd"
  1224. def definestr_string_builder_over_allocation(cls):
  1225. def fn(_):
  1226. s = StringBuilder(4)
  1227. s.append("abcd")
  1228. s.append("defg")
  1229. s.append("rty")
  1230. s.append_multiple_char('y', 1000)
  1231. gc.collect()
  1232. s.append_multiple_char('y', 1000)
  1233. res = s.build()
  1234. gc.collect()
  1235. return res
  1236. return fn
  1237. def test_string_builder_over_allocation(self):
  1238. res = self.run('string_builder_over_allocation')
  1239. assert res[1000] == 'y'
  1240. def definestr_string_builder_multiple_builds(cls):
  1241. def fn(_):
  1242. s = StringBuilder(4)
  1243. got = []
  1244. for i in range(50):
  1245. s.append(chr(33+i))
  1246. got.append(s.build())
  1247. gc.collect()
  1248. return ' '.join(got)
  1249. return fn
  1250. def test_string_builder_multiple_builds(self):
  1251. res = self.run('string_builder_multiple_builds')
  1252. assert res == ' '.join([''.join(map(chr, range(33, 33+length)))
  1253. for length in range(1, 51)])
  1254. def definestr_string_builder_multiple_builds_2(cls):
  1255. def fn(_):
  1256. got = []
  1257. for j in range(3, 76, 5):
  1258. s = StringBuilder()
  1259. for i in range(j):
  1260. s.append(chr(33+i))
  1261. gc.collect()
  1262. got.append(s.build())
  1263. return ' '.join(got)
  1264. return fn
  1265. def test_string_builder_multiple_builds_2(self):
  1266. res = self.run('string_builder_multiple_builds_2')
  1267. assert res == ' '.join([''.join(map(chr, range(33, 33+length)))
  1268. for length in range(3, 76, 5)])
  1269. def define_nursery_hash_base(cls):
  1270. from rpython.rlib.debug import debug_print
  1271. class A:
  1272. pass
  1273. def fn():
  1274. objects = []
  1275. hashes = []
  1276. for i in range(200):
  1277. debug_print("starting nursery collection", i)
  1278. rgc.collect(0) # nursery-only collection, if possible
  1279. debug_print("finishing nursery collection", i)
  1280. obj = A()
  1281. objects.append(obj)
  1282. hashes.append(compute_identity_hash(obj))
  1283. unique = {}
  1284. debug_print("objects", len(objects))
  1285. for i in range(len(objects)):
  1286. debug_print(i)
  1287. assert compute_identity_hash(objects[i]) == hashes[i]
  1288. debug_print("storing in dict")
  1289. unique[hashes[i]] = None
  1290. debug_print("done")
  1291. debug_print("finished")
  1292. return len(unique)
  1293. return fn
  1294. def test_nursery_hash_base(self):
  1295. res = self.run('nursery_hash_base')
  1296. assert res >= 195
  1297. def define_extra_item_after_alloc(cls):
  1298. from rpython.rtyper.lltypesystem import rstr
  1299. # all STR objects should be allocated with enough space for
  1300. # one extra char. Check this with our GCs. Use strings of 8,
  1301. # 16 and 24 chars because if the extra char is missing,
  1302. # writing to it is likely to cause corruption in nearby
  1303. # structures.
  1304. sizes = [random.choice([8, 16, 24]) for i in range(100)]
  1305. A = lltype.Struct('A', ('x', lltype.Signed))
  1306. prebuilt = [(rstr.mallocstr(sz),
  1307. lltype.malloc(A, flavor='raw', immortal=True))
  1308. for sz in sizes]
  1309. k = 0
  1310. for i, (s, a) in enumerate(prebuilt):
  1311. a.x = i
  1312. for i in range(len(s.chars)):
  1313. k += 1
  1314. if k == 256:
  1315. k = 1
  1316. s.chars[i] = chr(k)
  1317. def check(lst):
  1318. hashes = []
  1319. for i, (s, a) in enumerate(lst):
  1320. assert a.x == i
  1321. rgc.ll_write_final_null_char(s)
  1322. for i, (s, a) in enumerate(lst):
  1323. assert a.x == i # check it was not overwritten
  1324. def fn():
  1325. check(prebuilt)
  1326. lst1 = []
  1327. for i, sz in enumerate(sizes):
  1328. s = rstr.mallocstr(sz)
  1329. a = lltype.malloc(A, flavor='raw')
  1330. a.x = i
  1331. lst1.append((s, a))
  1332. check(lst1)
  1333. for _, a in lst1:
  1334. lltype.free(a, flavor='raw')
  1335. return 42
  1336. return fn
  1337. def test_extra_item_after_alloc(self):
  1338. res = self.run('extra_item_after_alloc')
  1339. assert res == 42
  1340. class TestGenerationalGC(TestSemiSpaceGC):
  1341. gcpolicy = "generation"
  1342. should_be_moving = True
  1343. class TestHybridGC(TestGenerationalGC):
  1344. gcpolicy = "hybrid"
  1345. should_be_moving = True
  1346. def test_gc_set_max_heap_size(self):
  1347. py.test.skip("not implemented")
  1348. class TestHybridGCRemoveTypePtr(TestHybridGC):
  1349. removetypeptr = True
  1350. class TestMiniMarkGC(TestSemiSpaceGC):
  1351. gcpolicy = "minimark"
  1352. should_be_moving = True
  1353. GC_CAN_SHRINK_ARRAY = True
  1354. def test_gc_heap_stats(self):
  1355. py.test.skip("not implemented")
  1356. def define_nongc_attached_to_gc(cls):
  1357. from rpython.rtyper.lltypesystem import rffi
  1358. ARRAY = rffi.CArray(rffi.INT)
  1359. class A:
  1360. def __init__(self, n):
  1361. self.buf = lltype.malloc(ARRAY, n, flavor='raw',
  1362. add_memory_pressure=True)
  1363. def __del__(self):
  1364. lltype.free(self.buf, flavor='raw')
  1365. A(6)
  1366. def f():
  1367. # allocate a total of ~77GB, but if the automatic gc'ing works,
  1368. # it should never need more than a few MBs at once
  1369. am1 = am2 = am3 = None
  1370. res = 0
  1371. for i in range(1, 100001):
  1372. if am3 is not None:
  1373. res += rffi.cast(lltype.Signed, am3.buf[0])
  1374. am3 = am2
  1375. am2 = am1
  1376. am1 = A(i * 4)
  1377. am1.buf[0] = rffi.cast(rffi.INT, i - 50000)
  1378. return res
  1379. return f
  1380. def test_nongc_attached_to_gc(self):
  1381. res = self.run("nongc_attached_to_gc")
  1382. assert res == -99997
  1383. def define_nongc_opaque_attached_to_gc(cls):
  1384. from rpython.rlib import rgc, ropenssl
  1385. class A:
  1386. def __init__(self):
  1387. self.ctx = lltype.malloc(ropenssl.EVP_MD_CTX.TO,
  1388. flavor='raw')
  1389. digest = ropenssl.EVP_get_digestbyname('sha1')
  1390. ropenssl.EVP_DigestInit(self.ctx, digest)
  1391. rgc.add_memory_pressure(ropenssl.HASH_MALLOC_SIZE + 64)
  1392. def __del__(self):
  1393. ropenssl.EVP_MD_CTX_cleanup(self.ctx)
  1394. lltype.free(self.ctx, flavor='raw')
  1395. #A() --- can't call it here?? get glibc crashes on tannit64
  1396. def f():
  1397. am1 = am2 = am3 = None
  1398. for i in range(100000):
  1399. am3 = am2
  1400. am2 = am1
  1401. am1 = A()
  1402. # what can we use for the res?
  1403. return 0
  1404. return f
  1405. def test_nongc_opaque_attached_to_gc(self):
  1406. res = self.run("nongc_opaque_attached_to_gc")
  1407. assert res == 0
  1408. def define_limited_memory(self):
  1409. class A(object):
  1410. def __init__(self, next):
  1411. self.next = next
  1412. def g(i):
  1413. a = None
  1414. while i != 0:
  1415. a = A(a)
  1416. i -= 1
  1417. return 0
  1418. def f(i):
  1419. try:
  1420. return g(i)
  1421. except MemoryError:
  1422. g(20) # allocate some more stuff, but exit
  1423. return 42
  1424. return f
  1425. def test_limited_memory(self):
  1426. import random
  1427. #
  1428. def myrunner(args):
  1429. env = os.environ.copy()
  1430. env['PYPY_GC_MAX'] = '%dKB' % gcmax
  1431. return subprocess.check_output(args, env=env)
  1432. #
  1433. for i in range(10):
  1434. gcmax = random.randrange(50000, 100000)
  1435. print gcmax
  1436. res = self.run("limited_memory", -1, runner=myrunner)
  1437. assert res == 42
  1438. class TestIncrementalMiniMarkGC(TestMiniMarkGC):
  1439. gcpolicy = "incminimark"
  1440. def define_random_pin(self):
  1441. class A:
  1442. foo = None
  1443. bar = '..'
  1444. def f():
  1445. alist = [A()]
  1446. slist = ['..']
  1447. i = 0
  1448. j = 0
  1449. k = 0
  1450. while i < 400000:
  1451. k = (k * 1291 + i) % 4603
  1452. a = A()
  1453. if k < 1000:
  1454. alist.append(a)
  1455. elif k < 2000:
  1456. j = (i * k)
  1457. alist[j % len(alist)].foo = alist[(j+i) % len(alist)]
  1458. elif k < 3000:
  1459. alist[i % len(alist)].bar = slist[(j+i) % len(slist)]
  1460. elif k < 4000:
  1461. slist.append(chr(i & 255) + chr(k & 255))
  1462. elif k < 4100 and len(alist) > 1:
  1463. drop = alist.pop()
  1464. alist[i % len(alist)] = drop
  1465. elif k < 4200 and len(slist) > 1:
  1466. drop = slist.pop()
  1467. slist[i % len(slist)] = drop
  1468. elif k < 4300:
  1469. rgc.pin(slist[i % len(slist)]) # <------ pin!
  1470. keepalive_until_here(a)
  1471. i += 1
  1472. n = 0
  1473. m = 0
  1474. for i in range(len(alist)):
  1475. a = alist[i]
  1476. if a.foo is None:
  1477. n -= 1
  1478. else:
  1479. n += ord(a.foo.bar[0])
  1480. m += ord(a.foo.bar[1])
  1481. return m - n
  1482. assert f() == 28495
  1483. return f
  1484. def test_random_pin(self):
  1485. res = self.run("random_pin")
  1486. assert res == 28495
  1487. define_limited_memory_linux = TestMiniMarkGC.define_limited_memory.im_func
  1488. def test_limited_memory_linux(self):
  1489. if not sys.platform.startswith('linux'):
  1490. py.test.skip("linux only")
  1491. #
  1492. import random
  1493. #
  1494. def myrunner(args):
  1495. args1 = ['/bin/bash', '-c', 'ulimit -v %d && %s' %
  1496. (ulimitv, ' '.join(args),)]
  1497. popen = subprocess.Popen(args1, stderr=subprocess.PIPE)
  1498. _, child_stderr = popen.communicate()
  1499. assert popen.wait() == 134 # aborted
  1500. assert 'out of memory:' in child_stderr
  1501. return '42'
  1502. #
  1503. for i in range(10):
  1504. ulimitv = random.randrange(50000, 100000)
  1505. print ulimitv
  1506. res = self.run("limited_memory_linux", -1, runner=myrunner)
  1507. assert res == 42
  1508. # ____________________________________________________________________
  1509. class TaggedPointersTest(object):
  1510. taggedpointers = True
  1511. def define_tagged(cls):
  1512. class Unrelated(object):
  1513. pass
  1514. u = Unrelated()
  1515. u.x = UnboxedObject(47)
  1516. def fn(n):
  1517. rgc.collect() # check that a prebuilt tagged pointer doesn't explode
  1518. if n > 0:
  1519. x = BoxedObject(n)
  1520. else:
  1521. x = UnboxedObject(n)
  1522. u.x = x # invoke write barrier
  1523. rgc.collect()
  1524. return x.meth(100)
  1525. def func():
  1526. return fn(1000) + fn(-1000)
  1527. return func
  1528. def test_tagged(self):
  1529. expected = self.run_orig("tagged")
  1530. res = self.run("tagged")
  1531. assert res == expected
  1532. def define_erased(cls):
  1533. from rpython.rlib import rerased
  1534. erase, unerase = rerased.new_erasing_pair("test")
  1535. class Unrelated(object):
  1536. pass
  1537. u = Unrelated()
  1538. u.tagged = True
  1539. u.x = rerased.erase_int(41)
  1540. class A(object):
  1541. pass
  1542. def fn():
  1543. n = 1
  1544. while n >= 0:
  1545. if u.tagged:
  1546. n = rerased.unerase_int(u.x)
  1547. a = A()
  1548. a.n = n - 1
  1549. u.x = erase(a)
  1550. u.tagged = False
  1551. else:
  1552. n = unerase(u.x).n
  1553. u.x = rerased.erase_int(n - 1)
  1554. u.tagged = True
  1555. def func():
  1556. rgc.collect() # check that a prebuilt erased integer doesn't explode
  1557. u.x = rerased.erase_int(1000)
  1558. u.tagged = True
  1559. fn()
  1560. return 1
  1561. return func
  1562. def test_erased(self):
  1563. expected = self.run_orig("erased")
  1564. res = self.run("erased")
  1565. assert res == expected
  1566. from rpython.rlib.objectmodel import UnboxedValue
  1567. class TaggedBase(object):
  1568. __slots__ = ()
  1569. def meth(self, x):
  1570. raise NotImplementedError
  1571. class BoxedObject(TaggedBase):
  1572. attrvalue = 66
  1573. def __init__(self, normalint):
  1574. self.normalint = normalint
  1575. def meth(self, x):
  1576. return self.normalint + x + 2
  1577. class UnboxedObject(TaggedBase, UnboxedValue):
  1578. __slots__ = 'smallint'
  1579. def meth(self, x):
  1580. return self.smallint + x + 3
  1581. class TestHybridTaggedPointers(TaggedPointersTest, TestHybridGC):
  1582. pass
  1583. class TestMiniMarkGCMostCompact(TaggedPointersTest, TestMiniMarkGC):
  1584. removetypeptr = True
  1585. class TestIncrementalMiniMarkGCMostCompact(TaggedPointersTest, TestIncrementalMiniMarkGC):
  1586. removetypeptr = True