[pypy-commit] pypy default: merge
fijal
noreply at buildbot.pypy.org
Tue Mar 26 07:00:16 CET 2013
Author: Maciej Fijalkowski <fijall at gmail.com>
Branch:
Changeset: r62801:01e22513aa0a
Date: 2013-03-25 22:59 -0700
http://bitbucket.org/pypy/pypy/changeset/01e22513aa0a/
Log: merge
diff too long, truncating to 2000 out of 2044 lines
diff --git a/rpython/memory/test/gc_test_base.py b/rpython/memory/test/gc_test_base.py
new file mode 100644
--- /dev/null
+++ b/rpython/memory/test/gc_test_base.py
@@ -0,0 +1,803 @@
+import py
+import sys
+
+from rpython.memory import gcwrapper
+from rpython.memory.test import snippet
+from rpython.rtyper.test.test_llinterp import get_interpreter
+from rpython.rtyper.lltypesystem import lltype
+from rpython.rtyper.lltypesystem.lloperation import llop
+from rpython.rlib.objectmodel import we_are_translated
+from rpython.rlib.objectmodel import compute_unique_id
+from rpython.rlib import rgc
+from rpython.rlib.rstring import StringBuilder
+from rpython.rlib.rarithmetic import LONG_BIT
+
+WORD = LONG_BIT // 8
+
+
+def stdout_ignore_ll_functions(msg):
+ strmsg = str(msg)
+ if "evaluating" in strmsg and "ll_" in strmsg:
+ return
+ print >>sys.stdout, strmsg
+
+
+class GCTest(object):
+ GC_PARAMS = {}
+ GC_CAN_MOVE = False
+ GC_CAN_MALLOC_NONMOVABLE = True
+ GC_CAN_SHRINK_ARRAY = False
+ GC_CAN_SHRINK_BIG_ARRAY = False
+ BUT_HOW_BIG_IS_A_BIG_STRING = 3*WORD
+
+ def setup_class(cls):
+ cls._saved_logstate = py.log._getstate()
+ py.log.setconsumer("llinterp", py.log.STDOUT)
+ py.log.setconsumer("llinterp frame", stdout_ignore_ll_functions)
+ py.log.setconsumer("llinterp operation", None)
+
+ def teardown_class(cls):
+ py.log._setstate(cls._saved_logstate)
+
+ def interpret(self, func, values, **kwds):
+ interp, graph = get_interpreter(func, values, **kwds)
+ gcwrapper.prepare_graphs_and_create_gc(interp, self.GCClass,
+ self.GC_PARAMS)
+ return interp.eval_graph(graph, values)
+
+ def test_llinterp_lists(self):
+ #curr = simulator.current_size
+ def malloc_a_lot():
+ i = 0
+ while i < 10:
+ i += 1
+ a = [1] * 10
+ j = 0
+ while j < 20:
+ j += 1
+ a.append(j)
+ self.interpret(malloc_a_lot, [])
+ #assert simulator.current_size - curr < 16000 * INT_SIZE / 4
+ #print "size before: %s, size after %s" % (curr, simulator.current_size)
+
+ def test_llinterp_tuples(self):
+ #curr = simulator.current_size
+ def malloc_a_lot():
+ i = 0
+ while i < 10:
+ i += 1
+ a = (1, 2, i)
+ b = [a] * 10
+ j = 0
+ while j < 20:
+ j += 1
+ b.append((1, j, i))
+ self.interpret(malloc_a_lot, [])
+ #assert simulator.current_size - curr < 16000 * INT_SIZE / 4
+ #print "size before: %s, size after %s" % (curr, simulator.current_size)
+
+ def test_global_list(self):
+ lst = []
+ def append_to_list(i, j):
+ lst.append([i] * 50)
+ return lst[j][0]
+ res = self.interpret(append_to_list, [0, 0])
+ assert res == 0
+ for i in range(1, 15):
+ res = self.interpret(append_to_list, [i, i - 1])
+ assert res == i - 1 # crashes if constants are not considered roots
+
+ def test_string_concatenation(self):
+ #curr = simulator.current_size
+ def concat(j):
+ lst = []
+ for i in range(j):
+ lst.append(str(i))
+ return len("".join(lst))
+ res = self.interpret(concat, [100])
+ assert res == concat(100)
+ #assert simulator.current_size - curr < 16000 * INT_SIZE / 4
+
+
+ def test_collect(self):
+ #curr = simulator.current_size
+ def concat(j):
+ lst = []
+ for i in range(j):
+ lst.append(str(i))
+ result = len("".join(lst))
+ if we_are_translated():
+ # can't call llop.gc__collect directly
+ llop.gc__collect(lltype.Void)
+ return result
+ res = self.interpret(concat, [100])
+ assert res == concat(100)
+ #assert simulator.current_size - curr < 16000 * INT_SIZE / 4
+
+ def test_collect_0(self):
+ #curr = simulator.current_size
+ def concat(j):
+ lst = []
+ for i in range(j):
+ lst.append(str(i))
+ result = len("".join(lst))
+ if we_are_translated():
+ # can't call llop.gc__collect directly
+ llop.gc__collect(lltype.Void, 0)
+ return result
+ res = self.interpret(concat, [100])
+ assert res == concat(100)
+ #assert simulator.current_size - curr < 16000 * INT_SIZE / 4
+
+ def test_finalizer(self):
+ class B(object):
+ pass
+ b = B()
+ b.nextid = 0
+ b.num_deleted = 0
+ class A(object):
+ def __init__(self):
+ self.id = b.nextid
+ b.nextid += 1
+ def __del__(self):
+ b.num_deleted += 1
+ def f(x):
+ a = A()
+ i = 0
+ while i < x:
+ i += 1
+ a = A()
+ llop.gc__collect(lltype.Void)
+ llop.gc__collect(lltype.Void)
+ return b.num_deleted
+ res = self.interpret(f, [5])
+ assert res == 6
+
+ def test_finalizer_calls_malloc(self):
+ class B(object):
+ pass
+ b = B()
+ b.nextid = 0
+ b.num_deleted = 0
+ class A(object):
+ def __init__(self):
+ self.id = b.nextid
+ b.nextid += 1
+ def __del__(self):
+ b.num_deleted += 1
+ C()
+ class C(A):
+ def __del__(self):
+ b.num_deleted += 1
+ def f(x):
+ a = A()
+ i = 0
+ while i < x:
+ i += 1
+ a = A()
+ llop.gc__collect(lltype.Void)
+ llop.gc__collect(lltype.Void)
+ return b.num_deleted
+ res = self.interpret(f, [5])
+ assert res == 12
+
+ def test_finalizer_calls_collect(self):
+ class B(object):
+ pass
+ b = B()
+ b.nextid = 0
+ b.num_deleted = 0
+ class A(object):
+ def __init__(self):
+ self.id = b.nextid
+ b.nextid += 1
+ def __del__(self):
+ b.num_deleted += 1
+ llop.gc__collect(lltype.Void)
+ def f(x):
+ a = A()
+ i = 0
+ while i < x:
+ i += 1
+ a = A()
+ llop.gc__collect(lltype.Void)
+ llop.gc__collect(lltype.Void)
+ return b.num_deleted
+ res = self.interpret(f, [5])
+ assert res == 6
+
+ def test_finalizer_resurrects(self):
+ class B(object):
+ pass
+ b = B()
+ b.nextid = 0
+ b.num_deleted = 0
+ class A(object):
+ def __init__(self):
+ self.id = b.nextid
+ b.nextid += 1
+ def __del__(self):
+ b.num_deleted += 1
+ b.a = self
+ def f(x):
+ a = A()
+ i = 0
+ while i < x:
+ i += 1
+ a = A()
+ llop.gc__collect(lltype.Void)
+ llop.gc__collect(lltype.Void)
+ aid = b.a.id
+ b.a = None
+ # check that __del__ is not called again
+ llop.gc__collect(lltype.Void)
+ llop.gc__collect(lltype.Void)
+ return b.num_deleted * 10 + aid + 100 * (b.a is None)
+ res = self.interpret(f, [5])
+ assert 160 <= res <= 165
+
+ def test_custom_trace(self):
+ from rpython.rtyper.annlowlevel import llhelper
+ from rpython.rtyper.lltypesystem import llmemory
+ from rpython.rtyper.lltypesystem.llarena import ArenaError
+ #
+ S = lltype.GcStruct('S', ('x', llmemory.Address),
+ ('y', llmemory.Address), rtti=True)
+ T = lltype.GcStruct('T', ('z', lltype.Signed))
+ offset_of_x = llmemory.offsetof(S, 'x')
+ def customtrace(obj, prev):
+ if not prev:
+ return obj + offset_of_x
+ else:
+ return llmemory.NULL
+ CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address],
+ llmemory.Address)
+ customtraceptr = llhelper(lltype.Ptr(CUSTOMTRACEFUNC), customtrace)
+ lltype.attachRuntimeTypeInfo(S, customtraceptr=customtraceptr)
+ #
+ for attrname in ['x', 'y']:
+ def setup():
+ s1 = lltype.malloc(S)
+ tx = lltype.malloc(T)
+ tx.z = 42
+ ty = lltype.malloc(T)
+ s1.x = llmemory.cast_ptr_to_adr(tx)
+ s1.y = llmemory.cast_ptr_to_adr(ty)
+ return s1
+ def f():
+ s1 = setup()
+ llop.gc__collect(lltype.Void)
+ return llmemory.cast_adr_to_ptr(getattr(s1, attrname),
+ lltype.Ptr(T))
+ if attrname == 'x':
+ res = self.interpret(f, [])
+ assert res.z == 42
+ else:
+ py.test.raises((RuntimeError, ArenaError),
+ self.interpret, f, [])
+
+ def test_weakref(self):
+ import weakref
+ class A(object):
+ pass
+ def g():
+ a = A()
+ return weakref.ref(a)
+ def f():
+ a = A()
+ ref = weakref.ref(a)
+ result = ref() is a
+ ref = g()
+ llop.gc__collect(lltype.Void)
+ result = result and (ref() is None)
+ # check that a further collection is fine
+ llop.gc__collect(lltype.Void)
+ result = result and (ref() is None)
+ return result
+ res = self.interpret(f, [])
+ assert res
+
+ def test_weakref_to_object_with_finalizer(self):
+ import weakref
+ class A(object):
+ count = 0
+ a = A()
+ class B(object):
+ def __del__(self):
+ a.count += 1
+ def g():
+ b = B()
+ return weakref.ref(b)
+ def f():
+ ref = g()
+ llop.gc__collect(lltype.Void)
+ llop.gc__collect(lltype.Void)
+ result = a.count == 1 and (ref() is None)
+ return result
+ res = self.interpret(f, [])
+ assert res
+
+ def test_bug_1(self):
+ import weakref
+ class B(object):
+ pass
+ def g():
+ b = B()
+ llop.gc__collect(lltype.Void) # force 'b' to be old
+ ref = weakref.ref(B())
+ b.ref = ref
+ return ref
+ def f():
+ ref = g()
+ llop.gc__collect(lltype.Void)
+ llop.gc__collect(lltype.Void)
+ result = (ref() is None)
+ return result
+ res = self.interpret(f, [])
+ assert res
+
+ def test_cycle_with_weakref_and_del(self):
+ import weakref
+ class A(object):
+ count = 0
+ a = A()
+ class B(object):
+ def __del__(self):
+ # when __del__ is called, the weakref to c should be dead
+ if self.ref() is None:
+ a.count += 10 # ok
+ else:
+ a.count = 666 # not ok
+ class C(object):
+ pass
+ def g():
+ c = C()
+ c.b = B()
+ ref = weakref.ref(c)
+ c.b.ref = ref
+ return ref
+ def f():
+ ref = g()
+ llop.gc__collect(lltype.Void)
+ llop.gc__collect(lltype.Void)
+ result = a.count + (ref() is None)
+ return result
+ res = self.interpret(f, [])
+ assert res == 11
+
+ def test_weakref_to_object_with_finalizer_ordering(self):
+ import weakref
+ class A(object):
+ count = 0
+ a = A()
+ class B(object):
+ def __del__(self):
+ # when __del__ is called, the weakref to myself is still valid
+ # in RPython (at least with most GCs; this test might be
+ # skipped for specific GCs)
+ if self.ref() is self:
+ a.count += 10 # ok
+ else:
+ a.count = 666 # not ok
+ def g():
+ b = B()
+ ref = weakref.ref(b)
+ b.ref = ref
+ return ref
+ def f():
+ ref = g()
+ llop.gc__collect(lltype.Void)
+ llop.gc__collect(lltype.Void)
+ result = a.count + (ref() is None)
+ return result
+ res = self.interpret(f, [])
+ assert res == 11
+
+ def test_weakref_bug_1(self):
+ import weakref
+ class A(object):
+ pass
+ class B(object):
+ def __del__(self):
+ self.wref().x += 1
+ def g(a):
+ b = B()
+ b.wref = weakref.ref(a)
+ # the only way to reach this weakref is via B, which is an
+ # object with finalizer (but the weakref itself points to
+ # a, which does not go away but will move during the next
+ # gc.collect)
+ def f():
+ a = A()
+ a.x = 10
+ g(a)
+ llop.gc__collect(lltype.Void)
+ return a.x
+ res = self.interpret(f, [])
+ assert res == 11
+
+ def test_id(self):
+ class A(object):
+ pass
+ a1 = A()
+ def f():
+ a2 = A()
+ a3 = A()
+ id1 = compute_unique_id(a1)
+ id2 = compute_unique_id(a2)
+ id3 = compute_unique_id(a3)
+ llop.gc__collect(lltype.Void)
+ error = 0
+ if id1 != compute_unique_id(a1): error += 1
+ if id2 != compute_unique_id(a2): error += 2
+ if id3 != compute_unique_id(a3): error += 4
+ return error
+ res = self.interpret(f, [])
+ assert res == 0
+
+ def test_finalizer_calls_malloc_during_minor_collect(self):
+ # originally a GenerationGC test, this has also found bugs in other GCs
+ class B(object):
+ pass
+ b = B()
+ b.nextid = 0
+ b.num_deleted = 0
+ b.all = []
+ class A(object):
+ def __init__(self):
+ self.id = b.nextid
+ b.nextid += 1
+ def __del__(self):
+ b.num_deleted += 1
+ b.all.append(D(b.num_deleted))
+ class D(object):
+ # make a big object that does not use malloc_varsize
+ def __init__(self, x):
+ self.x00 = self.x01 = self.x02 = self.x03 = self.x04 = x
+ self.x10 = self.x11 = self.x12 = self.x13 = self.x14 = x
+ self.x20 = self.x21 = self.x22 = self.x23 = self.x24 = x
+ def f(x):
+ i = 0
+ all = [None] * x
+ a = A()
+ while i < x:
+ d = D(i)
+ all[i] = d
+ i += 1
+ return b.num_deleted + len(all)
+ res = self.interpret(f, [500])
+ assert res == 1 + 500
+
+
+ def test_collect_during_collect(self):
+ class B(object):
+ pass
+ b = B()
+ b.nextid = 1
+ b.num_deleted = 0
+ b.num_deleted_c = 0
+ class A(object):
+ def __init__(self):
+ self.id = b.nextid
+ b.nextid += 1
+ def __del__(self):
+ llop.gc__collect(lltype.Void)
+ b.num_deleted += 1
+ C()
+ C()
+ class C(A):
+ def __del__(self):
+ b.num_deleted += 1
+ b.num_deleted_c += 1
+ def f(x, y):
+ persistent_a1 = A()
+ persistent_a2 = A()
+ i = 0
+ while i < x:
+ i += 1
+ a = A()
+ persistent_a3 = A()
+ persistent_a4 = A()
+ llop.gc__collect(lltype.Void)
+ llop.gc__collect(lltype.Void)
+ b.bla = persistent_a1.id + persistent_a2.id + persistent_a3.id + persistent_a4.id
+ print b.num_deleted_c
+ return b.num_deleted
+ res = self.interpret(f, [4, 42])
+ assert res == 12
+
+ def test_print_leak(self):
+ def f(n):
+ for i in range(n):
+ print i
+ return 42
+ res = self.interpret(f, [10])
+ assert res == 42
+
+ def test_weakref_across_minor_collection(self):
+ import weakref
+ class A:
+ pass
+ def f(x):
+ a = A()
+ a.foo = x
+ ref = weakref.ref(a)
+ all = [None] * x
+ i = 0
+ while i < x:
+ all[i] = [i] * i
+ i += 1
+ assert ref() is a
+ llop.gc__collect(lltype.Void)
+ assert ref() is a
+ return a.foo + len(all)
+ res = self.interpret(f, [20]) # for GenerationGC, enough for a minor collection
+ assert res == 20 + 20
+
+ def test_young_weakref_to_old_object(self):
+ import weakref
+ class A:
+ pass
+ def f(x):
+ a = A()
+ llop.gc__collect(lltype.Void)
+ # 'a' is old, 'ref' is young
+ ref = weakref.ref(a)
+ # now trigger a minor collection
+ all = [None] * x
+ i = 0
+ while i < x:
+ all[i] = [i] * i
+ i += 1
+ # now 'a' is old, but 'ref' did not move
+ assert ref() is a
+ llop.gc__collect(lltype.Void)
+ # now both 'a' and 'ref' have moved
+ return ref() is a
+ res = self.interpret(f, [20]) # for GenerationGC, enough for a minor collection
+ assert res == True
+
+ def test_weakref_to_prebuilt(self):
+ import weakref
+ class A:
+ pass
+ a = A()
+ def f(x):
+ ref = weakref.ref(a)
+ assert ref() is a
+ llop.gc__collect(lltype.Void)
+ return ref() is a
+ res = self.interpret(f, [20]) # for GenerationGC, enough for a minor collection
+ assert res == True
+
+ def test_many_weakrefs(self):
+ # test for the case where allocating the weakref itself triggers
+ # a collection
+ import weakref
+ class A:
+ pass
+ def f(x):
+ a = A()
+ i = 0
+ while i < x:
+ ref = weakref.ref(a)
+ assert ref() is a
+ i += 1
+ self.interpret(f, [1100])
+
+ def test_nongc_static_root(self):
+ from rpython.rtyper.lltypesystem import lltype
+ T1 = lltype.GcStruct("C", ('x', lltype.Signed))
+ T2 = lltype.Struct("C", ('p', lltype.Ptr(T1)))
+ static = lltype.malloc(T2, immortal=True)
+ def f():
+ t1 = lltype.malloc(T1)
+ t1.x = 42
+ static.p = t1
+ llop.gc__collect(lltype.Void)
+ return static.p.x
+ res = self.interpret(f, [])
+ assert res == 42
+
+ def test_can_move(self):
+ TP = lltype.GcArray(lltype.Float)
+ def func():
+ return rgc.can_move(lltype.malloc(TP, 1))
+ assert self.interpret(func, []) == self.GC_CAN_MOVE
+
+
+ def test_malloc_nonmovable(self):
+ TP = lltype.GcArray(lltype.Char)
+ def func():
+ a = rgc.malloc_nonmovable(TP, 3)
+ if a:
+ assert not rgc.can_move(a)
+ return 1
+ return 0
+
+ assert self.interpret(func, []) == int(self.GC_CAN_MALLOC_NONMOVABLE)
+
+ def test_malloc_nonmovable_fixsize(self):
+ S = lltype.GcStruct('S', ('x', lltype.Float))
+ TP = lltype.GcStruct('T', ('s', lltype.Ptr(S)))
+ def func():
+ try:
+ a = rgc.malloc_nonmovable(TP)
+ rgc.collect()
+ if a:
+ assert not rgc.can_move(a)
+ return 1
+ return 0
+ except Exception:
+ return 2
+
+ assert self.interpret(func, []) == int(self.GC_CAN_MALLOC_NONMOVABLE)
+
+ def test_shrink_array(self):
+ from rpython.rtyper.lltypesystem.rstr import STR
+
+ def f(n, m, gc_can_shrink_array):
+ ptr = lltype.malloc(STR, n)
+ ptr.hash = 0x62
+ ptr.chars[0] = 'A'
+ ptr.chars[1] = 'B'
+ ptr.chars[2] = 'C'
+ ptr2 = rgc.ll_shrink_array(ptr, 2)
+ assert (ptr == ptr2) == gc_can_shrink_array
+ rgc.collect()
+ return ( ord(ptr2.chars[0]) +
+ (ord(ptr2.chars[1]) << 8) +
+ (len(ptr2.chars) << 16) +
+ (ptr2.hash << 24))
+
+ flag = self.GC_CAN_SHRINK_ARRAY
+ assert self.interpret(f, [3, 0, flag]) == 0x62024241
+ # with larger numbers, it gets allocated outside the semispace
+ # with some GCs.
+ flag = self.GC_CAN_SHRINK_BIG_ARRAY
+ bigsize = self.BUT_HOW_BIG_IS_A_BIG_STRING
+ assert self.interpret(f, [bigsize, 0, flag]) == 0x62024241
+
+ def test_tagged_simple(self):
+ class Unrelated(object):
+ pass
+
+ u = Unrelated()
+ u.x = UnboxedObject(47)
+ def fn(n):
+ rgc.collect() # check that a prebuilt tagged pointer doesn't explode
+ if n > 0:
+ x = BoxedObject(n)
+ else:
+ x = UnboxedObject(n)
+ u.x = x # invoke write barrier
+ rgc.collect()
+ return x.meth(100)
+ res = self.interpret(fn, [1000], taggedpointers=True)
+ assert res == 1102
+ res = self.interpret(fn, [-1000], taggedpointers=True)
+ assert res == -897
+
+ def test_tagged_prebuilt(self):
+
+ class F:
+ pass
+
+ f = F()
+ f.l = [UnboxedObject(10)]
+ def fn(n):
+ if n > 0:
+ x = BoxedObject(n)
+ else:
+ x = UnboxedObject(n)
+ f.l.append(x)
+ rgc.collect()
+ return f.l[-1].meth(100)
+ res = self.interpret(fn, [1000], taggedpointers=True)
+ assert res == 1102
+ res = self.interpret(fn, [-1000], taggedpointers=True)
+ assert res == -897
+
+ def test_tagged_id(self):
+ class Unrelated(object):
+ pass
+
+ u = Unrelated()
+ u.x = UnboxedObject(0)
+ def fn(n):
+ id_prebuilt1 = compute_unique_id(u.x)
+ if n > 0:
+ x = BoxedObject(n)
+ else:
+ x = UnboxedObject(n)
+ id_x1 = compute_unique_id(x)
+ rgc.collect() # check that a prebuilt tagged pointer doesn't explode
+ id_prebuilt2 = compute_unique_id(u.x)
+ id_x2 = compute_unique_id(x)
+ print u.x, id_prebuilt1, id_prebuilt2
+ print x, id_x1, id_x2
+ return ((id_x1 == id_x2) * 1 +
+ (id_prebuilt1 == id_prebuilt2) * 10 +
+ (id_x1 != id_prebuilt1) * 100)
+ res = self.interpret(fn, [1000], taggedpointers=True)
+ assert res == 111
+ res = self.interpret(fn, [-1000], taggedpointers=True)
+ assert res == 111
+
+ def test_writebarrier_before_copy(self):
+ S = lltype.GcStruct('S', ('x', lltype.Char))
+ TP = lltype.GcArray(lltype.Ptr(S))
+ def fn():
+ l = lltype.malloc(TP, 100)
+ l2 = lltype.malloc(TP, 100)
+ for i in range(100):
+ l[i] = lltype.malloc(S)
+ rgc.ll_arraycopy(l, l2, 50, 0, 50)
+ x = []
+ # force minor collect
+ t = (1, lltype.malloc(S))
+ for i in range(20):
+ x.append(t)
+ for i in range(50):
+ assert l2[i] == l[50 + i]
+ return 0
+
+ self.interpret(fn, [])
+
+ def test_stringbuilder(self):
+ def fn():
+ s = StringBuilder(4)
+ s.append("abcd")
+ s.append("defg")
+ s.append("rty")
+ s.append_multiple_char('y', 1000)
+ rgc.collect()
+ s.append_multiple_char('y', 1000)
+ res = s.build()[1000]
+ rgc.collect()
+ return ord(res)
+ res = self.interpret(fn, [])
+ assert res == ord('y')
+
+ def test_gcflag_extra(self):
+ class A:
+ pass
+ a1 = A()
+ def fn():
+ a2 = A()
+ if not rgc.has_gcflag_extra():
+ return # cannot test it then
+ assert rgc.get_gcflag_extra(a1) == False
+ assert rgc.get_gcflag_extra(a2) == False
+ rgc.toggle_gcflag_extra(a1)
+ assert rgc.get_gcflag_extra(a1) == True
+ assert rgc.get_gcflag_extra(a2) == False
+ rgc.toggle_gcflag_extra(a2)
+ assert rgc.get_gcflag_extra(a1) == True
+ assert rgc.get_gcflag_extra(a2) == True
+ rgc.toggle_gcflag_extra(a1)
+ assert rgc.get_gcflag_extra(a1) == False
+ assert rgc.get_gcflag_extra(a2) == True
+ rgc.toggle_gcflag_extra(a2)
+ assert rgc.get_gcflag_extra(a1) == False
+ assert rgc.get_gcflag_extra(a2) == False
+ self.interpret(fn, [])
+
+from rpython.rlib.objectmodel import UnboxedValue
+
+class TaggedBase(object):
+ __slots__ = ()
+ def meth(self, x):
+ raise NotImplementedError
+
+class BoxedObject(TaggedBase):
+ attrvalue = 66
+ def __init__(self, normalint):
+ self.normalint = normalint
+ def meth(self, x):
+ return self.normalint + x + 2
+
+class UnboxedObject(TaggedBase, UnboxedValue):
+ __slots__ = 'smallint'
+ def meth(self, x):
+ return self.smallint + x + 3
diff --git a/rpython/memory/test/test_gc.py b/rpython/memory/test/test_gc.py
deleted file mode 100644
--- a/rpython/memory/test/test_gc.py
+++ /dev/null
@@ -1,945 +0,0 @@
-import py
-import sys
-
-from rpython.memory import gcwrapper
-from rpython.memory.test import snippet
-from rpython.rtyper.test.test_llinterp import get_interpreter
-from rpython.rtyper.lltypesystem import lltype
-from rpython.rtyper.lltypesystem.lloperation import llop
-from rpython.rlib.objectmodel import we_are_translated
-from rpython.rlib.objectmodel import compute_unique_id
-from rpython.rlib import rgc
-from rpython.rlib.rstring import StringBuilder
-from rpython.rlib.rarithmetic import LONG_BIT
-
-WORD = LONG_BIT // 8
-
-
-def stdout_ignore_ll_functions(msg):
- strmsg = str(msg)
- if "evaluating" in strmsg and "ll_" in strmsg:
- return
- print >>sys.stdout, strmsg
-
-
-class GCTest(object):
- GC_PARAMS = {}
- GC_CAN_MOVE = False
- GC_CAN_MALLOC_NONMOVABLE = True
- GC_CAN_SHRINK_ARRAY = False
- GC_CAN_SHRINK_BIG_ARRAY = False
- BUT_HOW_BIG_IS_A_BIG_STRING = 3*WORD
-
- def setup_class(cls):
- cls._saved_logstate = py.log._getstate()
- py.log.setconsumer("llinterp", py.log.STDOUT)
- py.log.setconsumer("llinterp frame", stdout_ignore_ll_functions)
- py.log.setconsumer("llinterp operation", None)
-
- def teardown_class(cls):
- py.log._setstate(cls._saved_logstate)
-
- def interpret(self, func, values, **kwds):
- interp, graph = get_interpreter(func, values, **kwds)
- gcwrapper.prepare_graphs_and_create_gc(interp, self.GCClass,
- self.GC_PARAMS)
- return interp.eval_graph(graph, values)
-
- def test_llinterp_lists(self):
- #curr = simulator.current_size
- def malloc_a_lot():
- i = 0
- while i < 10:
- i += 1
- a = [1] * 10
- j = 0
- while j < 20:
- j += 1
- a.append(j)
- self.interpret(malloc_a_lot, [])
- #assert simulator.current_size - curr < 16000 * INT_SIZE / 4
- #print "size before: %s, size after %s" % (curr, simulator.current_size)
-
- def test_llinterp_tuples(self):
- #curr = simulator.current_size
- def malloc_a_lot():
- i = 0
- while i < 10:
- i += 1
- a = (1, 2, i)
- b = [a] * 10
- j = 0
- while j < 20:
- j += 1
- b.append((1, j, i))
- self.interpret(malloc_a_lot, [])
- #assert simulator.current_size - curr < 16000 * INT_SIZE / 4
- #print "size before: %s, size after %s" % (curr, simulator.current_size)
-
- def test_global_list(self):
- lst = []
- def append_to_list(i, j):
- lst.append([i] * 50)
- return lst[j][0]
- res = self.interpret(append_to_list, [0, 0])
- assert res == 0
- for i in range(1, 15):
- res = self.interpret(append_to_list, [i, i - 1])
- assert res == i - 1 # crashes if constants are not considered roots
-
- def test_string_concatenation(self):
- #curr = simulator.current_size
- def concat(j):
- lst = []
- for i in range(j):
- lst.append(str(i))
- return len("".join(lst))
- res = self.interpret(concat, [100])
- assert res == concat(100)
- #assert simulator.current_size - curr < 16000 * INT_SIZE / 4
-
-
- def test_collect(self):
- #curr = simulator.current_size
- def concat(j):
- lst = []
- for i in range(j):
- lst.append(str(i))
- result = len("".join(lst))
- if we_are_translated():
- # can't call llop.gc__collect directly
- llop.gc__collect(lltype.Void)
- return result
- res = self.interpret(concat, [100])
- assert res == concat(100)
- #assert simulator.current_size - curr < 16000 * INT_SIZE / 4
-
- def test_collect_0(self):
- #curr = simulator.current_size
- def concat(j):
- lst = []
- for i in range(j):
- lst.append(str(i))
- result = len("".join(lst))
- if we_are_translated():
- # can't call llop.gc__collect directly
- llop.gc__collect(lltype.Void, 0)
- return result
- res = self.interpret(concat, [100])
- assert res == concat(100)
- #assert simulator.current_size - curr < 16000 * INT_SIZE / 4
-
- def test_finalizer(self):
- class B(object):
- pass
- b = B()
- b.nextid = 0
- b.num_deleted = 0
- class A(object):
- def __init__(self):
- self.id = b.nextid
- b.nextid += 1
- def __del__(self):
- b.num_deleted += 1
- def f(x):
- a = A()
- i = 0
- while i < x:
- i += 1
- a = A()
- llop.gc__collect(lltype.Void)
- llop.gc__collect(lltype.Void)
- return b.num_deleted
- res = self.interpret(f, [5])
- assert res == 6
-
- def test_finalizer_calls_malloc(self):
- class B(object):
- pass
- b = B()
- b.nextid = 0
- b.num_deleted = 0
- class A(object):
- def __init__(self):
- self.id = b.nextid
- b.nextid += 1
- def __del__(self):
- b.num_deleted += 1
- C()
- class C(A):
- def __del__(self):
- b.num_deleted += 1
- def f(x):
- a = A()
- i = 0
- while i < x:
- i += 1
- a = A()
- llop.gc__collect(lltype.Void)
- llop.gc__collect(lltype.Void)
- return b.num_deleted
- res = self.interpret(f, [5])
- assert res == 12
-
- def test_finalizer_calls_collect(self):
- class B(object):
- pass
- b = B()
- b.nextid = 0
- b.num_deleted = 0
- class A(object):
- def __init__(self):
- self.id = b.nextid
- b.nextid += 1
- def __del__(self):
- b.num_deleted += 1
- llop.gc__collect(lltype.Void)
- def f(x):
- a = A()
- i = 0
- while i < x:
- i += 1
- a = A()
- llop.gc__collect(lltype.Void)
- llop.gc__collect(lltype.Void)
- return b.num_deleted
- res = self.interpret(f, [5])
- assert res == 6
-
- def test_finalizer_resurrects(self):
- class B(object):
- pass
- b = B()
- b.nextid = 0
- b.num_deleted = 0
- class A(object):
- def __init__(self):
- self.id = b.nextid
- b.nextid += 1
- def __del__(self):
- b.num_deleted += 1
- b.a = self
- def f(x):
- a = A()
- i = 0
- while i < x:
- i += 1
- a = A()
- llop.gc__collect(lltype.Void)
- llop.gc__collect(lltype.Void)
- aid = b.a.id
- b.a = None
- # check that __del__ is not called again
- llop.gc__collect(lltype.Void)
- llop.gc__collect(lltype.Void)
- return b.num_deleted * 10 + aid + 100 * (b.a is None)
- res = self.interpret(f, [5])
- assert 160 <= res <= 165
-
- def test_custom_trace(self):
- from rpython.rtyper.annlowlevel import llhelper
- from rpython.rtyper.lltypesystem import llmemory
- from rpython.rtyper.lltypesystem.llarena import ArenaError
- #
- S = lltype.GcStruct('S', ('x', llmemory.Address),
- ('y', llmemory.Address), rtti=True)
- T = lltype.GcStruct('T', ('z', lltype.Signed))
- offset_of_x = llmemory.offsetof(S, 'x')
- def customtrace(obj, prev):
- if not prev:
- return obj + offset_of_x
- else:
- return llmemory.NULL
- CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address],
- llmemory.Address)
- customtraceptr = llhelper(lltype.Ptr(CUSTOMTRACEFUNC), customtrace)
- lltype.attachRuntimeTypeInfo(S, customtraceptr=customtraceptr)
- #
- for attrname in ['x', 'y']:
- def setup():
- s1 = lltype.malloc(S)
- tx = lltype.malloc(T)
- tx.z = 42
- ty = lltype.malloc(T)
- s1.x = llmemory.cast_ptr_to_adr(tx)
- s1.y = llmemory.cast_ptr_to_adr(ty)
- return s1
- def f():
- s1 = setup()
- llop.gc__collect(lltype.Void)
- return llmemory.cast_adr_to_ptr(getattr(s1, attrname),
- lltype.Ptr(T))
- if attrname == 'x':
- res = self.interpret(f, [])
- assert res.z == 42
- else:
- py.test.raises((RuntimeError, ArenaError),
- self.interpret, f, [])
-
- def test_weakref(self):
- import weakref
- class A(object):
- pass
- def g():
- a = A()
- return weakref.ref(a)
- def f():
- a = A()
- ref = weakref.ref(a)
- result = ref() is a
- ref = g()
- llop.gc__collect(lltype.Void)
- result = result and (ref() is None)
- # check that a further collection is fine
- llop.gc__collect(lltype.Void)
- result = result and (ref() is None)
- return result
- res = self.interpret(f, [])
- assert res
-
- def test_weakref_to_object_with_finalizer(self):
- import weakref
- class A(object):
- count = 0
- a = A()
- class B(object):
- def __del__(self):
- a.count += 1
- def g():
- b = B()
- return weakref.ref(b)
- def f():
- ref = g()
- llop.gc__collect(lltype.Void)
- llop.gc__collect(lltype.Void)
- result = a.count == 1 and (ref() is None)
- return result
- res = self.interpret(f, [])
- assert res
-
- def test_bug_1(self):
- import weakref
- class B(object):
- pass
- def g():
- b = B()
- llop.gc__collect(lltype.Void) # force 'b' to be old
- ref = weakref.ref(B())
- b.ref = ref
- return ref
- def f():
- ref = g()
- llop.gc__collect(lltype.Void)
- llop.gc__collect(lltype.Void)
- result = (ref() is None)
- return result
- res = self.interpret(f, [])
- assert res
-
- def test_cycle_with_weakref_and_del(self):
- import weakref
- class A(object):
- count = 0
- a = A()
- class B(object):
- def __del__(self):
- # when __del__ is called, the weakref to c should be dead
- if self.ref() is None:
- a.count += 10 # ok
- else:
- a.count = 666 # not ok
- class C(object):
- pass
- def g():
- c = C()
- c.b = B()
- ref = weakref.ref(c)
- c.b.ref = ref
- return ref
- def f():
- ref = g()
- llop.gc__collect(lltype.Void)
- llop.gc__collect(lltype.Void)
- result = a.count + (ref() is None)
- return result
- res = self.interpret(f, [])
- assert res == 11
-
- def test_weakref_to_object_with_finalizer_ordering(self):
- import weakref
- class A(object):
- count = 0
- a = A()
- class B(object):
- def __del__(self):
- # when __del__ is called, the weakref to myself is still valid
- # in RPython (at least with most GCs; this test might be
- # skipped for specific GCs)
- if self.ref() is self:
- a.count += 10 # ok
- else:
- a.count = 666 # not ok
- def g():
- b = B()
- ref = weakref.ref(b)
- b.ref = ref
- return ref
- def f():
- ref = g()
- llop.gc__collect(lltype.Void)
- llop.gc__collect(lltype.Void)
- result = a.count + (ref() is None)
- return result
- res = self.interpret(f, [])
- assert res == 11
-
- def test_weakref_bug_1(self):
- import weakref
- class A(object):
- pass
- class B(object):
- def __del__(self):
- self.wref().x += 1
- def g(a):
- b = B()
- b.wref = weakref.ref(a)
- # the only way to reach this weakref is via B, which is an
- # object with finalizer (but the weakref itself points to
- # a, which does not go away but will move during the next
- # gc.collect)
- def f():
- a = A()
- a.x = 10
- g(a)
- llop.gc__collect(lltype.Void)
- return a.x
- res = self.interpret(f, [])
- assert res == 11
-
- def test_id(self):
- class A(object):
- pass
- a1 = A()
- def f():
- a2 = A()
- a3 = A()
- id1 = compute_unique_id(a1)
- id2 = compute_unique_id(a2)
- id3 = compute_unique_id(a3)
- llop.gc__collect(lltype.Void)
- error = 0
- if id1 != compute_unique_id(a1): error += 1
- if id2 != compute_unique_id(a2): error += 2
- if id3 != compute_unique_id(a3): error += 4
- return error
- res = self.interpret(f, [])
- assert res == 0
-
- def test_finalizer_calls_malloc_during_minor_collect(self):
- # originally a GenerationGC test, this has also found bugs in other GCs
- class B(object):
- pass
- b = B()
- b.nextid = 0
- b.num_deleted = 0
- b.all = []
- class A(object):
- def __init__(self):
- self.id = b.nextid
- b.nextid += 1
- def __del__(self):
- b.num_deleted += 1
- b.all.append(D(b.num_deleted))
- class D(object):
- # make a big object that does not use malloc_varsize
- def __init__(self, x):
- self.x00 = self.x01 = self.x02 = self.x03 = self.x04 = x
- self.x10 = self.x11 = self.x12 = self.x13 = self.x14 = x
- self.x20 = self.x21 = self.x22 = self.x23 = self.x24 = x
- def f(x):
- i = 0
- all = [None] * x
- a = A()
- while i < x:
- d = D(i)
- all[i] = d
- i += 1
- return b.num_deleted + len(all)
- res = self.interpret(f, [500])
- assert res == 1 + 500
-
-
- def test_collect_during_collect(self):
- class B(object):
- pass
- b = B()
- b.nextid = 1
- b.num_deleted = 0
- b.num_deleted_c = 0
- class A(object):
- def __init__(self):
- self.id = b.nextid
- b.nextid += 1
- def __del__(self):
- llop.gc__collect(lltype.Void)
- b.num_deleted += 1
- C()
- C()
- class C(A):
- def __del__(self):
- b.num_deleted += 1
- b.num_deleted_c += 1
- def f(x, y):
- persistent_a1 = A()
- persistent_a2 = A()
- i = 0
- while i < x:
- i += 1
- a = A()
- persistent_a3 = A()
- persistent_a4 = A()
- llop.gc__collect(lltype.Void)
- llop.gc__collect(lltype.Void)
- b.bla = persistent_a1.id + persistent_a2.id + persistent_a3.id + persistent_a4.id
- print b.num_deleted_c
- return b.num_deleted
- res = self.interpret(f, [4, 42])
- assert res == 12
-
- def test_print_leak(self):
- def f(n):
- for i in range(n):
- print i
- return 42
- res = self.interpret(f, [10])
- assert res == 42
-
- def test_weakref_across_minor_collection(self):
- import weakref
- class A:
- pass
- def f(x):
- a = A()
- a.foo = x
- ref = weakref.ref(a)
- all = [None] * x
- i = 0
- while i < x:
- all[i] = [i] * i
- i += 1
- assert ref() is a
- llop.gc__collect(lltype.Void)
- assert ref() is a
- return a.foo + len(all)
- res = self.interpret(f, [20]) # for GenerationGC, enough for a minor collection
- assert res == 20 + 20
-
- def test_young_weakref_to_old_object(self):
- import weakref
- class A:
- pass
- def f(x):
- a = A()
- llop.gc__collect(lltype.Void)
- # 'a' is old, 'ref' is young
- ref = weakref.ref(a)
- # now trigger a minor collection
- all = [None] * x
- i = 0
- while i < x:
- all[i] = [i] * i
- i += 1
- # now 'a' is old, but 'ref' did not move
- assert ref() is a
- llop.gc__collect(lltype.Void)
- # now both 'a' and 'ref' have moved
- return ref() is a
- res = self.interpret(f, [20]) # for GenerationGC, enough for a minor collection
- assert res == True
-
- def test_weakref_to_prebuilt(self):
- import weakref
- class A:
- pass
- a = A()
- def f(x):
- ref = weakref.ref(a)
- assert ref() is a
- llop.gc__collect(lltype.Void)
- return ref() is a
- res = self.interpret(f, [20]) # for GenerationGC, enough for a minor collection
- assert res == True
-
- def test_many_weakrefs(self):
- # test for the case where allocating the weakref itself triggers
- # a collection
- import weakref
- class A:
- pass
- def f(x):
- a = A()
- i = 0
- while i < x:
- ref = weakref.ref(a)
- assert ref() is a
- i += 1
- self.interpret(f, [1100])
-
- def test_nongc_static_root(self):
- from rpython.rtyper.lltypesystem import lltype
- T1 = lltype.GcStruct("C", ('x', lltype.Signed))
- T2 = lltype.Struct("C", ('p', lltype.Ptr(T1)))
- static = lltype.malloc(T2, immortal=True)
- def f():
- t1 = lltype.malloc(T1)
- t1.x = 42
- static.p = t1
- llop.gc__collect(lltype.Void)
- return static.p.x
- res = self.interpret(f, [])
- assert res == 42
-
- def test_can_move(self):
- TP = lltype.GcArray(lltype.Float)
- def func():
- return rgc.can_move(lltype.malloc(TP, 1))
- assert self.interpret(func, []) == self.GC_CAN_MOVE
-
-
- def test_malloc_nonmovable(self):
- TP = lltype.GcArray(lltype.Char)
- def func():
- a = rgc.malloc_nonmovable(TP, 3)
- if a:
- assert not rgc.can_move(a)
- return 1
- return 0
-
- assert self.interpret(func, []) == int(self.GC_CAN_MALLOC_NONMOVABLE)
-
- def test_malloc_nonmovable_fixsize(self):
- S = lltype.GcStruct('S', ('x', lltype.Float))
- TP = lltype.GcStruct('T', ('s', lltype.Ptr(S)))
- def func():
- try:
- a = rgc.malloc_nonmovable(TP)
- rgc.collect()
- if a:
- assert not rgc.can_move(a)
- return 1
- return 0
- except Exception:
- return 2
-
- assert self.interpret(func, []) == int(self.GC_CAN_MALLOC_NONMOVABLE)
-
- def test_shrink_array(self):
- from rpython.rtyper.lltypesystem.rstr import STR
-
- def f(n, m, gc_can_shrink_array):
- ptr = lltype.malloc(STR, n)
- ptr.hash = 0x62
- ptr.chars[0] = 'A'
- ptr.chars[1] = 'B'
- ptr.chars[2] = 'C'
- ptr2 = rgc.ll_shrink_array(ptr, 2)
- assert (ptr == ptr2) == gc_can_shrink_array
- rgc.collect()
- return ( ord(ptr2.chars[0]) +
- (ord(ptr2.chars[1]) << 8) +
- (len(ptr2.chars) << 16) +
- (ptr2.hash << 24))
-
- flag = self.GC_CAN_SHRINK_ARRAY
- assert self.interpret(f, [3, 0, flag]) == 0x62024241
- # with larger numbers, it gets allocated outside the semispace
- # with some GCs.
- flag = self.GC_CAN_SHRINK_BIG_ARRAY
- bigsize = self.BUT_HOW_BIG_IS_A_BIG_STRING
- assert self.interpret(f, [bigsize, 0, flag]) == 0x62024241
-
- def test_tagged_simple(self):
- class Unrelated(object):
- pass
-
- u = Unrelated()
- u.x = UnboxedObject(47)
- def fn(n):
- rgc.collect() # check that a prebuilt tagged pointer doesn't explode
- if n > 0:
- x = BoxedObject(n)
- else:
- x = UnboxedObject(n)
- u.x = x # invoke write barrier
- rgc.collect()
- return x.meth(100)
- res = self.interpret(fn, [1000], taggedpointers=True)
- assert res == 1102
- res = self.interpret(fn, [-1000], taggedpointers=True)
- assert res == -897
-
- def test_tagged_prebuilt(self):
-
- class F:
- pass
-
- f = F()
- f.l = [UnboxedObject(10)]
- def fn(n):
- if n > 0:
- x = BoxedObject(n)
- else:
- x = UnboxedObject(n)
- f.l.append(x)
- rgc.collect()
- return f.l[-1].meth(100)
- res = self.interpret(fn, [1000], taggedpointers=True)
- assert res == 1102
- res = self.interpret(fn, [-1000], taggedpointers=True)
- assert res == -897
-
- def test_tagged_id(self):
- class Unrelated(object):
- pass
-
- u = Unrelated()
- u.x = UnboxedObject(0)
- def fn(n):
- id_prebuilt1 = compute_unique_id(u.x)
- if n > 0:
- x = BoxedObject(n)
- else:
- x = UnboxedObject(n)
- id_x1 = compute_unique_id(x)
- rgc.collect() # check that a prebuilt tagged pointer doesn't explode
- id_prebuilt2 = compute_unique_id(u.x)
- id_x2 = compute_unique_id(x)
- print u.x, id_prebuilt1, id_prebuilt2
- print x, id_x1, id_x2
- return ((id_x1 == id_x2) * 1 +
- (id_prebuilt1 == id_prebuilt2) * 10 +
- (id_x1 != id_prebuilt1) * 100)
- res = self.interpret(fn, [1000], taggedpointers=True)
- assert res == 111
- res = self.interpret(fn, [-1000], taggedpointers=True)
- assert res == 111
-
- def test_writebarrier_before_copy(self):
- S = lltype.GcStruct('S', ('x', lltype.Char))
- TP = lltype.GcArray(lltype.Ptr(S))
- def fn():
- l = lltype.malloc(TP, 100)
- l2 = lltype.malloc(TP, 100)
- for i in range(100):
- l[i] = lltype.malloc(S)
- rgc.ll_arraycopy(l, l2, 50, 0, 50)
- x = []
- # force minor collect
- t = (1, lltype.malloc(S))
- for i in range(20):
- x.append(t)
- for i in range(50):
- assert l2[i] == l[50 + i]
- return 0
-
- self.interpret(fn, [])
-
- def test_stringbuilder(self):
- def fn():
- s = StringBuilder(4)
- s.append("abcd")
- s.append("defg")
- s.append("rty")
- s.append_multiple_char('y', 1000)
- rgc.collect()
- s.append_multiple_char('y', 1000)
- res = s.build()[1000]
- rgc.collect()
- return ord(res)
- res = self.interpret(fn, [])
- assert res == ord('y')
-
- def test_gcflag_extra(self):
- class A:
- pass
- a1 = A()
- def fn():
- a2 = A()
- if not rgc.has_gcflag_extra():
- return # cannot test it then
- assert rgc.get_gcflag_extra(a1) == False
- assert rgc.get_gcflag_extra(a2) == False
- rgc.toggle_gcflag_extra(a1)
- assert rgc.get_gcflag_extra(a1) == True
- assert rgc.get_gcflag_extra(a2) == False
- rgc.toggle_gcflag_extra(a2)
- assert rgc.get_gcflag_extra(a1) == True
- assert rgc.get_gcflag_extra(a2) == True
- rgc.toggle_gcflag_extra(a1)
- assert rgc.get_gcflag_extra(a1) == False
- assert rgc.get_gcflag_extra(a2) == True
- rgc.toggle_gcflag_extra(a2)
- assert rgc.get_gcflag_extra(a1) == False
- assert rgc.get_gcflag_extra(a2) == False
- self.interpret(fn, [])
-
-from rpython.rlib.objectmodel import UnboxedValue
-
-class TaggedBase(object):
- __slots__ = ()
- def meth(self, x):
- raise NotImplementedError
-
-class BoxedObject(TaggedBase):
- attrvalue = 66
- def __init__(self, normalint):
- self.normalint = normalint
- def meth(self, x):
- return self.normalint + x + 2
-
-class UnboxedObject(TaggedBase, UnboxedValue):
- __slots__ = 'smallint'
- def meth(self, x):
- return self.smallint + x + 3
-
-
-class TestSemiSpaceGC(GCTest, snippet.SemiSpaceGCTests):
- from rpython.memory.gc.semispace import SemiSpaceGC as GCClass
- GC_CAN_MOVE = True
- GC_CAN_MALLOC_NONMOVABLE = False
- GC_CAN_SHRINK_ARRAY = True
- GC_CAN_SHRINK_BIG_ARRAY = True
-
-class TestGrowingSemiSpaceGC(TestSemiSpaceGC):
- GC_PARAMS = {'space_size': 16*WORD}
-
-class TestGenerationalGC(TestSemiSpaceGC):
- from rpython.memory.gc.generation import GenerationGC as GCClass
-
-class TestHybridGC(TestGenerationalGC):
- from rpython.memory.gc.hybrid import HybridGC as GCClass
- GC_CAN_MALLOC_NONMOVABLE = True
- GC_CAN_SHRINK_BIG_ARRAY = False
-
- def test_ref_from_rawmalloced_to_regular(self):
- import gc
- def concat(j):
- lst = []
- for i in range(j):
- lst.append(str(i))
- gc.collect()
- return len("".join(lst))
- res = self.interpret(concat, [100])
- assert res == concat(100)
-
- def test_longliving_weakref(self):
- # test for the case where a weakref points to a very old object
- # that was made non-movable after several collections
- import gc, weakref
- class A:
- pass
- def step1(x):
- a = A()
- a.x = 42
- ref = weakref.ref(a)
- i = 0
- while i < x:
- gc.collect()
- i += 1
- assert ref() is a
- assert ref().x == 42
- return ref
- def step2(ref):
- gc.collect() # 'a' is freed here
- assert ref() is None
- def f(x):
- ref = step1(x)
- step2(ref)
- self.interpret(f, [10])
-
- def test_longliving_object_with_finalizer(self):
- class B(object):
- pass
- b = B()
- b.nextid = 0
- b.num_deleted = 0
- class A(object):
- def __init__(self):
- self.id = b.nextid
- b.nextid += 1
- def __del__(self):
- b.num_deleted += 1
- def f(x):
- a = A()
- i = 0
- while i < x:
- i += 1
- a = A()
- llop.gc__collect(lltype.Void)
- llop.gc__collect(lltype.Void)
- llop.gc__collect(lltype.Void)
- return b.num_deleted
- res = self.interpret(f, [15])
- assert res == 16
-
- def test_malloc_nonmovable_fixsize(self):
- py.test.skip("Not supported")
-
-class TestHybridGCSmallHeap(GCTest):
- from rpython.memory.gc.hybrid import HybridGC as GCClass
- GC_CAN_MOVE = False # with this size of heap, stuff gets allocated
- # in 3rd gen.
- GC_CAN_MALLOC_NONMOVABLE = True
- GC_PARAMS = {'space_size': 48*WORD,
- 'min_nursery_size': 12*WORD,
- 'nursery_size': 12*WORD,
- 'large_object': 3*WORD,
- 'large_object_gcptrs': 3*WORD,
- 'generation3_collect_threshold': 5,
- }
-
- def test_gen3_to_gen2_refs(self):
- class A(object):
- def __init__(self):
- self.x1 = -1
- def f(x):
- loop = A()
- loop.next = loop
- loop.prev = loop
- i = 0
- while i < x:
- i += 1
- a1 = A()
- a1.x1 = i
- a2 = A()
- a2.x1 = i + 1000
- a1.prev = loop.prev
- a1.prev.next = a1
- a1.next = loop
- loop.prev = a1
- a2.prev = loop
- a2.next = loop.next
- a2.next.prev = a2
- loop.next = a2
- i = 0
- a = loop
- while True:
- a = a.next
- i += 1
- if a is loop:
- return i
- res = self.interpret(f, [200])
- assert res == 401
-
- def test_malloc_nonmovable_fixsize(self):
- py.test.skip("Not supported")
-
-
-class TestMiniMarkGC(TestSemiSpaceGC):
- from rpython.memory.gc.minimark import MiniMarkGC as GCClass
- GC_CAN_SHRINK_BIG_ARRAY = False
- GC_CAN_MALLOC_NONMOVABLE = True
- BUT_HOW_BIG_IS_A_BIG_STRING = 11*WORD
-
-class TestMiniMarkGCCardMarking(TestMiniMarkGC):
- GC_PARAMS = {'card_page_indices': 4}
diff --git a/rpython/memory/test/test_generational_gc.py b/rpython/memory/test/test_generational_gc.py
new file mode 100644
--- /dev/null
+++ b/rpython/memory/test/test_generational_gc.py
@@ -0,0 +1,4 @@
+from rpython.memory.test.test_semispace_gc import TestSemiSpaceGC
+
+class TestGenerationalGC(TestSemiSpaceGC):
+ from rpython.memory.gc.generation import GenerationGC as GCClass
diff --git a/rpython/memory/test/test_growingsemispace_gc.py b/rpython/memory/test/test_growingsemispace_gc.py
new file mode 100644
--- /dev/null
+++ b/rpython/memory/test/test_growingsemispace_gc.py
@@ -0,0 +1,8 @@
+from rpython.rlib.rarithmetic import LONG_BIT
+
+from rpython.memory.test.test_semispace_gc import TestSemiSpaceGC
+
+WORD = LONG_BIT // 8
+
+class TestGrowingSemiSpaceGC(TestSemiSpaceGC):
+ GC_PARAMS = {'space_size': 16*WORD}
diff --git a/rpython/memory/test/test_hybrid_gc.py b/rpython/memory/test/test_hybrid_gc.py
new file mode 100644
--- /dev/null
+++ b/rpython/memory/test/test_hybrid_gc.py
@@ -0,0 +1,76 @@
+import py
+
+from rpython.rtyper.lltypesystem import lltype
+from rpython.rtyper.lltypesystem.lloperation import llop
+
+from rpython.memory.test.test_generational_gc import TestGenerationalGC
+
+
+class TestHybridGC(TestGenerationalGC):
+ from rpython.memory.gc.hybrid import HybridGC as GCClass
+ GC_CAN_MALLOC_NONMOVABLE = True
+ GC_CAN_SHRINK_BIG_ARRAY = False
+
+ def test_ref_from_rawmalloced_to_regular(self):
+ import gc
+ def concat(j):
+ lst = []
+ for i in range(j):
+ lst.append(str(i))
+ gc.collect()
+ return len("".join(lst))
+ res = self.interpret(concat, [100])
+ assert res == concat(100)
+
+ def test_longliving_weakref(self):
+ # test for the case where a weakref points to a very old object
+ # that was made non-movable after several collections
+ import gc, weakref
+ class A:
+ pass
+ def step1(x):
+ a = A()
+ a.x = 42
+ ref = weakref.ref(a)
+ i = 0
+ while i < x:
+ gc.collect()
+ i += 1
+ assert ref() is a
+ assert ref().x == 42
+ return ref
+ def step2(ref):
+ gc.collect() # 'a' is freed here
+ assert ref() is None
+ def f(x):
+ ref = step1(x)
+ step2(ref)
+ self.interpret(f, [10])
+
+ def test_longliving_object_with_finalizer(self):
+ class B(object):
+ pass
+ b = B()
+ b.nextid = 0
+ b.num_deleted = 0
+ class A(object):
+ def __init__(self):
+ self.id = b.nextid
+ b.nextid += 1
+ def __del__(self):
+ b.num_deleted += 1
+ def f(x):
+ a = A()
+ i = 0
+ while i < x:
+ i += 1
+ a = A()
+ llop.gc__collect(lltype.Void)
+ llop.gc__collect(lltype.Void)
+ llop.gc__collect(lltype.Void)
+ return b.num_deleted
+ res = self.interpret(f, [15])
+ assert res == 16
+
+ def test_malloc_nonmovable_fixsize(self):
+ py.test.skip("Not supported")
diff --git a/rpython/memory/test/test_hybrid_gc_smallheap.py b/rpython/memory/test/test_hybrid_gc_smallheap.py
new file mode 100644
--- /dev/null
+++ b/rpython/memory/test/test_hybrid_gc_smallheap.py
@@ -0,0 +1,56 @@
+import py
+
+from rpython.rlib.rarithmetic import LONG_BIT
+
+from rpython.memory.test.gc_test_base import GCTest
+
+WORD = LONG_BIT // 8
+
+class TestHybridGCSmallHeap(GCTest):
+ from rpython.memory.gc.hybrid import HybridGC as GCClass
+ GC_CAN_MOVE = False # with this size of heap, stuff gets allocated
+ # in 3rd gen.
+ GC_CAN_MALLOC_NONMOVABLE = True
+ GC_PARAMS = {'space_size': 48*WORD,
+ 'min_nursery_size': 12*WORD,
+ 'nursery_size': 12*WORD,
+ 'large_object': 3*WORD,
+ 'large_object_gcptrs': 3*WORD,
+ 'generation3_collect_threshold': 5,
+ }
+
+ def test_gen3_to_gen2_refs(self):
+ class A(object):
+ def __init__(self):
+ self.x1 = -1
+ def f(x):
+ loop = A()
+ loop.next = loop
+ loop.prev = loop
+ i = 0
+ while i < x:
+ i += 1
+ a1 = A()
+ a1.x1 = i
+ a2 = A()
+ a2.x1 = i + 1000
+ a1.prev = loop.prev
+ a1.prev.next = a1
+ a1.next = loop
+ loop.prev = a1
+ a2.prev = loop
+ a2.next = loop.next
+ a2.next.prev = a2
+ loop.next = a2
+ i = 0
+ a = loop
+ while True:
+ a = a.next
+ i += 1
+ if a is loop:
+ return i
+ res = self.interpret(f, [200])
+ assert res == 401
+
+ def test_malloc_nonmovable_fixsize(self):
+ py.test.skip("Not supported")
diff --git a/rpython/memory/test/test_minimark_gc.py b/rpython/memory/test/test_minimark_gc.py
new file mode 100644
--- /dev/null
+++ b/rpython/memory/test/test_minimark_gc.py
@@ -0,0 +1,11 @@
+from rpython.rlib.rarithmetic import LONG_BIT
+
+from rpython.memory.test.test_semispace_gc import TestSemiSpaceGC
+
+WORD = LONG_BIT // 8
+
+class TestMiniMarkGC(TestSemiSpaceGC):
+ from rpython.memory.gc.minimark import MiniMarkGC as GCClass
+ GC_CAN_SHRINK_BIG_ARRAY = False
+ GC_CAN_MALLOC_NONMOVABLE = True
+ BUT_HOW_BIG_IS_A_BIG_STRING = 11*WORD
diff --git a/rpython/memory/test/test_minimark_gc_cardmarking.py b/rpython/memory/test/test_minimark_gc_cardmarking.py
new file mode 100644
--- /dev/null
+++ b/rpython/memory/test/test_minimark_gc_cardmarking.py
@@ -0,0 +1,4 @@
+from rpython.memory.test.test_minimark_gc import TestMiniMarkGC
+
+class TestMiniMarkGCCardMarking(TestMiniMarkGC):
+ GC_PARAMS = {'card_page_indices': 4}
diff --git a/rpython/memory/test/test_semispace_gc.py b/rpython/memory/test/test_semispace_gc.py
new file mode 100644
--- /dev/null
+++ b/rpython/memory/test/test_semispace_gc.py
@@ -0,0 +1,9 @@
+from rpython.memory.test import snippet
+from rpython.memory.test.gc_test_base import GCTest
+
+class TestSemiSpaceGC(GCTest, snippet.SemiSpaceGCTests):
+ from rpython.memory.gc.semispace import SemiSpaceGC as GCClass
+ GC_CAN_MOVE = True
+ GC_CAN_MALLOC_NONMOVABLE = False
+ GC_CAN_SHRINK_ARRAY = True
+ GC_CAN_SHRINK_BIG_ARRAY = True
diff --git a/rpython/rlib/_rsocket_rffi.py b/rpython/rlib/_rsocket_rffi.py
--- a/rpython/rlib/_rsocket_rffi.py
+++ b/rpython/rlib/_rsocket_rffi.py
@@ -81,11 +81,14 @@
'#define RCVALL_ON 1',
'#define RCVALL_SOCKETLEVELONLY 2',
'''\
+ #ifndef __MINGW32__
struct tcp_keepalive {
u_long onoff;
u_long keepalivetime;
u_long keepaliveinterval;
- };'''
+ };
+ #endif
+ '''
])
HEADER = '\n'.join(header_lines)
COND_HEADER = ''
diff --git a/rpython/rlib/clibffi.py b/rpython/rlib/clibffi.py
--- a/rpython/rlib/clibffi.py
+++ b/rpython/rlib/clibffi.py
@@ -115,10 +115,10 @@
)
eci = rffi_platform.configure_external_library(
- 'libffi-5', eci,
+ 'ffi-5', eci,
[dict(prefix='libffi-',
include_dir='include', library_dir='.libs'),
- dict(prefix=r'c:\mingw64', include_dir='include', library_dir='lib'),
+ dict(prefix=r'c:\\mingw64', include_dir='include', library_dir='lib'),
])
else:
USE_C_LIBFFI_MSVC = True
diff --git a/rpython/translator/c/src/commondefs.h b/rpython/translator/c/src/commondefs.h
--- a/rpython/translator/c/src/commondefs.h
+++ b/rpython/translator/c/src/commondefs.h
@@ -28,6 +28,9 @@
More information about the pypy-commit
mailing list