PageRenderTime 52ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/rpython/memory/test/test_transformed_gc.py

https://bitbucket.org/pypy/pypy/
Python | 1546 lines | 1507 code | 34 blank | 5 comment | 33 complexity | 92057f9db28d937568448da0a5baee25 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import py
  2. import inspect
  3. from rpython.rlib.objectmodel import compute_hash, compute_identity_hash
  4. from rpython.translator.c import gc
  5. from rpython.annotator import model as annmodel
  6. from rpython.rtyper.llannotation import SomePtr
  7. from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, llgroup
  8. from rpython.memory.gctransform import framework, shadowstack
  9. from rpython.rtyper.lltypesystem.lloperation import llop, void
  10. from rpython.rlib.objectmodel import compute_unique_id, we_are_translated
  11. from rpython.rlib.debug import ll_assert
  12. from rpython.rlib import rgc
  13. from rpython.conftest import option
  14. from rpython.rlib.rstring import StringBuilder
  15. from rpython.rlib.rarithmetic import LONG_BIT
  16. from rpython.rtyper.rtyper import llinterp_backend
  17. WORD = LONG_BIT // 8
  18. def rtype(func, inputtypes, specialize=True, gcname='ref',
  19. backendopt=False, **extraconfigopts):
  20. from rpython.translator.translator import TranslationContext
  21. t = TranslationContext()
  22. # XXX XXX XXX mess
  23. t.config.translation.gc = gcname
  24. t.config.translation.gcremovetypeptr = True
  25. t.config.set(**extraconfigopts)
  26. ann = t.buildannotator()
  27. ann.build_types(func, inputtypes)
  28. rtyper = t.buildrtyper()
  29. rtyper.backend = llinterp_backend
  30. if specialize:
  31. rtyper.specialize()
  32. if backendopt:
  33. from rpython.translator.backendopt.all import backend_optimizations
  34. backend_optimizations(t)
  35. if option.view:
  36. t.viewcg()
  37. return t
  38. ARGS = lltype.FixedSizeArray(lltype.Signed, 3)
  39. class GCTest(object):
  40. gcpolicy = None
  41. GC_CAN_MOVE = False
  42. taggedpointers = False
  43. def setup_class(cls):
  44. cls.marker = lltype.malloc(rffi.CArray(lltype.Signed), 1,
  45. flavor='raw', zero=True)
  46. funcs0 = []
  47. funcs2 = []
  48. cleanups = []
  49. name_to_func = {}
  50. mixlevelstuff = []
  51. for fullname in dir(cls):
  52. if not fullname.startswith('define'):
  53. continue
  54. definefunc = getattr(cls, fullname)
  55. _, name = fullname.split('_', 1)
  56. func_fixup = definefunc.im_func(cls)
  57. cleanup = None
  58. if isinstance(func_fixup, tuple):
  59. func, cleanup, fixup = func_fixup
  60. mixlevelstuff.append(fixup)
  61. else:
  62. func = func_fixup
  63. func.func_name = "f_%s" % name
  64. if cleanup:
  65. cleanup.func_name = "clean_%s" % name
  66. nargs = len(inspect.getargspec(func)[0])
  67. name_to_func[name] = len(funcs0)
  68. if nargs == 2:
  69. funcs2.append(func)
  70. funcs0.append(None)
  71. elif nargs == 0:
  72. funcs0.append(func)
  73. funcs2.append(None)
  74. else:
  75. raise NotImplementedError(
  76. "defined test functions should have 0/2 arguments")
  77. # used to let test cleanup static root pointing to runtime
  78. # allocated stuff
  79. cleanups.append(cleanup)
  80. def entrypoint(args):
  81. num = args[0]
  82. func = funcs0[num]
  83. if func:
  84. res = func()
  85. else:
  86. func = funcs2[num]
  87. res = func(args[1], args[2])
  88. cleanup = cleanups[num]
  89. if cleanup:
  90. cleanup()
  91. return res
  92. from rpython.translator.c.genc import CStandaloneBuilder
  93. s_args = SomePtr(lltype.Ptr(ARGS))
  94. t = rtype(entrypoint, [s_args], gcname=cls.gcname,
  95. taggedpointers=cls.taggedpointers)
  96. for fixup in mixlevelstuff:
  97. if fixup:
  98. fixup(t)
  99. cbuild = CStandaloneBuilder(t, entrypoint, config=t.config,
  100. gcpolicy=cls.gcpolicy)
  101. cbuild.make_entrypoint_wrapper = False
  102. db = cbuild.build_database()
  103. entrypointptr = cbuild.getentrypointptr()
  104. entrygraph = entrypointptr._obj.graph
  105. if option.view:
  106. t.viewcg()
  107. cls.name_to_func = name_to_func
  108. cls.entrygraph = entrygraph
  109. cls.rtyper = t.rtyper
  110. cls.db = db
  111. def runner(self, name, transformer=False):
  112. db = self.db
  113. name_to_func = self.name_to_func
  114. entrygraph = self.entrygraph
  115. from rpython.rtyper.llinterp import LLInterpreter
  116. llinterp = LLInterpreter(self.rtyper)
  117. gct = db.gctransformer
  118. if self.__class__.__dict__.get('_used', False):
  119. teardowngraph = gct.frameworkgc__teardown_ptr.value._obj.graph
  120. llinterp.eval_graph(teardowngraph, [])
  121. self.__class__._used = True
  122. # FIIIIISH
  123. setupgraph = gct.frameworkgc_setup_ptr.value._obj.graph
  124. # setup => resets the gc
  125. llinterp.eval_graph(setupgraph, [])
  126. def run(args):
  127. ll_args = lltype.malloc(ARGS, immortal=True)
  128. ll_args[0] = name_to_func[name]
  129. for i in range(len(args)):
  130. ll_args[1+i] = args[i]
  131. res = llinterp.eval_graph(entrygraph, [ll_args])
  132. return res
  133. if transformer:
  134. return run, gct
  135. else:
  136. return run
  137. class GenericGCTests(GCTest):
  138. GC_CAN_SHRINK_ARRAY = False
  139. def define_instances(cls):
  140. class A(object):
  141. pass
  142. class B(A):
  143. def __init__(self, something):
  144. self.something = something
  145. def malloc_a_lot():
  146. i = 0
  147. first = None
  148. while i < 10:
  149. i += 1
  150. a = somea = A()
  151. a.last = first
  152. first = a
  153. j = 0
  154. while j < 30:
  155. b = B(somea)
  156. b.last = first
  157. j += 1
  158. return 0
  159. return malloc_a_lot
  160. def test_instances(self):
  161. run = self.runner("instances")
  162. run([])
  163. def define_llinterp_lists(cls):
  164. def malloc_a_lot():
  165. i = 0
  166. while i < 10:
  167. i += 1
  168. a = [1] * 10
  169. j = 0
  170. while j < 30:
  171. j += 1
  172. a.append(j)
  173. return 0
  174. return malloc_a_lot
  175. def test_llinterp_lists(self):
  176. run = self.runner("llinterp_lists")
  177. run([])
  178. def define_llinterp_tuples(cls):
  179. def malloc_a_lot():
  180. i = 0
  181. while i < 10:
  182. i += 1
  183. a = (1, 2, i)
  184. b = [a] * 10
  185. j = 0
  186. while j < 20:
  187. j += 1
  188. b.append((1, j, i))
  189. return 0
  190. return malloc_a_lot
  191. def test_llinterp_tuples(self):
  192. run = self.runner("llinterp_tuples")
  193. run([])
  194. def define_llinterp_dict(self):
  195. class A(object):
  196. pass
  197. def malloc_a_lot():
  198. i = 0
  199. while i < 10:
  200. i += 1
  201. a = (1, 2, i)
  202. b = {a: A()}
  203. j = 0
  204. while j < 20:
  205. j += 1
  206. b[1, j, i] = A()
  207. return 0
  208. return malloc_a_lot
  209. def test_llinterp_dict(self):
  210. run = self.runner("llinterp_dict")
  211. run([])
  212. def skipdefine_global_list(cls):
  213. gl = []
  214. class Box:
  215. def __init__(self):
  216. self.lst = gl
  217. box = Box()
  218. def append_to_list(i, j):
  219. box.lst.append([i] * 50)
  220. llop.gc__collect(lltype.Void)
  221. return box.lst[j][0]
  222. return append_to_list, None, None
  223. def test_global_list(self):
  224. py.test.skip("doesn't fit in the model, tested elsewhere too")
  225. run = self.runner("global_list")
  226. res = run([0, 0])
  227. assert res == 0
  228. for i in range(1, 5):
  229. res = run([i, i - 1])
  230. assert res == i - 1 # crashes if constants are not considered roots
  231. def define_string_concatenation(cls):
  232. def concat(j, dummy):
  233. lst = []
  234. for i in range(j):
  235. lst.append(str(i))
  236. return len("".join(lst))
  237. return concat
  238. def test_string_concatenation(self):
  239. run = self.runner("string_concatenation")
  240. res = run([100, 0])
  241. assert res == len(''.join([str(x) for x in range(100)]))
  242. def define_nongc_static_root(cls):
  243. T1 = lltype.GcStruct("C", ('x', lltype.Signed))
  244. T2 = lltype.Struct("C", ('p', lltype.Ptr(T1)))
  245. static = lltype.malloc(T2, immortal=True)
  246. def f():
  247. t1 = lltype.malloc(T1)
  248. t1.x = 42
  249. static.p = t1
  250. llop.gc__collect(lltype.Void)
  251. return static.p.x
  252. def cleanup():
  253. static.p = lltype.nullptr(T1)
  254. return f, cleanup, None
  255. def test_nongc_static_root(self):
  256. run = self.runner("nongc_static_root")
  257. res = run([])
  258. assert res == 42
  259. def define_destructor(cls):
  260. class B(object):
  261. pass
  262. b = B()
  263. b.nextid = 0
  264. b.num_deleted = 0
  265. class A(object):
  266. def __init__(self):
  267. self.id = b.nextid
  268. b.nextid += 1
  269. def __del__(self):
  270. b.num_deleted += 1
  271. def f(x, y):
  272. a = A()
  273. i = 0
  274. while i < x:
  275. i += 1
  276. a = A()
  277. llop.gc__collect(lltype.Void)
  278. llop.gc__collect(lltype.Void)
  279. return b.num_deleted
  280. return f
  281. def test_destructor(self):
  282. run = self.runner("destructor")
  283. res = run([5, 42]) #XXX pure lazyness here too
  284. assert res == 6
  285. def define_old_style_finalizer(cls):
  286. class B(object):
  287. pass
  288. b = B()
  289. b.nextid = 0
  290. b.num_deleted = 0
  291. class A(object):
  292. def __init__(self):
  293. self.id = b.nextid
  294. b.nextid += 1
  295. def __del__(self):
  296. llop.gc__collect(lltype.Void)
  297. b.num_deleted += 1
  298. def f(x, y):
  299. a = A()
  300. i = 0
  301. while i < x:
  302. i += 1
  303. a = A()
  304. llop.gc__collect(lltype.Void)
  305. llop.gc__collect(lltype.Void)
  306. return b.num_deleted
  307. return f
  308. def test_old_style_finalizer(self):
  309. run = self.runner("old_style_finalizer")
  310. res = run([5, 42]) #XXX pure lazyness here too
  311. assert res == 6
  312. def define_finalizer(cls):
  313. class B(object):
  314. pass
  315. b = B()
  316. b.nextid = 0
  317. b.num_deleted = 0
  318. class A(object):
  319. def __init__(self):
  320. self.id = b.nextid
  321. b.nextid += 1
  322. fq.register_finalizer(self)
  323. class FQ(rgc.FinalizerQueue):
  324. Class = A
  325. def finalizer_trigger(self):
  326. while self.next_dead() is not None:
  327. b.num_deleted += 1
  328. fq = FQ()
  329. def f(x, y):
  330. a = A()
  331. i = 0
  332. while i < x:
  333. i += 1
  334. a = A()
  335. llop.gc__collect(lltype.Void)
  336. llop.gc__collect(lltype.Void)
  337. return b.num_deleted
  338. return f
  339. def test_finalizer(self):
  340. run = self.runner("finalizer")
  341. res = run([5, 42]) #XXX pure lazyness here too
  342. assert res == 6
  343. def define_finalizer_calls_malloc(cls):
  344. class B(object):
  345. pass
  346. b = B()
  347. b.nextid = 0
  348. b.num_deleted = 0
  349. class AAA(object):
  350. def __init__(self):
  351. self.id = b.nextid
  352. b.nextid += 1
  353. fq.register_finalizer(self)
  354. class C(AAA):
  355. pass
  356. class FQ(rgc.FinalizerQueue):
  357. Class = AAA
  358. def finalizer_trigger(self):
  359. while True:
  360. a = self.next_dead()
  361. if a is None:
  362. break
  363. b.num_deleted += 1
  364. if not isinstance(a, C):
  365. C()
  366. fq = FQ()
  367. def f(x, y):
  368. a = AAA()
  369. i = 0
  370. while i < x:
  371. i += 1
  372. a = AAA()
  373. llop.gc__collect(lltype.Void)
  374. llop.gc__collect(lltype.Void)
  375. return b.num_deleted
  376. return f
  377. def test_finalizer_calls_malloc(self):
  378. run = self.runner("finalizer_calls_malloc")
  379. res = run([5, 42]) #XXX pure lazyness here too
  380. assert res == 12
  381. def define_finalizer_resurrects(cls):
  382. class B(object):
  383. pass
  384. b = B()
  385. b.nextid = 0
  386. b.num_deleted = 0
  387. class A(object):
  388. def __init__(self):
  389. self.id = b.nextid
  390. b.nextid += 1
  391. fq.register_finalizer(self)
  392. class FQ(rgc.FinalizerQueue):
  393. Class = A
  394. def finalizer_trigger(self):
  395. while True:
  396. a = self.next_dead()
  397. if a is None:
  398. break
  399. b.num_deleted += 1
  400. b.a = a
  401. fq = FQ()
  402. def f(x, y):
  403. a = A()
  404. i = 0
  405. while i < x:
  406. i += 1
  407. a = A()
  408. llop.gc__collect(lltype.Void)
  409. llop.gc__collect(lltype.Void)
  410. aid = b.a.id
  411. b.a = None
  412. # check that finalizer_trigger() is not called again
  413. llop.gc__collect(lltype.Void)
  414. llop.gc__collect(lltype.Void)
  415. return b.num_deleted * 10 + aid + 100 * (b.a is None)
  416. return f
  417. def test_finalizer_resurrects(self):
  418. run = self.runner("finalizer_resurrects")
  419. res = run([5, 42]) #XXX pure lazyness here too
  420. assert 160 <= res <= 165
  421. def define_custom_trace(cls):
  422. #
  423. S = lltype.GcStruct('S', ('x', llmemory.Address))
  424. T = lltype.GcStruct('T', ('z', lltype.Signed))
  425. offset_of_x = llmemory.offsetof(S, 'x')
  426. def customtrace(gc, obj, callback, arg):
  427. gc._trace_callback(callback, arg, obj + offset_of_x)
  428. lambda_customtrace = lambda: customtrace
  429. #
  430. def setup():
  431. rgc.register_custom_trace_hook(S, lambda_customtrace)
  432. tx = lltype.malloc(T)
  433. tx.z = 4243
  434. s1 = lltype.malloc(S)
  435. s1.x = llmemory.cast_ptr_to_adr(tx)
  436. return s1
  437. def f():
  438. s1 = setup()
  439. llop.gc__collect(lltype.Void)
  440. return llmemory.cast_adr_to_ptr(s1.x, lltype.Ptr(T)).z
  441. return f
  442. def test_custom_trace(self):
  443. run = self.runner("custom_trace")
  444. res = run([])
  445. assert res == 4243
  446. def define_weakref(cls):
  447. import weakref, gc
  448. class A(object):
  449. pass
  450. def g():
  451. a = A()
  452. return weakref.ref(a)
  453. def f():
  454. a = A()
  455. ref = weakref.ref(a)
  456. result = ref() is a
  457. ref = g()
  458. llop.gc__collect(lltype.Void)
  459. result = result and (ref() is None)
  460. # check that a further collection is fine
  461. llop.gc__collect(lltype.Void)
  462. result = result and (ref() is None)
  463. return result
  464. return f
  465. def test_weakref(self):
  466. run = self.runner("weakref")
  467. res = run([])
  468. assert res
  469. def define_weakref_to_object_with_destructor(cls):
  470. import weakref, gc
  471. class A(object):
  472. count = 0
  473. a = A()
  474. class B(object):
  475. def __del__(self):
  476. a.count += 1
  477. def g():
  478. b = B()
  479. return weakref.ref(b)
  480. def f():
  481. ref = g()
  482. llop.gc__collect(lltype.Void)
  483. llop.gc__collect(lltype.Void)
  484. result = a.count == 1 and (ref() is None)
  485. return result
  486. return f
  487. def test_weakref_to_object_with_destructor(self):
  488. run = self.runner("weakref_to_object_with_destructor")
  489. res = run([])
  490. assert res
  491. def define_weakref_to_object_with_finalizer(cls):
  492. import weakref, gc
  493. class A(object):
  494. count = 0
  495. a = A()
  496. class B(object):
  497. pass
  498. class FQ(rgc.FinalizerQueue):
  499. Class = B
  500. def finalizer_trigger(self):
  501. while self.next_dead() is not None:
  502. a.count += 1
  503. fq = FQ()
  504. def g():
  505. b = B()
  506. fq.register_finalizer(b)
  507. return weakref.ref(b)
  508. def f():
  509. ref = g()
  510. llop.gc__collect(lltype.Void)
  511. llop.gc__collect(lltype.Void)
  512. result = a.count == 1 and (ref() is None)
  513. return result
  514. return f
  515. def test_weakref_to_object_with_finalizer(self):
  516. run = self.runner("weakref_to_object_with_finalizer")
  517. res = run([])
  518. assert res
  519. def define_collect_during_collect(cls):
  520. class B(object):
  521. pass
  522. b = B()
  523. b.nextid = 1
  524. b.num_deleted = 0
  525. b.num_deleted_c = 0
  526. class A(object):
  527. def __init__(self):
  528. self.id = b.nextid
  529. b.nextid += 1
  530. fq.register_finalizer(self)
  531. class C(A):
  532. pass
  533. class FQ(rgc.FinalizerQueue):
  534. Class = A
  535. def finalizer_trigger(self):
  536. while True:
  537. a = self.next_dead()
  538. if a is None:
  539. break
  540. llop.gc__collect(lltype.Void)
  541. b.num_deleted += 1
  542. if isinstance(a, C):
  543. b.num_deleted_c += 1
  544. else:
  545. C()
  546. C()
  547. fq = FQ()
  548. def f(x, y):
  549. persistent_a1 = A()
  550. persistent_a2 = A()
  551. i = 0
  552. while i < x:
  553. i += 1
  554. a = A()
  555. persistent_a3 = A()
  556. persistent_a4 = A()
  557. llop.gc__collect(lltype.Void)
  558. llop.gc__collect(lltype.Void)
  559. b.bla = persistent_a1.id + persistent_a2.id + persistent_a3.id + persistent_a4.id
  560. # NB print would create a static root!
  561. llop.debug_print(lltype.Void, b.num_deleted_c)
  562. return b.num_deleted
  563. return f
  564. def test_collect_during_collect(self):
  565. run = self.runner("collect_during_collect")
  566. # runs collect recursively 4 times
  567. res = run([4, 42]) #XXX pure lazyness here too
  568. assert res == 12
  569. def define_collect_0(cls):
  570. def concat(j, dummy):
  571. lst = []
  572. for i in range(j):
  573. lst.append(str(i))
  574. result = len("".join(lst))
  575. if we_are_translated():
  576. llop.gc__collect(lltype.Void, 0)
  577. return result
  578. return concat
  579. def test_collect_0(self):
  580. run = self.runner("collect_0")
  581. res = run([100, 0])
  582. assert res == len(''.join([str(x) for x in range(100)]))
  583. def define_interior_ptrs(cls):
  584. from rpython.rtyper.lltypesystem.lltype import Struct, GcStruct, GcArray
  585. from rpython.rtyper.lltypesystem.lltype import Array, Signed, malloc
  586. S1 = Struct("S1", ('x', Signed))
  587. T1 = GcStruct("T1", ('s', S1))
  588. def f1():
  589. t = malloc(T1)
  590. t.s.x = 1
  591. return t.s.x
  592. S2 = Struct("S2", ('x', Signed))
  593. T2 = GcArray(S2)
  594. def f2():
  595. t = malloc(T2, 1)
  596. t[0].x = 1
  597. return t[0].x
  598. S3 = Struct("S3", ('x', Signed))
  599. T3 = GcStruct("T3", ('items', Array(S3)))
  600. def f3():
  601. t = malloc(T3, 1)
  602. t.items[0].x = 1
  603. return t.items[0].x
  604. S4 = Struct("S4", ('x', Signed))
  605. T4 = Struct("T4", ('s', S4))
  606. U4 = GcArray(T4)
  607. def f4():
  608. u = malloc(U4, 1)
  609. u[0].s.x = 1
  610. return u[0].s.x
  611. S5 = Struct("S5", ('x', Signed))
  612. T5 = GcStruct("T5", ('items', Array(S5)))
  613. def f5():
  614. t = malloc(T5, 1)
  615. return len(t.items)
  616. T6 = GcStruct("T6", ('s', Array(Signed)))
  617. def f6():
  618. t = malloc(T6, 1)
  619. t.s[0] = 1
  620. return t.s[0]
  621. def func():
  622. return (f1() * 100000 +
  623. f2() * 10000 +
  624. f3() * 1000 +
  625. f4() * 100 +
  626. f5() * 10 +
  627. f6())
  628. assert func() == 111111
  629. return func
  630. def test_interior_ptrs(self):
  631. run = self.runner("interior_ptrs")
  632. res = run([])
  633. assert res == 111111
  634. def define_id(cls):
  635. class A(object):
  636. pass
  637. a1 = A()
  638. def func():
  639. a2 = A()
  640. a3 = A()
  641. id1 = compute_unique_id(a1)
  642. id2 = compute_unique_id(a2)
  643. id3 = compute_unique_id(a3)
  644. llop.gc__collect(lltype.Void)
  645. error = 0
  646. if id1 != compute_unique_id(a1): error += 1
  647. if id2 != compute_unique_id(a2): error += 2
  648. if id3 != compute_unique_id(a3): error += 4
  649. return error
  650. return func
  651. def test_id(self):
  652. run = self.runner("id")
  653. res = run([])
  654. assert res == 0
  655. def define_can_move(cls):
  656. TP = lltype.GcArray(lltype.Float)
  657. def func():
  658. return rgc.can_move(lltype.malloc(TP, 1))
  659. return func
  660. def test_can_move(self):
  661. run = self.runner("can_move")
  662. res = run([])
  663. assert res == self.GC_CAN_MOVE
  664. def define_shrink_array(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_shrink_array(self):
  680. run = self.runner("shrink_array")
  681. if self.GC_CAN_SHRINK_ARRAY:
  682. expected = 0x62024231
  683. else:
  684. expected = 0x62024230
  685. assert run([]) == expected
  686. def define_string_builder_over_allocation(cls):
  687. import gc
  688. def fn():
  689. s = StringBuilder(4)
  690. s.append("abcd")
  691. s.append("defg")
  692. s.append("rty")
  693. s.append_multiple_char('y', 1000)
  694. gc.collect()
  695. s.append_multiple_char('y', 1000)
  696. res = s.build()[1000]
  697. gc.collect()
  698. return ord(res)
  699. return fn
  700. def test_string_builder_over_allocation(self):
  701. fn = self.runner("string_builder_over_allocation")
  702. res = fn([])
  703. assert res == ord('y')
  704. class GenericMovingGCTests(GenericGCTests):
  705. GC_CAN_MOVE = True
  706. GC_CAN_TEST_ID = False
  707. def define_many_ids(cls):
  708. class A(object):
  709. pass
  710. def f():
  711. from rpython.rtyper.lltypesystem import rffi
  712. alist = [A() for i in range(50)]
  713. idarray = lltype.malloc(rffi.SIGNEDP.TO, len(alist), flavor='raw')
  714. # Compute the id of all the elements of the list. The goal is
  715. # to not allocate memory, so that if the GC needs memory to
  716. # remember the ids, it will trigger some collections itself
  717. i = 0
  718. while i < len(alist):
  719. idarray[i] = compute_unique_id(alist[i])
  720. i += 1
  721. j = 0
  722. while j < 2:
  723. if j == 1: # allocate some stuff between the two iterations
  724. [A() for i in range(20)]
  725. i = 0
  726. while i < len(alist):
  727. assert idarray[i] == compute_unique_id(alist[i])
  728. i += 1
  729. j += 1
  730. lltype.free(idarray, flavor='raw')
  731. return 0
  732. return f
  733. def test_many_ids(self):
  734. if not self.GC_CAN_TEST_ID:
  735. py.test.skip("fails for bad reasons in lltype.py :-(")
  736. run = self.runner("many_ids")
  737. run([])
  738. @classmethod
  739. def ensure_layoutbuilder(cls, translator):
  740. jit2gc = getattr(translator, '_jit2gc', None)
  741. if jit2gc:
  742. assert 'invoke_after_minor_collection' in jit2gc
  743. return jit2gc['layoutbuilder']
  744. marker = cls.marker
  745. GCClass = cls.gcpolicy.transformerclass.GCClass
  746. layoutbuilder = framework.TransformerLayoutBuilder(translator, GCClass)
  747. layoutbuilder.delay_encoding()
  748. def seeme():
  749. marker[0] += 1
  750. translator._jit2gc = {
  751. 'layoutbuilder': layoutbuilder,
  752. 'invoke_after_minor_collection': seeme,
  753. }
  754. return layoutbuilder
  755. def define_do_malloc_operations(cls):
  756. P = lltype.GcStruct('P', ('x', lltype.Signed))
  757. def g():
  758. r = lltype.malloc(P)
  759. r.x = 1
  760. p = llop.do_malloc_fixedsize(llmemory.GCREF) # placeholder
  761. p = lltype.cast_opaque_ptr(lltype.Ptr(P), p)
  762. p.x = r.x
  763. return p.x
  764. def f():
  765. i = 0
  766. while i < 40:
  767. g()
  768. i += 1
  769. return 0
  770. if cls.gcname == 'incminimark':
  771. marker = cls.marker
  772. def cleanup():
  773. assert marker[0] > 0
  774. marker[0] = 0
  775. else:
  776. cleanup = None
  777. def fix_graph_of_g(translator):
  778. from rpython.translator.translator import graphof
  779. from rpython.flowspace.model import Constant
  780. from rpython.rtyper.lltypesystem import rffi
  781. layoutbuilder = cls.ensure_layoutbuilder(translator)
  782. type_id = layoutbuilder.get_type_id(P)
  783. #
  784. # now fix the do_malloc_fixedsize in the graph of g
  785. graph = graphof(translator, g)
  786. for op in graph.startblock.operations:
  787. if op.opname == 'do_malloc_fixedsize':
  788. op.args = [Constant(type_id, llgroup.HALFWORD),
  789. Constant(llmemory.sizeof(P), lltype.Signed),
  790. Constant(False, lltype.Bool), # has_finalizer
  791. Constant(False, lltype.Bool), # is_finalizer_light
  792. Constant(False, lltype.Bool)] # contains_weakptr
  793. break
  794. else:
  795. assert 0, "oups, not found"
  796. return f, cleanup, fix_graph_of_g
  797. def test_do_malloc_operations(self):
  798. run = self.runner("do_malloc_operations")
  799. run([])
  800. def define_do_malloc_operations_in_call(cls):
  801. P = lltype.GcStruct('P', ('x', lltype.Signed))
  802. def g():
  803. llop.do_malloc_fixedsize(llmemory.GCREF) # placeholder
  804. def f():
  805. q = lltype.malloc(P)
  806. q.x = 1
  807. i = 0
  808. while i < 40:
  809. g()
  810. i += q.x
  811. return 0
  812. def fix_graph_of_g(translator):
  813. from rpython.translator.translator import graphof
  814. from rpython.flowspace.model import Constant
  815. from rpython.rtyper.lltypesystem import rffi
  816. layoutbuilder = cls.ensure_layoutbuilder(translator)
  817. type_id = layoutbuilder.get_type_id(P)
  818. #
  819. # now fix the do_malloc_fixedsize in the graph of g
  820. graph = graphof(translator, g)
  821. for op in graph.startblock.operations:
  822. if op.opname == 'do_malloc_fixedsize':
  823. op.args = [Constant(type_id, llgroup.HALFWORD),
  824. Constant(llmemory.sizeof(P), lltype.Signed),
  825. Constant(False, lltype.Bool), # has_finalizer
  826. Constant(False, lltype.Bool), # is_finalizer_light
  827. Constant(False, lltype.Bool)] # contains_weakptr
  828. break
  829. else:
  830. assert 0, "oups, not found"
  831. return f, None, fix_graph_of_g
  832. def test_do_malloc_operations_in_call(self):
  833. run = self.runner("do_malloc_operations_in_call")
  834. run([])
  835. def define_gc_heap_stats(cls):
  836. S = lltype.GcStruct('S', ('x', lltype.Signed))
  837. l1 = []
  838. l2 = []
  839. l3 = []
  840. l4 = []
  841. def f():
  842. for i in range(10):
  843. s = lltype.malloc(S)
  844. l1.append(s)
  845. l2.append(s)
  846. if i < 3:
  847. l3.append(s)
  848. l4.append(s)
  849. # We cheat here and only read the table which we later on
  850. # process ourselves, otherwise this test takes ages
  851. llop.gc__collect(lltype.Void)
  852. tb = rgc._heap_stats()
  853. a = 0
  854. nr = 0
  855. b = 0
  856. c = 0
  857. d = 0
  858. e = 0
  859. for i in range(len(tb)):
  860. if tb[i].count == 10:
  861. a += 1
  862. nr = i
  863. if tb[i].count > 50:
  864. d += 1
  865. for i in range(len(tb)):
  866. if tb[i].count == 4:
  867. b += 1
  868. c += tb[i].links[nr]
  869. e += tb[i].size
  870. return d * 1000 + c * 100 + b * 10 + a
  871. return f
  872. def test_gc_heap_stats(self):
  873. py.test.skip("this test makes the following test crash. Investigate.")
  874. run = self.runner("gc_heap_stats")
  875. res = run([])
  876. assert res % 10000 == 2611
  877. totsize = (res / 10000)
  878. size_of_int = rffi.sizeof(lltype.Signed)
  879. assert (totsize - 26 * size_of_int) % 4 == 0
  880. # ^^^ a crude assumption that totsize - varsize would be dividable by 4
  881. # (and give fixedsize)
  882. def define_writebarrier_before_copy(cls):
  883. S = lltype.GcStruct('S', ('x', lltype.Char))
  884. TP = lltype.GcArray(lltype.Ptr(S))
  885. def fn():
  886. l = lltype.malloc(TP, 100)
  887. l2 = lltype.malloc(TP, 100)
  888. for i in range(100):
  889. l[i] = lltype.malloc(S)
  890. rgc.ll_arraycopy(l, l2, 50, 0, 50)
  891. # force nursery collect
  892. x = []
  893. for i in range(20):
  894. x.append((1, lltype.malloc(S)))
  895. for i in range(50):
  896. assert l2[i] == l[50 + i]
  897. return 0
  898. return fn
  899. def test_writebarrier_before_copy(self):
  900. run = self.runner("writebarrier_before_copy")
  901. run([])
  902. # ________________________________________________________________
  903. class TestSemiSpaceGC(GenericMovingGCTests):
  904. gcname = "semispace"
  905. GC_CAN_SHRINK_ARRAY = True
  906. class gcpolicy(gc.BasicFrameworkGcPolicy):
  907. class transformerclass(shadowstack.ShadowStackFrameworkGCTransformer):
  908. from rpython.memory.gc.semispace import SemiSpaceGC as GCClass
  909. GC_PARAMS = {'space_size': 512*WORD,
  910. 'translated_to_c': False}
  911. root_stack_depth = 200
  912. class TestGenerationGC(GenericMovingGCTests):
  913. gcname = "generation"
  914. GC_CAN_SHRINK_ARRAY = True
  915. class gcpolicy(gc.BasicFrameworkGcPolicy):
  916. class transformerclass(shadowstack.ShadowStackFrameworkGCTransformer):
  917. from rpython.memory.gc.generation import GenerationGC as \
  918. GCClass
  919. GC_PARAMS = {'space_size': 512*WORD,
  920. 'nursery_size': 32*WORD,
  921. 'translated_to_c': False}
  922. root_stack_depth = 200
  923. def define_weakref_across_minor_collection(cls):
  924. import weakref
  925. class A:
  926. pass
  927. def f():
  928. x = 20 # for GenerationGC, enough for a minor collection
  929. a = A()
  930. a.foo = x
  931. ref = weakref.ref(a)
  932. all = [None] * x
  933. i = 0
  934. while i < x:
  935. all[i] = [i] * i
  936. i += 1
  937. assert ref() is a
  938. llop.gc__collect(lltype.Void)
  939. assert ref() is a
  940. return a.foo + len(all)
  941. return f
  942. def test_weakref_across_minor_collection(self):
  943. run = self.runner("weakref_across_minor_collection")
  944. res = run([])
  945. assert res == 20 + 20
  946. def define_nongc_static_root_minor_collect(cls):
  947. T1 = lltype.GcStruct("C", ('x', lltype.Signed))
  948. T2 = lltype.Struct("C", ('p', lltype.Ptr(T1)))
  949. static = lltype.malloc(T2, immortal=True)
  950. def f():
  951. t1 = lltype.malloc(T1)
  952. t1.x = 42
  953. static.p = t1
  954. x = 20
  955. all = [None] * x
  956. i = 0
  957. while i < x: # enough to cause a minor collect
  958. all[i] = [i] * i
  959. i += 1
  960. i = static.p.x
  961. llop.gc__collect(lltype.Void)
  962. return static.p.x + i
  963. def cleanup():
  964. static.p = lltype.nullptr(T1)
  965. return f, cleanup, None
  966. def test_nongc_static_root_minor_collect(self):
  967. run = self.runner("nongc_static_root_minor_collect")
  968. res = run([])
  969. assert res == 84
  970. def define_static_root_minor_collect(cls):
  971. class A:
  972. pass
  973. class B:
  974. pass
  975. static = A()
  976. static.p = None
  977. def f():
  978. t1 = B()
  979. t1.x = 42
  980. static.p = t1
  981. x = 20
  982. all = [None] * x
  983. i = 0
  984. while i < x: # enough to cause a minor collect
  985. all[i] = [i] * i
  986. i += 1
  987. i = static.p.x
  988. llop.gc__collect(lltype.Void)
  989. return static.p.x + i
  990. def cleanup():
  991. static.p = None
  992. return f, cleanup, None
  993. def test_static_root_minor_collect(self):
  994. run = self.runner("static_root_minor_collect")
  995. res = run([])
  996. assert res == 84
  997. def define_many_weakrefs(cls):
  998. # test for the case where allocating the weakref itself triggers
  999. # a collection
  1000. import weakref
  1001. class A:
  1002. pass
  1003. def f():
  1004. a = A()
  1005. i = 0
  1006. while i < 17:
  1007. ref = weakref.ref(a)
  1008. assert ref() is a
  1009. i += 1
  1010. return 0
  1011. return f
  1012. def test_many_weakrefs(self):
  1013. run = self.runner("many_weakrefs")
  1014. run([])
  1015. def define_immutable_to_old_promotion(cls):
  1016. T_CHILD = lltype.Ptr(lltype.GcStruct('Child', ('field', lltype.Signed)))
  1017. T_PARENT = lltype.Ptr(lltype.GcStruct('Parent', ('sub', T_CHILD)))
  1018. child = lltype.malloc(T_CHILD.TO)
  1019. child2 = lltype.malloc(T_CHILD.TO)
  1020. parent = lltype.malloc(T_PARENT.TO)
  1021. parent2 = lltype.malloc(T_PARENT.TO)
  1022. parent.sub = child
  1023. child.field = 3
  1024. parent2.sub = child2
  1025. child2.field = 8
  1026. T_ALL = lltype.Ptr(lltype.GcArray(T_PARENT))
  1027. all = lltype.malloc(T_ALL.TO, 2)
  1028. all[0] = parent
  1029. all[1] = parent2
  1030. def f(x, y):
  1031. res = all[x]
  1032. #all[x] = lltype.nullptr(T_PARENT.TO)
  1033. return res.sub.field
  1034. return f
  1035. def test_immutable_to_old_promotion(self):
  1036. run, transformer = self.runner("immutable_to_old_promotion", transformer=True)
  1037. run([1, 4])
  1038. if not transformer.GCClass.prebuilt_gc_objects_are_static_roots:
  1039. assert len(transformer.layoutbuilder.addresses_of_static_ptrs) == 0
  1040. else:
  1041. assert len(transformer.layoutbuilder.addresses_of_static_ptrs) >= 4
  1042. # NB. Remember that the number above does not count
  1043. # the number of prebuilt GC objects, but the number of locations
  1044. # within prebuilt GC objects that are of type Ptr(Gc).
  1045. # At the moment we get additional_roots_sources == 6:
  1046. # * all[0]
  1047. # * all[1]
  1048. # * parent.sub
  1049. # * parent2.sub
  1050. # * the GcArray pointer from gc.wr_to_objects_with_id
  1051. # * the GcArray pointer from gc.object_id_dict.
  1052. def define_adr_of_nursery(cls):
  1053. class A(object):
  1054. pass
  1055. def f():
  1056. # we need at least 1 obj to allocate a nursery
  1057. a = A()
  1058. nf_a = llop.gc_adr_of_nursery_free(llmemory.Address)
  1059. nt_a = llop.gc_adr_of_nursery_top(llmemory.Address)
  1060. nf0 = nf_a.address[0]
  1061. nt0 = nt_a.address[0]
  1062. a0 = A()
  1063. a1 = A()
  1064. nf1 = nf_a.address[0]
  1065. nt1 = nt_a.address[0]
  1066. assert nf1 > nf0
  1067. assert nt1 > nf1
  1068. assert nt1 == nt0
  1069. return 0
  1070. return f
  1071. def test_adr_of_nursery(self):
  1072. run = self.runner("adr_of_nursery")
  1073. res = run([])
  1074. class TestGenerationalNoFullCollectGC(GCTest):
  1075. # test that nursery is doing its job and that no full collection
  1076. # is needed when most allocated objects die quickly
  1077. gcname = "generation"
  1078. class gcpolicy(gc.BasicFrameworkGcPolicy):
  1079. class transformerclass(shadowstack.ShadowStackFrameworkGCTransformer):
  1080. from rpython.memory.gc.generation import GenerationGC
  1081. class GCClass(GenerationGC):
  1082. __ready = False
  1083. def setup(self):
  1084. from rpython.memory.gc.generation import GenerationGC
  1085. GenerationGC.setup(self)
  1086. self.__ready = True
  1087. def semispace_collect(self, size_changing=False):
  1088. ll_assert(not self.__ready,
  1089. "no full collect should occur in this test")
  1090. def _teardown(self):
  1091. self.__ready = False # collecting here is expected
  1092. GenerationGC._teardown(self)
  1093. GC_PARAMS = {'space_size': 512*WORD,
  1094. 'nursery_size': 128*WORD,
  1095. 'translated_to_c': False}
  1096. root_stack_depth = 200
  1097. def define_working_nursery(cls):
  1098. def f():
  1099. total = 0
  1100. i = 0
  1101. while i < 40:
  1102. lst = []
  1103. j = 0
  1104. while j < 5:
  1105. lst.append(i*j)
  1106. j += 1
  1107. total += len(lst)
  1108. i += 1
  1109. return total
  1110. return f
  1111. def test_working_nursery(self):
  1112. run = self.runner("working_nursery")
  1113. res = run([])
  1114. assert res == 40 * 5
  1115. class TestHybridGC(TestGenerationGC):
  1116. gcname = "hybrid"
  1117. class gcpolicy(gc.BasicFrameworkGcPolicy):
  1118. class transformerclass(shadowstack.ShadowStackFrameworkGCTransformer):
  1119. from rpython.memory.gc.hybrid import HybridGC as GCClass
  1120. GC_PARAMS = {'space_size': 512*WORD,
  1121. 'nursery_size': 32*WORD,
  1122. 'large_object': 8*WORD,
  1123. 'translated_to_c': False}
  1124. root_stack_depth = 200
  1125. def define_ref_from_rawmalloced_to_regular(cls):
  1126. import gc
  1127. S = lltype.GcStruct('S', ('x', lltype.Signed))
  1128. A = lltype.GcStruct('A', ('p', lltype.Ptr(S)),
  1129. ('a', lltype.Array(lltype.Char)))
  1130. def setup(j):
  1131. p = lltype.malloc(S)
  1132. p.x = j*2
  1133. lst = lltype.malloc(A, j)
  1134. # the following line generates a write_barrier call at the moment,
  1135. # which is important because the 'lst' can be allocated directly
  1136. # in generation 2. This can only occur with varsized mallocs.
  1137. lst.p = p
  1138. return lst
  1139. def f(i, j):
  1140. lst = setup(j)
  1141. gc.collect()
  1142. return lst.p.x
  1143. return f
  1144. def test_ref_from_rawmalloced_to_regular(self):
  1145. run = self.runner("ref_from_rawmalloced_to_regular")
  1146. res = run([100, 100])
  1147. assert res == 200
  1148. def define_write_barrier_direct(cls):
  1149. from rpython.rlib import rgc
  1150. S = lltype.GcForwardReference()
  1151. S.become(lltype.GcStruct('S',
  1152. ('x', lltype.Signed),
  1153. ('prev', lltype.Ptr(S)),
  1154. ('next', lltype.Ptr(S))))
  1155. s0 = lltype.malloc(S, immortal=True)
  1156. def f():
  1157. s = lltype.malloc(S)
  1158. s.x = 42
  1159. llop.bare_setfield(lltype.Void, s0, void('next'), s)
  1160. llop.gc_writebarrier(lltype.Void, llmemory.cast_ptr_to_adr(s0))
  1161. rgc.collect(0)
  1162. return s0.next.x
  1163. def cleanup():
  1164. s0.next = lltype.nullptr(S)
  1165. return f, cleanup, None
  1166. def test_write_barrier_direct(self):
  1167. run = self.runner("write_barrier_direct")
  1168. res = run([])
  1169. assert res == 42
  1170. class TestMiniMarkGC(TestHybridGC):
  1171. gcname = "minimark"
  1172. GC_CAN_TEST_ID = True
  1173. class gcpolicy(gc.BasicFrameworkGcPolicy):
  1174. class transformerclass(shadowstack.ShadowStackFrameworkGCTransformer):
  1175. from rpython.memory.gc.minimark import MiniMarkGC as GCClass
  1176. GC_PARAMS = {'nursery_size': 32*WORD,
  1177. 'page_size': 16*WORD,
  1178. 'arena_size': 64*WORD,
  1179. 'small_request_threshold': 5*WORD,
  1180. 'large_object': 8*WORD,
  1181. 'card_page_indices': 4,
  1182. 'translated_to_c': False,
  1183. }
  1184. root_stack_depth = 200
  1185. def define_no_clean_setarrayitems(cls):
  1186. # The optimization find_clean_setarrayitems() in
  1187. # gctransformer/framework.py does not work with card marking.
  1188. # Check that it is turned off.
  1189. S = lltype.GcStruct('S', ('x', lltype.Signed))
  1190. A = lltype.GcArray(lltype.Ptr(S))
  1191. def sub(lst):
  1192. lst[15] = lltype.malloc(S) # 'lst' is set the single mark "12-15"
  1193. lst[15].x = 123
  1194. lst[0] = lst[15] # that would be a "clean_setarrayitem"
  1195. def f():
  1196. lst = lltype.malloc(A, 16) # 16 > 10
  1197. rgc.collect()
  1198. sub(lst)
  1199. null = lltype.nullptr(S)
  1200. lst[15] = null # clear, so that A() is only visible via lst[0]
  1201. rgc.collect() # -> crash
  1202. return lst[0].x
  1203. return f
  1204. def test_no_clean_setarrayitems(self):
  1205. run = self.runner("no_clean_setarrayitems")
  1206. res = run([])
  1207. assert res == 123
  1208. def define_nursery_hash_base(cls):
  1209. class A:
  1210. pass
  1211. def fn():
  1212. objects = []
  1213. hashes = []
  1214. for i in range(200):
  1215. rgc.collect(0) # nursery-only collection, if possible
  1216. obj = A()
  1217. objects.append(obj)
  1218. hashes.append(compute_identity_hash(obj))
  1219. unique = {}
  1220. for i in range(len(objects)):
  1221. assert compute_identity_hash(objects[i]) == hashes[i]
  1222. unique[hashes[i]] = None
  1223. return len(unique)
  1224. return fn
  1225. def test_nursery_hash_base(self):
  1226. res = self.runner('nursery_hash_base')
  1227. assert res([]) >= 195
  1228. def define_instantiate_nonmovable(cls):
  1229. from rpython.rlib import objectmodel
  1230. from rpython.rtyper import annlowlevel
  1231. class A:
  1232. pass
  1233. def fn():
  1234. a1 = A()
  1235. a = objectmodel.instantiate(A, nonmovable=True)
  1236. a.next = a1 # 'a' is known young here, so no write barrier emitted
  1237. res = rgc.can_move(annlowlevel.cast_instance_to_base_ptr(a))
  1238. rgc.collect()
  1239. objectmodel.keepalive_until_here(a)
  1240. return res
  1241. return fn
  1242. def test_instantiate_nonmovable(self):
  1243. res = self.runner('instantiate_nonmovable')
  1244. assert res([]) == 0
  1245. class TestIncrementalMiniMarkGC(TestMiniMarkGC):
  1246. gcname = "incminimark"
  1247. class gcpolicy(gc.BasicFrameworkGcPolicy):
  1248. class transformerclass(shadowstack.ShadowStackFrameworkGCTransformer):
  1249. from rpython.memory.gc.incminimark import IncrementalMiniMarkGC \
  1250. as GCClass
  1251. GC_PARAMS = {'nursery_size': 32*WORD,
  1252. 'page_size': 16*WORD,
  1253. 'arena_size': 64*WORD,
  1254. 'small_request_threshold': 5*WORD,
  1255. 'large_object': 8*WORD,
  1256. 'card_page_indices': 4,
  1257. 'translated_to_c': False,
  1258. }
  1259. root_stack_depth = 200
  1260. def define_malloc_array_of_gcptr(self):
  1261. S = lltype.GcStruct('S', ('x', lltype.Signed))
  1262. A = lltype.GcArray(lltype.Ptr(S))
  1263. def f():
  1264. lst = lltype.malloc(A, 5)
  1265. return (lst[0] == lltype.nullptr(S)
  1266. and lst[1] == lltype.nullptr(S)
  1267. and lst[2] == lltype.nullptr(S)
  1268. and lst[3] == lltype.nullptr(S)
  1269. and lst[4] == lltype.nullptr(S))
  1270. return f
  1271. def test_malloc_array_of_gcptr(self):
  1272. run = self.runner('malloc_array_of_gcptr')
  1273. res = run([])
  1274. assert res
  1275. def define_malloc_struct_of_gcptr(cls):
  1276. S1 = lltype.GcStruct('S', ('x', lltype.Signed))
  1277. S = lltype.GcStruct('S',
  1278. ('x', lltype.Signed),
  1279. ('filed1', lltype.Ptr(S1)),
  1280. ('filed2', lltype.Ptr(S1)))
  1281. s0 = lltype.malloc(S)
  1282. def f():
  1283. return (s0.filed1 == lltype.nullptr(S1) and s0.filed2 == lltype.nullptr(S1))
  1284. return f
  1285. def test_malloc_struct_of_gcptr(self):
  1286. run = self.runner("malloc_struct_of_gcptr")
  1287. res = run([])
  1288. assert res
  1289. # ________________________________________________________________
  1290. # tagged pointers
  1291. class TaggedPointerGCTests(GCTest):
  1292. taggedpointers = True
  1293. def define_tagged_simple(cls):
  1294. class Unrelated(object):
  1295. pass
  1296. u = Unrelated()
  1297. u.x = UnboxedObject(47)
  1298. def fn(n):
  1299. rgc.collect() # check that a prebuilt tagged pointer doesn't explode
  1300. if n > 0:
  1301. x = BoxedObject(n)
  1302. else:
  1303. x = UnboxedObject(n)
  1304. u.x = x # invoke write barrier
  1305. rgc.collect()
  1306. return x.meth(100)
  1307. def func():
  1308. return fn(1000) + fn(-1000)
  1309. assert func() == 205
  1310. return func
  1311. def test_tagged_simple(self):
  1312. func = self.runner("tagged_simple")
  1313. res = func([])
  1314. assert res == 205
  1315. def define_tagged_prebuilt(cls):
  1316. class F:
  1317. pass
  1318. f = F()
  1319. f.l = [UnboxedObject(10)]
  1320. def fn(n):
  1321. if n > 0:
  1322. x = BoxedObject(n)
  1323. else:
  1324. x = UnboxedObject(n)
  1325. f.l.append(x)
  1326. rgc.collect()
  1327. return f.l[-1].meth(100)
  1328. def func():
  1329. return fn(1000) ^ fn(-1000)
  1330. assert func() == -1999
  1331. return func
  1332. def test_tagged_prebuilt(self):
  1333. func = self.runner("tagged_prebuilt")
  1334. res = func([])
  1335. assert res == -1999
  1336. def define_gettypeid(cls):
  1337. class A(object):
  1338. pass
  1339. def fn():
  1340. a = A()
  1341. return rgc.get_typeid(a)
  1342. return fn
  1343. def test_gettypeid(self):
  1344. func = self.runner("gettypeid")
  1345. res = func([])
  1346. print res
  1347. from rpython.rlib.objectmodel import UnboxedValue
  1348. class TaggedBase(object):
  1349. __slots__ = ()
  1350. def meth(self, x):
  1351. raise NotImplementedError
  1352. class BoxedObject(TaggedBase):
  1353. attrvalue = 66
  1354. def __init__(self, normalint):
  1355. self.normalint = normalint
  1356. def meth(self, x):
  1357. return self.normalint + x + 2
  1358. class UnboxedObject(TaggedBase, UnboxedValue):
  1359. __slots__ = 'smallint'
  1360. def meth(self, x):
  1361. return self.smallint + x + 3
  1362. class TestHybridTaggedPointerGC(TaggedPointerGCTests):
  1363. gcname = "hybrid"
  1364. class gcpolicy(gc.BasicFrameworkGcPolicy):
  1365. class transformerclass(shadowstack.ShadowStackFrameworkGCTransformer):
  1366. from rpython.memory.gc.generation import GenerationGC as \
  1367. GCClass
  1368. GC_PARAMS = {'space_size': 512*WORD,
  1369. 'nursery_size': 32*WORD,
  1370. 'translated_to_c': False}
  1371. root_stack_depth = 200
  1372. def test_gettypeid(self):
  1373. py.test.skip("fails for obscure reasons")