コード例 #1
0
ファイル: test_framework.py プロジェクト: sczfaker/pypy
def test_find_clean_setarrayitems_2():
    S = lltype.GcStruct('S')
    A = lltype.GcArray(lltype.Ptr(S))

    def f():
        l = lltype.malloc(A, 3)
        l[0] = lltype.malloc(S)
        l[1] = lltype.malloc(S)
        l[2] = lltype.malloc(S)
        x = l[1]
        l[2] = lltype.malloc(S) # <- this can possibly collect
        l[0] = x
        return len(l)

    t = rtype(f, [])
    etrafo = ExceptionTransformer(t)
    graph = etrafo.transform_completely()
    collect_analyzer = CollectAnalyzer(t)
    clean_setarrayitems = find_clean_setarrayitems(collect_analyzer,
                                                   t.graphs[0])
    assert len(clean_setarrayitems) == 0
コード例 #2
0
def test_along_link():
    S1 = lltype.GcStruct('S1', ('x', lltype.Signed), hints={'immutable': True})
    s1 = lltype.malloc(S1)
    s1.x = 123
    s2 = lltype.malloc(S1)
    s2.x = 60
    def fn(x):
        if x:
            x = s1.x
        else:
            x = s2.x
        return x+1

    graph, t = get_graph(fn, [int])
    assert summary(graph) == {'int_is_true': 1,
                              'getfield': 2,
                              'int_add': 1}
    constant_fold_graph(graph)
    assert summary(graph) == {'int_is_true': 1}
    check_graph(graph, [-1], 124, t)
    check_graph(graph, [0], 61, t)
コード例 #3
0
ファイル: test_constfold.py プロジェクト: sbw111/lab4
def test_keepalive_const_fieldptr():
    S1 = lltype.GcStruct('S1', ('x', lltype.Signed))
    s1 = lltype.malloc(S1)
    s1.x = 1234

    def fn():
        p1 = lltype.direct_fieldptr(s1, 'x')
        return p1[0]

    graph, t = get_graph(fn, [])
    assert summary(graph) == {'direct_fieldptr': 1, 'getarrayitem': 1}
    constant_fold_graph(graph)

    # kill all references to 's1'
    s1 = fn = None
    del graph.func
    import gc
    gc.collect()

    assert summary(graph) == {'getarrayitem': 1}
    check_graph(graph, [], 1234, t)
コード例 #4
0
def get_shadowstackref(root_walker, gctransformer):
    if hasattr(gctransformer, '_SHADOWSTACKREF'):
        return gctransformer._SHADOWSTACKREF

    SHADOWSTACKREFPTR = lltype.Ptr(lltype.GcForwardReference())
    SHADOWSTACKREF = lltype.GcStruct('ShadowStackRef',
                                     ('base', llmemory.Address),
                                     ('top', llmemory.Address),
                                     rtti=True)
    SHADOWSTACKREFPTR.TO.become(SHADOWSTACKREF)

    def customtrace(gc, obj, callback, arg1, arg2):
        obj = llmemory.cast_adr_to_ptr(obj, SHADOWSTACKREFPTR)
        walk_stack_root(gc._trace_callback,
                        callback,
                        arg1,
                        arg2,
                        obj.base,
                        obj.top,
                        is_minor=False)  # xxx optimize?

    gc = gctransformer.gcdata.gc
    assert not hasattr(gc, 'custom_trace_dispatcher')
    # ^^^ create_custom_trace_funcs() must not run before this
    gctransformer.translator.rtyper.custom_trace_funcs.append(
        (SHADOWSTACKREF, customtrace))

    def shadowstack_destructor(shadowstackref):
        base = shadowstackref.base
        shadowstackref.base = llmemory.NULL
        shadowstackref.top = llmemory.NULL
        llmemory.raw_free(base)

    destrptr = gctransformer.annotate_helper(shadowstack_destructor,
                                             [SHADOWSTACKREFPTR], lltype.Void)

    lltype.attachRuntimeTypeInfo(SHADOWSTACKREF, destrptr=destrptr)

    gctransformer._SHADOWSTACKREF = SHADOWSTACKREF
    return SHADOWSTACKREF
コード例 #5
0
ファイル: test_inline.py プロジェクト: sota/pypy-old
    def test_keepalive_hard_case(self):
        from rpython.rtyper.lltypesystem import lltype
        Y = lltype.Struct('y', ('n', lltype.Signed))
        X = lltype.GcStruct('x', ('y', Y))

        def g(x):
            if x:
                return 3
            else:
                return 4

        def f():
            x = lltype.malloc(X)
            x.y.n = 2
            y = x.y
            z1 = g(y.n)
            z = y.n
            return z + z1

        eval_func = self.check_inline(g, f, [])
        res = eval_func([])
        assert res == 5
コード例 #6
0
ファイル: test_llmemory.py プロジェクト: sota/pypy-old
def test_llinterp_raw_malloc_struct():
    T = lltype.GcStruct('T', ('z', lltype.Signed))
    S = lltype.Struct('S', ('x', lltype.Signed), ('y', lltype.Ptr(T)))

    size = sizeof(S)

    def test_read_uninit():
        adr = raw_malloc(size)
        s = cast_adr_to_ptr(adr, lltype.Ptr(S))
        return s.x

    py.test.raises(lltype.UninitializedMemoryAccess,
                   "interpret(test_read_uninit, [])")

    def test_read_init():
        adr = raw_malloc(size)
        raw_memclear(adr, size)
        s = cast_adr_to_ptr(adr, lltype.Ptr(S))
        return s.x

    res = interpret(test_read_init, [])
    assert res == 0
コード例 #7
0
ファイル: test_transformed_gc.py プロジェクト: zielmicha/pypy
    def define_no_clean_setarrayitems(cls):
        # The optimization find_clean_setarrayitems() in
        # gctransformer/framework.py does not work with card marking.
        # Check that it is turned off.
        S = lltype.GcStruct('S', ('x', lltype.Signed))
        A = lltype.GcArray(lltype.Ptr(S))

        def sub(lst):
            lst[15] = lltype.malloc(S)  # 'lst' is set the single mark "12-15"
            lst[15].x = 123
            lst[0] = lst[15]  # that would be a "clean_setarrayitem"

        def f():
            lst = lltype.malloc(A, 16)  # 16 > 10
            rgc.collect()
            sub(lst)
            null = lltype.nullptr(S)
            lst[15] = null  # clear, so that A() is only visible via lst[0]
            rgc.collect()  # -> crash
            return lst[0].x

        return f
コード例 #8
0
    def test_needs_keepalive(self):
        check_debug_build()
        from rpython.rtyper.lltypesystem import lltype
        X = lltype.GcStruct("X", ('y', lltype.Struct("Y",
                                                     ('z', lltype.Signed))))

        def can_raise(n):
            if n:
                raise Exception
            else:
                return 1

        def foo(n):
            x = lltype.malloc(X)
            y = x.y
            y.z = 42
            r = can_raise(n)
            return r + y.z

        f = self.compile(foo, [int])
        res = f(0)
        assert res == 43
コード例 #9
0
    def test_adt_method(self):
        def ll_callme(n):
            return n
        ll_callme = lltype.staticAdtMethod(ll_callme)
        S = lltype.GcStruct('S', ('x', lltype.Signed),
                            adtmeths = {'yep': True,
                                        'callme': ll_callme})
        def g(p, x, y, z):
            p.x = x
            if p.yep:
                z *= p.callme(y)
            return z
        def f(x, y, z):
            p = lltype.malloc(S)
            return g(p, x, y, z)

        t, wa = self.translate(f, [int, int, int])
        fgraph = graphof(t, f)
        assert fgraph.startblock.operations[-1].opname == 'direct_call'

        result = wa.analyze(fgraph.startblock.operations[-1])
        assert list(result) == [("struct", lltype.Ptr(S), "x")]
コード例 #10
0
ファイル: test_transformed_gc.py プロジェクト: zielmicha/pypy
    def define_gc_heap_stats(cls):
        S = lltype.GcStruct('S', ('x', lltype.Signed))
        l1 = []
        l2 = []
        l3 = []
        l4 = []

        def f():
            for i in range(10):
                s = lltype.malloc(S)
                l1.append(s)
                l2.append(s)
                if i < 3:
                    l3.append(s)
                    l4.append(s)
            # We cheat here and only read the table which we later on
            # process ourselves, otherwise this test takes ages
            llop.gc__collect(lltype.Void)
            tb = rgc._heap_stats()
            a = 0
            nr = 0
            b = 0
            c = 0
            d = 0
            e = 0
            for i in range(len(tb)):
                if tb[i].count == 10:
                    a += 1
                    nr = i
                if tb[i].count > 50:
                    d += 1
            for i in range(len(tb)):
                if tb[i].count == 4:
                    b += 1
                    c += tb[i].links[nr]
                    e += tb[i].size
            return d * 1000 + c * 100 + b * 10 + a

        return f
コード例 #11
0
ファイル: test_transformed_gc.py プロジェクト: zielmicha/pypy
    def define_do_malloc_operations_in_call(cls):
        P = lltype.GcStruct('P', ('x', lltype.Signed))

        def g():
            llop.do_malloc_fixedsize(llmemory.GCREF)  # placeholder

        def f():
            q = lltype.malloc(P)
            q.x = 1
            i = 0
            while i < 40:
                g()
                i += q.x
            return 0

        def fix_graph_of_g(translator):
            from rpython.translator.translator import graphof
            from rpython.flowspace.model import Constant
            from rpython.rtyper.lltypesystem import rffi
            layoutbuilder = cls.ensure_layoutbuilder(translator)
            type_id = layoutbuilder.get_type_id(P)
            #
            # now fix the do_malloc_fixedsize in the graph of g
            graph = graphof(translator, g)
            for op in graph.startblock.operations:
                if op.opname == 'do_malloc_fixedsize':
                    op.args = [
                        Constant(type_id, llgroup.HALFWORD),
                        Constant(llmemory.sizeof(P), lltype.Signed),
                        Constant(False, lltype.Bool),  # has_finalizer
                        Constant(False, lltype.Bool),  # is_finalizer_light
                        Constant(False, lltype.Bool)
                    ]  # contains_weakptr
                    break
            else:
                assert 0, "oups, not found"

        return f, None, fix_graph_of_g
コード例 #12
0
ファイル: test_virtualstate.py プロジェクト: sota/pypy-old
    def test_NotVirtualStateInfo_generalization(self):
        def isgeneral(value1, value2):
            info1 = NotVirtualStateInfo(value1)
            info1.position = 0
            info2 = NotVirtualStateInfo(value2)
            info2.position = 0
            return info1.generalization_of(info2, {}, {})

        assert isgeneral(OptValue(BoxInt()), OptValue(ConstInt(7)))
        assert not isgeneral(OptValue(ConstInt(7)), OptValue(BoxInt()))

        ptr = OptValue(BoxPtr())
        nonnull = OptValue(BoxPtr())
        nonnull.make_nonnull(0)
        knownclass = OptValue(BoxPtr())
        knownclass.make_constant_class(ConstPtr(self.someptr1), 0)
        const = OptValue(BoxPtr)
        const.make_constant_class(ConstPtr(self.someptr1), 0)
        const.make_constant(ConstPtr(self.someptr1))
        inorder = [ptr, nonnull, knownclass, const]
        for i in range(len(inorder)):
            for j in range(i, len(inorder)):
                assert isgeneral(inorder[i], inorder[j])
                if i != j:
                    assert not isgeneral(inorder[j], inorder[i])

        value1 = OptValue(BoxInt())
        value2 = OptValue(BoxInt())
        value2.intbound.make_lt(IntBound(10, 10))
        assert isgeneral(value1, value2)
        assert not isgeneral(value2, value1)

        assert isgeneral(OptValue(ConstInt(7)), OptValue(ConstInt(7)))
        S = lltype.GcStruct('S')
        foo = lltype.malloc(S)
        fooref = lltype.cast_opaque_ptr(llmemory.GCREF, foo)
        assert isgeneral(OptValue(ConstPtr(fooref)),
                         OptValue(ConstPtr(fooref)))
コード例 #13
0
ファイル: test_constfold.py プロジェクト: sbw111/lab4
def test_fold_exitswitch():
    S1 = lltype.GcStruct('S1', ('x', lltype.Signed), hints={'immutable': True})
    s1 = lltype.malloc(S1)
    s1.x = 123
    s2 = lltype.malloc(S1)
    s2.x = 60

    def fn(n):
        if s1.x:
            return n * 5
        else:
            return n - 7

    graph, t = get_graph(fn, [int])
    assert summary(graph) == {
        'getfield': 1,
        'int_is_true': 1,
        'int_mul': 1,
        'int_sub': 1
    }
    constant_fold_graph(graph)
    assert summary(graph) == {'int_mul': 1}
    check_graph(graph, [12], 60, t)
コード例 #14
0
ファイル: test_transformed_gc.py プロジェクト: zielmicha/pypy
    def define_nongc_static_root_minor_collect(cls):
        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
            x = 20
            all = [None] * x
            i = 0
            while i < x:  # enough to cause a minor collect
                all[i] = [i] * i
                i += 1
            i = static.p.x
            llop.gc__collect(lltype.Void)
            return static.p.x + i

        def cleanup():
            static.p = lltype.nullptr(T1)

        return f, cleanup, None
コード例 #15
0
ファイル: test_standalone.py プロジェクト: juokaz/pypy
    def test_llhelper_stored_in_struct(self):
        from rpython.rtyper.annlowlevel import llhelper

        def f(x):
            return x + 3

        FUNC_TP = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed))

        S = lltype.GcStruct('s', ('f', FUNC_TP))

        class Glob(object):
            pass

        glob = Glob()

        def entry_point(argv):
            x = llhelper(FUNC_TP, f)
            s = lltype.malloc(S)
            s.f = x
            glob.s = s  # escape
            return 0

        self.compile(entry_point)
コード例 #16
0
        def __init__(self, rtyper):
            super(RuleRepr, self).__init__()

            self.ll_rule_cache = {}

            self.match_init_repr = rtyper.getrepr(
                rtyper.annotator.bookkeeper.immutablevalue(Match.__init__))
            self.match_context_init_repr = rtyper.getrepr(
                rtyper.annotator.bookkeeper.immutablevalue(
                    rsre_core.StrMatchContext.__init__))
            self.match_context_repr = rtyper.getrepr(
                rtyper.annotator.bookkeeper.immutablevalue(
                    rsre_core.match_context))

            list_repr = FixedSizeListRepr(
                rtyper, rtyper.getrepr(model.SomeInteger(nonneg=True)))
            list_repr._setup_repr()
            self.lowleveltype = lltype.Ptr(
                lltype.GcStruct(
                    "RULE",
                    ("name", lltype.Ptr(STR)),
                    ("code", list_repr.lowleveltype),
                ))
コード例 #17
0
ファイル: test_runner.py プロジェクト: fhalde/pypy
 def test_nullity_with_guard(self):
     allops = [rop.INT_IS_TRUE]
     guards = [rop.GUARD_TRUE, rop.GUARD_FALSE]
     p = lltype.cast_opaque_ptr(llmemory.GCREF,
                                lltype.malloc(lltype.GcStruct('x')))
     nullptr = lltype.nullptr(llmemory.GCREF.TO)
     f = InputArgInt()
     for op in allops:
         for guard in guards:
             if op == rop.INT_IS_TRUE:
                 bp = InputArgInt(1)
                 n = InputArgInt(0)
             else:
                 bp = InputArgRef(p)
                 n = InputArgRef(nullptr)
             for b in (bp, n):
                 i1 = ResOperation(rop.SAME_AS_I, [ConstInt(1)])
                 f = ResOperation(op, [b])
                 ops = [
                     i1,
                     f,
                     ResOperation(guard, [f],
                                  descr=BasicFailDescr()),
                     ResOperation(rop.FINISH, [ConstInt(0)],
                                  descr=BasicFinalDescr()),
                     ]
                 ops[-2].setfailargs([i1])
                 looptoken = JitCellToken()
                 self.cpu.compile_loop([b], ops, looptoken)
                 deadframe = self.cpu.execute_token(looptoken, b.getint())
                 result = self.cpu.get_int_value(deadframe, 0)
                 if guard == rop.GUARD_FALSE:
                     assert result == execute(self.cpu, None,
                                              op, None, b)
                 else:
                     assert result != execute(self.cpu, None,
                                              op, None, b)
コード例 #18
0
def test_memoryerror():
    # in rev 30717 this test causes a segfault on some Linux, but usually
    # only after the test is run.  It is caused by the following sequence
    # of events in lltype.malloc(S, n): there is an OP_MAX_VARSIZE macro
    # which figures out that the size asked for is too large and would
    # cause a wrap-around, so it sets a MemoryError; but execution continues
    # nevertheless and the next line is an OP_MALLOC instruction, which
    # because of the wrap-around allocates for 's' an amount of bytes which
    # falls precisely between 0 and offsetof(s, tail).  It succeeds.  Then
    # the length field of s.tail is initialized - this overwrites random
    # memory!  And only then is the exception check performed, and the
    # MemoryError is noticed.
    A = lltype.Array(lltype.Signed)
    S = lltype.GcStruct('S', ('a', lltype.Signed), ('b', lltype.Signed),
                        ('c', lltype.Signed), ('tail', A))

    def g(n, tag):
        s = lltype.malloc(S, n)
        tag.a = 42
        return s

    def testfn(n):
        tag = lltype.malloc(S, 0)
        try:
            s = g(n, tag)
            result = s.tail[n // 2]
        except MemoryError:
            result = 1000
        return result + tag.a

    f1 = getcompiled(testfn, [int])
    assert f1(10) == 42
    assert f1(sys.maxint) == 1000
    for i in range(20):
        assert f1(int((sys.maxint + 1) // 2 - i)) == 1000
    assert f1(sys.maxint // 2 - 16384) == 1000
    assert f1(sys.maxint // 2 + 16384) == 1000
コード例 #19
0
def test_wrap():
    def _is(box1, box2):
        return (box1.__class__ == box2.__class__ and
                box1.value == box2.value)
    p = lltype.malloc(lltype.GcStruct('S'))
    po = lltype.cast_opaque_ptr(llmemory.GCREF, p)
    assert _is(wrap(None, 42), BoxInt(42))
    assert _is(wrap(None, 42.5), boxfloat(42.5))
    assert _is(wrap(None, p), BoxPtr(po))
    assert _is(wrap(None, 42, in_const_box=True), ConstInt(42))
    assert _is(wrap(None, 42.5, in_const_box=True), constfloat(42.5))
    assert _is(wrap(None, p, in_const_box=True), ConstPtr(po))
    if longlong.supports_longlong:
        import sys
        from rpython.rlib.rarithmetic import r_longlong, r_ulonglong
        value = r_longlong(-sys.maxint*17)
        assert _is(wrap(None, value), BoxFloat(value))
        assert _is(wrap(None, value, in_const_box=True), ConstFloat(value))
        value_unsigned = r_ulonglong(-sys.maxint*17)
        assert _is(wrap(None, value_unsigned), BoxFloat(value))
    sfval = r_singlefloat(42.5)
    ival = longlong.singlefloat2int(sfval)
    assert _is(wrap(None, sfval), BoxInt(ival))
    assert _is(wrap(None, sfval, in_const_box=True), ConstInt(ival))
コード例 #20
0
ファイル: test_gc.py プロジェクト: zcxowwww/pypy
def test_boehm():
    gc_ll_descr = gc.GcLLDescr_boehm(None, None, None)
    #
    record = []
    prev_malloc_fn_ptr = gc_ll_descr.malloc_fn_ptr

    def my_malloc_fn_ptr(size):
        p = prev_malloc_fn_ptr(size)
        record.append((size, p))
        return p

    gc_ll_descr.malloc_fn_ptr = my_malloc_fn_ptr
    #
    # ---------- gc_malloc ----------
    S = lltype.GcStruct('S', ('x', lltype.Signed))
    sizedescr = descr.get_size_descr(gc_ll_descr, S)
    p = gc_ll_descr.gc_malloc(sizedescr)
    assert record == [(sizedescr.size, p)]
    del record[:]
    # ---------- gc_malloc_array ----------
    A = lltype.GcArray(lltype.Signed)
    arraydescr = descr.get_array_descr(gc_ll_descr, A)
    p = gc_ll_descr.gc_malloc_array(10, arraydescr)
    assert record == [(arraydescr.basesize + 10 * arraydescr.itemsize, p)]
    del record[:]
    # ---------- gc_malloc_str ----------
    p = gc_ll_descr.gc_malloc_str(10)
    basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR, False)
    assert record == [(basesize + 10 * itemsize, p)]
    del record[:]
    # ---------- gc_malloc_unicode ----------
    p = gc_ll_descr.gc_malloc_unicode(10)
    basesize, itemsize, ofs_length = symbolic.get_array_token(
        rstr.UNICODE, False)
    assert record == [(basesize + 10 * itemsize, p)]
    del record[:]
コード例 #21
0
ファイル: test_llmemory.py プロジェクト: sota/pypy-old
def test_raw_malloc_gcstruct():
    from rpython.memory import gcheader
    HDR = lltype.Struct('header', ('a', lltype.Signed))
    builder = gcheader.GCHeaderBuilder(HDR)
    gchdr = builder.size_gc_header
    S = lltype.GcStruct('S', ('x', lltype.Signed))

    def allocate():
        adr = raw_malloc(gchdr + sizeof(S))
        p = cast_adr_to_ptr(adr, lltype.Ptr(HDR))
        p.a = -21
        adr = cast_ptr_to_adr(p)
        sadr = adr + gchdr
        s = cast_adr_to_ptr(sadr, lltype.Ptr(S))
        s.x = 123
        assert (sadr + offsetof(S, 'x')).signed[0] == 123
        (sadr + offsetof(S, 'x')).signed[0] = 125
        assert s.x == 125
        return s

    s = allocate()
    adr = cast_ptr_to_adr(s) - gchdr
    p = cast_adr_to_ptr(adr, lltype.Ptr(HDR))
    assert p.a == -21
コード例 #22
0
ファイル: test_assembler.py プロジェクト: sota/pypy-old
def test_assemble_cast_consts():
    ssarepr = SSARepr("test")
    S = lltype.GcStruct('S')
    s = lltype.malloc(S)
    F = lltype.FuncType([], lltype.Signed)
    f = lltype.functionptr(F, 'f')
    ssarepr.insns = [
        ('int_return', Constant('X', lltype.Char)),
        ('int_return', Constant(unichr(0x1234), lltype.UniChar)),
        ('int_return', Constant(f, lltype.Ptr(F))),
        ('ref_return', Constant(s, lltype.Ptr(S))),
    ]
    assembler = Assembler()
    jitcode = assembler.assemble(ssarepr)
    assert jitcode.code == ("\x00\x58" "\x01\xFF" "\x01\xFE" "\x02\xFF")
    assert assembler.insns == {
        'int_return/c': 0,
        'int_return/i': 1,
        'ref_return/r': 2
    }
    f_int = heaptracker.adr2int(llmemory.cast_ptr_to_adr(f))
    assert jitcode.constants_i == [0x1234, f_int]
    s_gcref = lltype.cast_opaque_ptr(llmemory.GCREF, s)
    assert jitcode.constants_r == [s_gcref]
コード例 #23
0
    def test_keepalive(self):
        S = lltype.GcStruct('S')

        def g():
            return lltype.malloc(S)

        def f(x):
            p = g()
            q = g()
            keepalive_until_here(p)
            keepalive_until_here(q)
            return x

        self.encoding_test(f, [5],
                           """
            residual_call_r_r $<* fn g>, R[], <Descr> -> %r0
            -live-
            residual_call_r_r $<* fn g>, R[], <Descr> -> %r1
            -live-
            -live- %r0
            -live- %r1
            int_return %i0
        """,
                           transform=True)
        self.encoding_test(f, [5],
                           """
            residual_call_r_r $<* fn g>, R[], <Descr> -> %r0
            -live- %i0, %r0
            residual_call_r_r $<* fn g>, R[], <Descr> -> %r1
            -live- %i0, %r0, %r1
            -live- %i0, %r0, %r1
            -live- %i0, %r1
            int_return %i0
        """,
                           transform=True,
                           liveness=True)
コード例 #24
0
 def define_compile_framework_7_interior(cls):
     # Array of structs containing pointers (test the write barrier
     # for setinteriorfield_gc)
     S = lltype.GcStruct('S', ('i', lltype.Signed))
     A = lltype.GcArray(lltype.Struct('entry', ('x', lltype.Ptr(S)),
                                               ('y', lltype.Ptr(S)),
                                               ('z', lltype.Ptr(S))))
     class Glob:
         a = lltype.nullptr(A)
     glob = Glob()
     #
     def make_s(i):
         s = lltype.malloc(S)
         s.i = i
         return s
     #
     @unroll_safe
     def f(n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s):
         a = glob.a
         if not a:
             a = glob.a = lltype.malloc(A, 10)
         i = 0
         while i < 10:
             a[i].x = make_s(n + i * 100 + 1)
             a[i].y = make_s(n + i * 100 + 2)
             a[i].z = make_s(n + i * 100 + 3)
             i += 1
         i = 0
         while i < 10:
             check(a[i].x.i == n + i * 100 + 1)
             check(a[i].y.i == n + i * 100 + 2)
             check(a[i].z.i == n + i * 100 + 3)
             i += 1
         n -= x.foo
         return n, x, x0, x1, x2, x3, x4, x5, x6, x7, l, s
     return None, f, None
コード例 #25
0
class TestRegallocMoreRegisters(CustomBaseTestRegalloc):

    cpu = CustomBaseTestRegalloc.cpu
    targettoken = TargetToken()

    S = lltype.GcStruct('S', ('field', lltype.Char))
    fielddescr = cpu.fielddescrof(S, 'field')

    A = lltype.GcArray(lltype.Char)
    I = lltype.GcArray(lltype.Signed)
    arraydescr = cpu.arraydescrof(A)
    arraydescr_i = cpu.arraydescrof(I)

    namespace = locals().copy()

    def test_int_is_true(self):
        ops = '''
        [i0, i1, i2, i3, i4, i5, i6, i7]
        i10 = int_is_true(i0)
        i11 = int_is_true(i1)
        i12 = int_is_true(i2)
        i13 = int_is_true(i3)
        i14 = int_is_true(i4)
        i15 = int_is_true(i5)
        i16 = int_is_true(i6)
        i17 = int_is_true(i7)
        guard_true(i0) [i10, i11, i12, i13, i14, i15, i16, i17]
        '''
        self.interpret(ops, [0, 42, 12, 0, 13, 0, 0, 3333])
        assert self.getints(8) == [0, 1, 1, 0, 1, 0, 0, 1]

    def test_comparison_ops(self):
        ops = '''
        [i0, i1, i2, i3, i4, i5, i6]
        i10 = int_lt(i0, i1)
        i11 = int_le(i2, i3)
        i12 = int_ge(i4, i5)
        i13 = int_eq(i5, i6)
        i14 = int_gt(i6, i2)
        i15 = int_ne(i2, i6)
        guard_true(i15) [i10, i11, i12, i13, i14, i15]

        '''
        self.interpret(ops, [0, 1, 2, 3, 4, 5, 6])
        assert self.getints(6) == [1, 1, 0, 0, 1, 1]

    def test_strsetitem(self):
        ops = '''
        [p0, i]
        strsetitem(p0, 1, i)
        finish()
        '''
        llstr = rstr.mallocstr(10)
        self.interpret(ops, [llstr, ord('a')])
        assert llstr.chars[1] == 'a'

    def test_setfield_char(self):
        ops = '''
        [p0, i]
        setfield_gc(p0, i, descr=fielddescr)
        finish()
        '''
        s = lltype.malloc(self.S)
        self.interpret(ops, [s, ord('a')])
        assert s.field == 'a'

    def test_setarrayitem_gc(self):
        ops = '''
        [p0, i]
        setarrayitem_gc(p0, 1, i, descr=arraydescr)
        finish()
        '''
        s = lltype.malloc(self.A, 3)
        self.interpret(ops, [s, ord('a')])
        assert s[1] == 'a'

    def test_setarrayitem2_gc(self):
        ops = '''
        [p0, i, i1]
        setarrayitem_gc(p0, i1, i, descr=arraydescr)
        finish()
        '''
        s = lltype.malloc(self.A, 3)
        self.interpret(ops, [s, ord('a'), 1])
        assert s[1] == 'a'

    def test_setarrayitem3_gc(self):
        ops = '''
        [p0, i0, i1]
        setarrayitem_gc(p0, i1, i0, descr=arraydescr_i)
        finish()
        '''
        s = lltype.malloc(self.I, 3)
        self.interpret(ops, [s, 1234567890, 1])
        assert s[1] == 1234567890

    def test_setarrayitem4_gc(self):
        ops = '''
        [p0, i0]
        setarrayitem_gc(p0, 1, i0, descr=arraydescr_i)
        finish()
        '''
        s = lltype.malloc(self.I, 3)
        self.interpret(ops, [s, 1234567890])
        assert s[1] == 1234567890

    def test_division_optimized(self):
        ops = '''
        [i7, i6]
        label(i7, i6, descr=targettoken)
        i18 = int_floordiv(i7, i6)
        i19 = int_xor(i7, i6)
        i21 = int_lt(i19, 0)
        i22 = int_mod(i7, i6)
        i23 = int_is_true(i22)
        i24 = int_eq(i6, 4)
        guard_false(i24) [i18]
        jump(i18, i6, descr=targettoken)
        '''
        self.interpret(ops, [10, 4])
        assert self.getint(0) == 2
コード例 #26
0
import py
from rpython.rtyper.lltypesystem import lltype, llmemory
from rpython.memory.gc.incminimark import IncrementalMiniMarkGC
from rpython.memory.gc.test.test_direct import BaseDirectGCTest
from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY
from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY_LIGHT

PYOBJ_HDR = IncrementalMiniMarkGC.PYOBJ_HDR
PYOBJ_HDR_PTR = IncrementalMiniMarkGC.PYOBJ_HDR_PTR

S = lltype.GcForwardReference()
S.become(
    lltype.GcStruct('S', ('x', lltype.Signed), ('prev', lltype.Ptr(S)),
                    ('next', lltype.Ptr(S))))


class TestRawRefCount(BaseDirectGCTest):
    GCClass = IncrementalMiniMarkGC

    def _collect(self, major, expected_trigger=0):
        if major:
            self.gc.collect()
        else:
            self.gc._minor_collection()
        count1 = len(self.trigger)
        self.gc.rrc_invoke_callback()
        count2 = len(self.trigger)
        assert count2 - count1 == expected_trigger

    def _rawrefcount_pair(self,
                          intval,
コード例 #27
0
class SemiSpaceGC(MovingGCBase):
    _alloc_flavor_ = "raw"
    inline_simple_malloc = True
    inline_simple_malloc_varsize = True
    malloc_zero_filled = True
    first_unused_gcflag = first_gcflag << 6
    gcflag_extra = GCFLAG_EXTRA

    HDR = lltype.Struct('header', ('tid', lltype.Signed))  # XXX or rffi.INT?
    typeid_is_in_field = 'tid'
    FORWARDSTUB = lltype.GcStruct('forwarding_stub',
                                  ('forw', llmemory.Address))
    FORWARDSTUBPTR = lltype.Ptr(FORWARDSTUB)

    object_minimal_size = llmemory.sizeof(FORWARDSTUB)

    # the following values override the default arguments of __init__ when
    # translating to a real backend.
    TRANSLATION_PARAMS = {'space_size': 8 * 1024 * 1024}  # XXX adjust

    def __init__(self,
                 config,
                 space_size=4096,
                 max_space_size=sys.maxint // 2 + 1,
                 **kwds):
        self.param_space_size = space_size
        self.param_max_space_size = max_space_size
        MovingGCBase.__init__(self, config, **kwds)

    def setup(self):
        #self.total_collection_time = 0.0
        self.total_collection_count = 0

        self.space_size = self.param_space_size
        self.max_space_size = self.param_max_space_size
        self.red_zone = 0

        #self.program_start_time = time.time()
        self.tospace = llarena.arena_malloc(self.space_size, True)
        ll_assert(bool(self.tospace), "couldn't allocate tospace")
        self.top_of_space = self.tospace + self.space_size
        self.fromspace = llarena.arena_malloc(self.space_size, True)
        ll_assert(bool(self.fromspace), "couldn't allocate fromspace")
        self.free = self.tospace
        MovingGCBase.setup(self)
        self.objects_with_finalizers = self.AddressDeque()
        self.objects_with_light_finalizers = self.AddressStack()
        self.objects_with_weakrefs = self.AddressStack()

    def _teardown(self):
        debug_print("Teardown")
        llarena.arena_free(self.fromspace)
        llarena.arena_free(self.tospace)

    # This class only defines the malloc_{fixed,var}size_clear() methods
    # because the spaces are filled with zeroes in advance.

    def malloc_fixedsize_clear(self,
                               typeid16,
                               size,
                               has_finalizer=False,
                               is_finalizer_light=False,
                               contains_weakptr=False):
        size_gc_header = self.gcheaderbuilder.size_gc_header
        totalsize = size_gc_header + size
        result = self.free
        if raw_malloc_usage(totalsize) > self.top_of_space - result:
            result = self.obtain_free_space(totalsize)
        llarena.arena_reserve(result, totalsize)
        self.init_gc_object(result, typeid16)
        self.free = result + totalsize
        #if is_finalizer_light:
        #    self.objects_with_light_finalizers.append(result + size_gc_header)
        #else:
        if has_finalizer:
            from rpython.rtyper.lltypesystem import rffi
            self.objects_with_finalizers.append(result + size_gc_header)
            self.objects_with_finalizers.append(rffi.cast(
                llmemory.Address, -1))
        if contains_weakptr:
            self.objects_with_weakrefs.append(result + size_gc_header)
        return llmemory.cast_adr_to_ptr(result + size_gc_header,
                                        llmemory.GCREF)

    def malloc_varsize_clear(self, typeid16, length, size, itemsize,
                             offset_to_length):
        size_gc_header = self.gcheaderbuilder.size_gc_header
        nonvarsize = size_gc_header + size
        try:
            varsize = ovfcheck(itemsize * length)
            totalsize = ovfcheck(nonvarsize + varsize)
        except OverflowError:
            raise memoryError
        result = self.free
        if raw_malloc_usage(totalsize) > self.top_of_space - result:
            result = self.obtain_free_space(totalsize)
        llarena.arena_reserve(result, totalsize)
        self.init_gc_object(result, typeid16)
        (result + size_gc_header + offset_to_length).signed[0] = length
        self.free = result + llarena.round_up_for_allocation(totalsize)
        return llmemory.cast_adr_to_ptr(result + size_gc_header,
                                        llmemory.GCREF)

    def shrink_array(self, addr, smallerlength):
        size_gc_header = self.gcheaderbuilder.size_gc_header
        if self._is_in_the_space(addr - size_gc_header):
            typeid = self.get_type_id(addr)
            totalsmallersize = (
                size_gc_header + self.fixed_size(typeid) +
                self.varsize_item_sizes(typeid) * smallerlength)
            llarena.arena_shrink_obj(addr - size_gc_header, totalsmallersize)
            #
            offset_to_length = self.varsize_offset_to_length(typeid)
            (addr + offset_to_length).signed[0] = smallerlength
            return True
        else:
            return False

    def register_finalizer(self, fq_index, gcobj):
        from rpython.rtyper.lltypesystem import rffi
        obj = llmemory.cast_ptr_to_adr(gcobj)
        fq_index = rffi.cast(llmemory.Address, fq_index)
        self.objects_with_finalizers.append(obj)
        self.objects_with_finalizers.append(fq_index)

    def obtain_free_space(self, needed):
        # a bit of tweaking to maximize the performance and minimize the
        # amount of code in an inlined version of malloc_fixedsize_clear()
        if not self.try_obtain_free_space(needed):
            raise memoryError
        return self.free

    obtain_free_space._dont_inline_ = True

    def try_obtain_free_space(self, needed):
        # XXX for bonus points do big objects differently
        needed = raw_malloc_usage(needed)
        if (self.red_zone >= 2 and self.space_size < self.max_space_size
                and self.double_space_size()):
            pass  # collect was done during double_space_size()
        else:
            self.semispace_collect()
        missing = needed - (self.top_of_space - self.free)
        if missing <= 0:
            return True  # success
        else:
            # first check if the object could possibly fit
            proposed_size = self.space_size
            while missing > 0:
                if proposed_size >= self.max_space_size:
                    return False  # no way
                missing -= proposed_size
                proposed_size *= 2
            # For address space fragmentation reasons, we double the space
            # size possibly several times, moving the objects at each step,
            # instead of going directly for the final size.  We assume that
            # it's a rare case anyway.
            while self.space_size < proposed_size:
                if not self.double_space_size():
                    return False
            ll_assert(needed <= self.top_of_space - self.free,
                      "double_space_size() failed to do its job")
            return True

    def double_space_size(self):
        self.red_zone = 0
        old_fromspace = self.fromspace
        newsize = self.space_size * 2
        newspace = llarena.arena_malloc(newsize, True)
        if not newspace:
            return False  # out of memory
        llarena.arena_free(old_fromspace)
        self.fromspace = newspace
        # now self.tospace contains the existing objects and
        # self.fromspace is the freshly allocated bigger space

        self.semispace_collect(size_changing=True)
        self.top_of_space = self.tospace + newsize
        # now self.tospace is the freshly allocated bigger space,
        # and self.fromspace is the old smaller space, now empty
        llarena.arena_free(self.fromspace)

        newspace = llarena.arena_malloc(newsize, True)
        if not newspace:
            # Complex failure case: we have in self.tospace a big chunk
            # of memory, and the two smaller original spaces are already gone.
            # Unsure if it's worth these efforts, but we can artificially
            # split self.tospace in two again...
            self.max_space_size = self.space_size  # don't try to grow again,
            #              because doing arena_free(self.fromspace) would crash
            self.fromspace = self.tospace + self.space_size
            self.top_of_space = self.fromspace
            ll_assert(self.free <= self.top_of_space,
                      "unexpected growth of GC space usage during collect")
            return False  # out of memory

        self.fromspace = newspace
        self.space_size = newsize
        return True  # success

    def set_max_heap_size(self, size):
        # Set the maximum semispace size.
        # The size is rounded down to the next power of two.  Also, this is
        # the size of one semispace only, so actual usage can be the double
        # during a collection.  Finally, note that this will never shrink
        # an already-allocated heap.
        if size < 1:
            size = 1  # actually, the minimum is 8MB in default translations
        self.max_space_size = sys.maxint // 2 + 1
        while self.max_space_size > size:
            self.max_space_size >>= 1

    @classmethod
    def JIT_minimal_size_in_nursery(cls):
        return cls.object_minimal_size

    def collect(self, gen=0):
        self.debug_check_consistency()
        self.semispace_collect()
        # the indirection is required by the fact that collect() is referred
        # to by the gc transformer, and the default argument would crash
        # (this is also a hook for the HybridGC)

    def semispace_collect(self, size_changing=False):
        debug_start("gc-collect")
        debug_print()
        debug_print(".----------- Full collection ------------------")
        start_usage = self.free - self.tospace
        debug_print("| used before collection:          ", start_usage,
                    "bytes")
        #start_time = time.time()
        #llop.debug_print(lltype.Void, 'semispace_collect', int(size_changing))

        # Switch the spaces.  We copy everything over to the empty space
        # (self.fromspace at the beginning of the collection), and clear the old
        # one (self.tospace at the beginning).  Their purposes will be reversed
        # for the next collection.
        tospace = self.fromspace
        fromspace = self.tospace
        self.fromspace = fromspace
        self.tospace = tospace
        self.top_of_space = tospace + self.space_size
        scan = self.free = tospace
        self.starting_full_collect()
        self.collect_roots()
        self.copy_pending_finalizers(self.copy)
        scan = self.scan_copied(scan)
        if self.objects_with_light_finalizers.non_empty():
            self.deal_with_objects_with_light_finalizers()
        if self.objects_with_finalizers.non_empty():
            scan = self.deal_with_objects_with_finalizers(scan)
        if self.objects_with_weakrefs.non_empty():
            self.invalidate_weakrefs()
        self.update_objects_with_id()
        self.finished_full_collect()
        self.debug_check_consistency()
        if not size_changing:
            llarena.arena_reset(fromspace, self.space_size, True)
            self.record_red_zone()
            self.execute_finalizers()
        #llop.debug_print(lltype.Void, 'collected', self.space_size, size_changing, self.top_of_space - self.free)
        if have_debug_prints():
            #end_time = time.time()
            #elapsed_time = end_time - start_time
            #self.total_collection_time += elapsed_time
            self.total_collection_count += 1
            #total_program_time = end_time - self.program_start_time
            end_usage = self.free - self.tospace
            debug_print("| used after collection:           ", end_usage,
                        "bytes")
            debug_print("| freed:                           ",
                        start_usage - end_usage, "bytes")
            debug_print("| size of each semispace:          ", self.space_size,
                        "bytes")
            debug_print("| fraction of semispace now used:  ",
                        end_usage * 100.0 / self.space_size, "%")
            #ct = self.total_collection_time
            cc = self.total_collection_count
            debug_print("| number of semispace_collects:    ", cc)
            #debug_print("|                         i.e.:    ",
            #            cc / total_program_time, "per second")
            #debug_print("| total time in semispace_collect: ",
            #            ct, "seconds")
            #debug_print("|                            i.e.: ",
            #            ct * 100.0 / total_program_time, "%")
            debug_print("`----------------------------------------------")
        debug_stop("gc-collect")

    def starting_full_collect(self):
        pass  # hook for the HybridGC

    def finished_full_collect(self):
        pass  # hook for the HybridGC

    def record_red_zone(self):
        # red zone: if the space is more than 80% full, the next collection
        # should double its size.  If it is more than 66% full twice in a row,
        # then it should double its size too.  (XXX adjust)
        # The goal is to avoid many repeated collection that don't free a lot
        # of memory each, if the size of the live object set is just below the
        # size of the space.
        free_after_collection = self.top_of_space - self.free
        if free_after_collection > self.space_size // 3:
            self.red_zone = 0
        else:
            self.red_zone += 1
            if free_after_collection < self.space_size // 5:
                self.red_zone += 1

    def get_size_incl_hash(self, obj):
        size = self.get_size(obj)
        hdr = self.header(obj)
        if (hdr.tid & GCFLAG_HASHMASK) == GC_HASH_HASFIELD:
            size += llmemory.sizeof(lltype.Signed)
        return size

    def scan_copied(self, scan):
        while scan < self.free:
            curr = scan + self.size_gc_header()
            self.trace_and_copy(curr)
            scan += self.size_gc_header() + self.get_size_incl_hash(curr)
        return scan

    def collect_roots(self):
        self.root_walker.walk_roots(
            SemiSpaceGC._collect_root,  # stack roots
            SemiSpaceGC._collect_root,  # static in prebuilt non-gc structures
            SemiSpaceGC._collect_root)  # static in prebuilt gc objects

    def _collect_root(self, root):
        root.address[0] = self.copy(root.address[0])

    def copy(self, obj):
        if self.DEBUG:
            self.debug_check_can_copy(obj)
        if self.is_forwarded(obj):
            #llop.debug_print(lltype.Void, obj, "already copied to", self.get_forwarding_address(obj))
            return self.get_forwarding_address(obj)
        else:
            objsize = self.get_size(obj)
            newobj = self.make_a_copy(obj, objsize)
            #llop.debug_print(lltype.Void, obj, "copied to", newobj,
            #                 "tid", self.header(obj).tid,
            #                 "size", totalsize)
            self.set_forwarding_address(obj, newobj, objsize)
            return newobj

    def _get_object_hash(self, obj, objsize, tid):
        # Returns the hash of the object, which must not be GC_HASH_NOTTAKEN.
        gc_hash = tid & GCFLAG_HASHMASK
        if gc_hash == GC_HASH_HASFIELD:
            obj = llarena.getfakearenaaddress(obj)
            return (obj + objsize).signed[0]
        elif gc_hash == GC_HASH_TAKEN_ADDR:
            return llmemory.cast_adr_to_int(obj)
        elif gc_hash == GC_HASH_TAKEN_NURS:
            return self._compute_current_nursery_hash(obj)
        else:
            assert 0, "gc_hash == GC_HASH_NOTTAKEN"

    def _make_a_copy_with_tid(self, obj, objsize, tid):
        totalsize = self.size_gc_header() + objsize
        newaddr = self.free
        llarena.arena_reserve(newaddr, totalsize)
        raw_memcopy(obj - self.size_gc_header(), newaddr, totalsize)
        if tid & GCFLAG_HASHMASK:
            hash = self._get_object_hash(obj, objsize, tid)
            llarena.arena_reserve(newaddr + totalsize,
                                  llmemory.sizeof(lltype.Signed))
            (newaddr + totalsize).signed[0] = hash
            tid |= GC_HASH_HASFIELD
            totalsize += llmemory.sizeof(lltype.Signed)
        self.free += totalsize
        newhdr = llmemory.cast_adr_to_ptr(newaddr, lltype.Ptr(self.HDR))
        newhdr.tid = tid
        newobj = newaddr + self.size_gc_header()
        return newobj

    def make_a_copy(self, obj, objsize):
        tid = self.header(obj).tid
        return self._make_a_copy_with_tid(obj, objsize, tid)

    def trace_and_copy(self, obj):
        self.trace(obj, self._trace_copy, None)

    def _trace_copy(self, pointer, ignored):
        pointer.address[0] = self.copy(pointer.address[0])

    def surviving(self, obj):
        # To use during a collection.  Check if the object is currently
        # marked as surviving the collection.  This is equivalent to
        # self.is_forwarded() for all objects except the nonmoving objects
        # created by the HybridGC subclass.  In all cases, if an object
        # survives, self.get_forwarding_address() returns its new address.
        return self.is_forwarded(obj)

    def is_forwarded(self, obj):
        return self.header(obj).tid & GCFLAG_FORWARDED != 0
        # note: all prebuilt objects also have this flag set

    def get_forwarding_address(self, obj):
        tid = self.header(obj).tid
        if tid & GCFLAG_EXTERNAL:
            self.visit_external_object(obj)
            return obj  # external or prebuilt objects are "forwarded"
            # to themselves
        else:
            stub = llmemory.cast_adr_to_ptr(obj, self.FORWARDSTUBPTR)
            return stub.forw

    def visit_external_object(self, obj):
        pass  # hook for the HybridGC

    def get_possibly_forwarded_type_id(self, obj):
        tid = self.header(obj).tid
        if self.is_forwarded(obj) and not (tid & GCFLAG_EXTERNAL):
            obj = self.get_forwarding_address(obj)
        return self.get_type_id(obj)

    def set_forwarding_address(self, obj, newobj, objsize):
        # To mark an object as forwarded, we set the GCFLAG_FORWARDED and
        # overwrite the object with a FORWARDSTUB.  Doing so is a bit
        # long-winded on llarena, but it all melts down to two memory
        # writes after translation to C.
        size_gc_header = self.size_gc_header()
        stubsize = llmemory.sizeof(self.FORWARDSTUB)
        tid = self.header(obj).tid
        ll_assert(tid & GCFLAG_EXTERNAL == 0, "unexpected GCFLAG_EXTERNAL")
        ll_assert(tid & GCFLAG_FORWARDED == 0, "unexpected GCFLAG_FORWARDED")
        # replace the object at 'obj' with a FORWARDSTUB.
        hdraddr = obj - size_gc_header
        llarena.arena_reset(hdraddr, size_gc_header + objsize, False)
        llarena.arena_reserve(hdraddr, size_gc_header + stubsize)
        hdr = llmemory.cast_adr_to_ptr(hdraddr, lltype.Ptr(self.HDR))
        hdr.tid = tid | GCFLAG_FORWARDED
        stub = llmemory.cast_adr_to_ptr(obj, self.FORWARDSTUBPTR)
        stub.forw = newobj

    def combine(self, typeid16, flags):
        return llop.combine_ushort(lltype.Signed, typeid16, flags)

    def get_type_id(self, addr):
        tid = self.header(addr).tid
        ll_assert(
            tid & (GCFLAG_FORWARDED | GCFLAG_EXTERNAL) != GCFLAG_FORWARDED,
            "get_type_id on forwarded obj")
        # Non-prebuilt forwarded objects are overwritten with a FORWARDSTUB.
        # Although calling get_type_id() on a forwarded object works by itself,
        # we catch it as an error because it's likely that what is then
        # done with the typeid is bogus.
        return llop.extract_ushort(llgroup.HALFWORD, tid)

    def init_gc_object(self, addr, typeid16, flags=0):
        hdr = llmemory.cast_adr_to_ptr(addr, lltype.Ptr(self.HDR))
        hdr.tid = self.combine(typeid16, flags)

    def init_gc_object_immortal(self, addr, typeid16, flags=0):
        hdr = llmemory.cast_adr_to_ptr(addr, lltype.Ptr(self.HDR))
        flags |= GCFLAG_EXTERNAL | GCFLAG_FORWARDED | GC_HASH_TAKEN_ADDR
        hdr.tid = self.combine(typeid16, flags)
        # immortal objects always have GCFLAG_FORWARDED set;
        # see get_forwarding_address().

    def deal_with_objects_with_light_finalizers(self):
        """ This is a much simpler version of dealing with finalizers
        and an optimization - we can reasonably assume that those finalizers
        don't do anything fancy and *just* call them. Among other things
        they won't resurrect objects
        """
        new_objects = self.AddressStack()
        while self.objects_with_light_finalizers.non_empty():
            obj = self.objects_with_light_finalizers.pop()
            if self.surviving(obj):
                new_objects.append(self.get_forwarding_address(obj))
            else:
                self.call_destructor(obj)
        self.objects_with_light_finalizers.delete()
        self.objects_with_light_finalizers = new_objects

    def deal_with_objects_with_finalizers(self, scan):
        # walk over list of objects with finalizers
        # if it is not copied, add it to the list of to-be-called finalizers
        # and copy it, to me make the finalizer runnable
        # We try to run the finalizers in a "reasonable" order, like
        # CPython does.  The details of this algorithm are in
        # pypy/doc/discussion/finalizer-order.txt.
        new_with_finalizer = self.AddressDeque()
        marked = self.AddressDeque()
        pending = self.AddressStack()
        self.tmpstack = self.AddressStack()
        while self.objects_with_finalizers.non_empty():
            x = self.objects_with_finalizers.popleft()
            fq_nr = self.objects_with_finalizers.popleft()
            ll_assert(
                self._finalization_state(x) != 1, "bad finalization state 1")
            if self.surviving(x):
                new_with_finalizer.append(self.get_forwarding_address(x))
                new_with_finalizer.append(fq_nr)
                continue
            marked.append(x)
            marked.append(fq_nr)
            pending.append(x)
            while pending.non_empty():
                y = pending.pop()
                state = self._finalization_state(y)
                if state == 0:
                    self._bump_finalization_state_from_0_to_1(y)
                    self.trace(y, self._append_if_nonnull, pending)
                elif state == 2:
                    self._recursively_bump_finalization_state_from_2_to_3(y)
            scan = self._recursively_bump_finalization_state_from_1_to_2(
                x, scan)

        while marked.non_empty():
            x = marked.popleft()
            fq_nr = marked.popleft()
            state = self._finalization_state(x)
            ll_assert(state >= 2, "unexpected finalization state < 2")
            newx = self.get_forwarding_address(x)
            if state == 2:
                from rpython.rtyper.lltypesystem import rffi
                fq_index = rffi.cast(lltype.Signed, fq_nr)
                self.mark_finalizer_to_run(fq_index, newx)
                # we must also fix the state from 2 to 3 here, otherwise
                # we leave the GCFLAG_FINALIZATION_ORDERING bit behind
                # which will confuse the next collection
                self._recursively_bump_finalization_state_from_2_to_3(x)
            else:
                new_with_finalizer.append(newx)
                new_with_finalizer.append(fq_nr)

        self.tmpstack.delete()
        pending.delete()
        marked.delete()
        self.objects_with_finalizers.delete()
        self.objects_with_finalizers = new_with_finalizer
        return scan

    def _append_if_nonnull(pointer, stack):
        stack.append(pointer.address[0])

    _append_if_nonnull = staticmethod(_append_if_nonnull)

    def _finalization_state(self, obj):
        if self.surviving(obj):
            newobj = self.get_forwarding_address(obj)
            hdr = self.header(newobj)
            if hdr.tid & GCFLAG_FINALIZATION_ORDERING:
                return 2
            else:
                return 3
        else:
            hdr = self.header(obj)
            if hdr.tid & GCFLAG_FINALIZATION_ORDERING:
                return 1
            else:
                return 0

    def _bump_finalization_state_from_0_to_1(self, obj):
        ll_assert(
            self._finalization_state(obj) == 0,
            "unexpected finalization state != 0")
        hdr = self.header(obj)
        hdr.tid |= GCFLAG_FINALIZATION_ORDERING

    def _recursively_bump_finalization_state_from_2_to_3(self, obj):
        ll_assert(
            self._finalization_state(obj) == 2,
            "unexpected finalization state != 2")
        newobj = self.get_forwarding_address(obj)
        pending = self.tmpstack
        ll_assert(not pending.non_empty(), "tmpstack not empty")
        pending.append(newobj)
        while pending.non_empty():
            y = pending.pop()
            hdr = self.header(y)
            if hdr.tid & GCFLAG_FINALIZATION_ORDERING:  # state 2 ?
                hdr.tid &= ~GCFLAG_FINALIZATION_ORDERING  # change to state 3
                self.trace(y, self._append_if_nonnull, pending)

    def _recursively_bump_finalization_state_from_1_to_2(self, obj, scan):
        # recursively convert objects from state 1 to state 2.
        # Note that copy() copies all bits, including the
        # GCFLAG_FINALIZATION_ORDERING.  The mapping between
        # state numbers and the presence of this bit was designed
        # for the following to work :-)
        self.copy(obj)
        return self.scan_copied(scan)

    def invalidate_weakrefs(self):
        # walk over list of objects that contain weakrefs
        # if the object it references survives then update the weakref
        # otherwise invalidate the weakref
        new_with_weakref = self.AddressStack()
        while self.objects_with_weakrefs.non_empty():
            obj = self.objects_with_weakrefs.pop()
            if not self.surviving(obj):
                continue  # weakref itself dies
            obj = self.get_forwarding_address(obj)
            offset = self.weakpointer_offset(self.get_type_id(obj))
            pointing_to = (obj + offset).address[0]
            # XXX I think that pointing_to cannot be NULL here
            if pointing_to:
                if self.surviving(pointing_to):
                    (obj + offset
                     ).address[0] = self.get_forwarding_address(pointing_to)
                    new_with_weakref.append(obj)
                else:
                    (obj + offset).address[0] = NULL
        self.objects_with_weakrefs.delete()
        self.objects_with_weakrefs = new_with_weakref

    def _is_external(self, obj):
        return (self.header(obj).tid & GCFLAG_EXTERNAL) != 0

    def _is_in_the_space(self, obj):
        return self.tospace <= obj < self.free

    def debug_check_object(self, obj):
        """Check the invariants about 'obj' that should be true
        between collections."""
        tid = self.header(obj).tid
        if tid & GCFLAG_EXTERNAL:
            ll_assert(tid & GCFLAG_FORWARDED != 0, "bug: external+!forwarded")
            ll_assert(not (self.tospace <= obj < self.free),
                      "external flag but object inside the semispaces")
        else:
            ll_assert(not (tid & GCFLAG_FORWARDED), "bug: !external+forwarded")
            ll_assert(self.tospace <= obj < self.free,
                      "!external flag but object outside the semispaces")
        ll_assert(not (tid & GCFLAG_FINALIZATION_ORDERING),
                  "unexpected GCFLAG_FINALIZATION_ORDERING")

    def debug_check_can_copy(self, obj):
        ll_assert(not (self.tospace <= obj < self.free),
                  "copy() on already-copied object")

    STATISTICS_NUMBERS = 0

    def is_in_nursery(self, addr):
        # overridden in generation.py.
        return False

    def _compute_current_nursery_hash(self, obj):
        # overridden in generation.py.
        raise AssertionError("should not be called")

    def identityhash(self, gcobj):
        # The following loop should run at most twice.
        while 1:
            obj = llmemory.cast_ptr_to_adr(gcobj)
            hdr = self.header(obj)
            if hdr.tid & GCFLAG_HASHMASK:
                break
            # It's the first time we ask for a hash, and it's not an
            # external object.  Shrink the top of space by the extra
            # hash word that will be needed after a collect.
            shrunk_top = self.top_of_space - llmemory.sizeof(lltype.Signed)
            if shrunk_top < self.free:
                # Cannot shrink!  Do a collection, asking for at least
                # one word of free space, and try again.  May raise
                # MemoryError.  Obscure: not called directly, but
                # across an llop, to make sure that there is the
                # correct push_roots/pop_roots around the call...
                llop.gc_obtain_free_space(llmemory.Address,
                                          llmemory.sizeof(lltype.Signed))
                continue
            else:
                # Now we can have side-effects: lower the top of space
                # and set one of the GC_HASH_TAKEN_xxx flags.
                self.top_of_space = shrunk_top
                if self.is_in_nursery(obj):
                    hdr.tid |= GC_HASH_TAKEN_NURS
                else:
                    hdr.tid |= GC_HASH_TAKEN_ADDR
                break
        # Now we can return the result
        objsize = self.get_size(obj)
        return self._get_object_hash(obj, objsize, hdr.tid)

    def track_heap_parent(self, obj, parent):
        addr = obj.address[0]
        parent_idx = llop.get_member_index(lltype.Signed,
                                           self.get_type_id(parent))
        idx = llop.get_member_index(lltype.Signed, self.get_type_id(addr))
        self._ll_typeid_map[parent_idx].links[idx] += 1
        self.track_heap(addr)

    def track_heap(self, adr):
        if self._tracked_dict.contains(adr):
            return
        self._tracked_dict.add(adr)
        idx = llop.get_member_index(lltype.Signed, self.get_type_id(adr))
        self._ll_typeid_map[idx].count += 1
        totsize = self.get_size(adr) + self.size_gc_header()
        self._ll_typeid_map[idx].size += llmemory.raw_malloc_usage(totsize)
        self.trace(adr, self.track_heap_parent, adr)

    @staticmethod
    def _track_heap_root(obj, self):
        self.track_heap(obj)

    def heap_stats(self):
        self._tracked_dict = self.AddressDict()
        max_tid = self.root_walker.gcdata.max_type_id
        ll_typeid_map = lltype.malloc(ARRAY_TYPEID_MAP, max_tid, zero=True)
        for i in range(max_tid):
            ll_typeid_map[i] = lltype.malloc(TYPEID_MAP, max_tid, zero=True)
        self._ll_typeid_map = ll_typeid_map
        self._tracked_dict.add(llmemory.cast_ptr_to_adr(ll_typeid_map))
        i = 0
        while i < max_tid:
            self._tracked_dict.add(llmemory.cast_ptr_to_adr(ll_typeid_map[i]))
            i += 1
        self.enumerate_all_roots(SemiSpaceGC._track_heap_root, self)
        self._ll_typeid_map = lltype.nullptr(ARRAY_TYPEID_MAP)
        self._tracked_dict.delete()
        return ll_typeid_map
コード例 #28
0
from rpython.rtyper.lltypesystem import lltype
from rpython.translator.unsimplify import varoftype
from rpython.flowspace.model import Constant, SpaceOperation

from rpython.jit.codewriter.jtransform import Transformer, NotSupported
from rpython.jit.codewriter.flatten import GraphFlattener
from rpython.jit.codewriter.format import assert_format
from rpython.jit.codewriter.test.test_flatten import fake_regallocs
from rpython.jit.metainterp.history import AbstractDescr

# ____________________________________________________________

FIXEDLIST = lltype.Ptr(lltype.GcArray(lltype.Signed))
FIXEDPTRLIST = lltype.Ptr(lltype.GcArray(FIXEDLIST))
VARLIST = lltype.Ptr(lltype.GcStruct('VARLIST',
                                     ('length', lltype.Signed),
                                     ('items', FIXEDLIST),
                                     adtmeths={"ITEM": lltype.Signed}))

class FakeCPU:
    class arraydescrof(AbstractDescr):
        def __init__(self, ARRAY):
            assert ARRAY.OF != lltype.Void
            self.ARRAY = ARRAY
        def __repr__(self):
            return '<ArrayDescr>'
    class fielddescrof(AbstractDescr):
        def __init__(self, STRUCT, fieldname):
            self.STRUCT = STRUCT
            self.fieldname = fieldname
        def __repr__(self):
            return '<FieldDescr %s>' % self.fieldname
コード例 #29
0
from rpython.rtyper.lltypesystem import lltype, llmemory, llarena, rffi
from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.rlib.debug import ll_assert
from rpython.memory.gcheader import GCHeaderBuilder
from rpython.memory.support import DEFAULT_CHUNK_SIZE
from rpython.memory.support import get_address_stack, get_address_deque
from rpython.memory.support import AddressDict, null_address_dict
from rpython.rtyper.lltypesystem.llmemory import NULL, raw_malloc_usage
from rpython.rtyper.annlowlevel import cast_adr_to_nongc_instance

TYPEID_MAP = lltype.GcStruct('TYPEID_MAP', ('count', lltype.Signed),
                             ('size', lltype.Signed),
                             ('links', lltype.Array(lltype.Signed)))
ARRAY_TYPEID_MAP = lltype.GcArray(lltype.Ptr(TYPEID_MAP))


class GCBase(object):
    _alloc_flavor_ = "raw"
    moving_gc = False
    needs_write_barrier = False
    malloc_zero_filled = False
    prebuilt_gc_objects_are_static_roots = True
    can_usually_pin_objects = False
    object_minimal_size = 0
    gcflag_extra = 0  # or a real GC flag that is always 0 when not collecting

    def __init__(self,
                 config,
                 chunk_size=DEFAULT_CHUNK_SIZE,
                 translated_to_c=True):
        self.gcheaderbuilder = GCHeaderBuilder(self.HDR)
コード例 #30
0
from rpython.rlib import rgc
from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.jit.backend.llsupport.symbolic import WORD

GCREFTRACER = lltype.GcStruct('GCREFTRACER',
                              ('array_base_addr', lltype.Signed),
                              ('array_length', lltype.Signed),
                              rtti=True)


def gcrefs_trace(gc, obj_addr, callback, arg):
    obj = llmemory.cast_adr_to_ptr(obj_addr, lltype.Ptr(GCREFTRACER))
    i = 0
    length = obj.array_length
    addr = obj.array_base_addr
    while i < length:
        p = rffi.cast(llmemory.Address, addr + i * WORD)
        gc._trace_callback(callback, arg, p)
        i += 1


lambda_gcrefs_trace = lambda: gcrefs_trace


def make_framework_tracer(array_base_addr, gcrefs):
    # careful about the order here: the allocation of the GCREFTRACER
    # can trigger a GC.  So we must write the gcrefs into the raw
    # array only afterwards...
    rgc.register_custom_trace_hook(GCREFTRACER, lambda_gcrefs_trace)
    length = len(gcrefs)