1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
import py
from rpython.translator.backendopt.finalizer import FinalizerAnalyzer,\
FinalizerError
from rpython.translator.translator import TranslationContext, graphof
from rpython.translator.backendopt.all import backend_optimizations
from rpython.translator.unsimplify import varoftype
from rpython.rtyper.lltypesystem import lltype, rffi
from rpython.conftest import option
from rpython.rlib import rgc
class TestFinalizerAnalyzer(object):
""" Below are typical destructors that we encounter in pypy
"""
def analyze(self, func, sig, func_to_analyze=None, backendopt=False):
if func_to_analyze is None:
func_to_analyze = func
t = TranslationContext()
t.buildannotator().build_types(func, sig)
t.buildrtyper().specialize()
if backendopt:
backend_optimizations(t)
if option.view:
t.view()
a = FinalizerAnalyzer(t)
fgraph = graphof(t, func_to_analyze)
result = a.analyze_light_finalizer(fgraph)
return result
def test_nothing(self):
def f():
pass
r = self.analyze(f, [])
assert not r
def test_malloc(self):
S = lltype.GcStruct('S')
def f():
return lltype.malloc(S)
r = self.analyze(f, [])
assert r
def test_raw_free_getfield(self):
S = lltype.Struct('S')
class A(object):
def __init__(self):
self.x = lltype.malloc(S, flavor='raw')
def __del__(self):
if self.x:
lltype.free(self.x, flavor='raw')
self.x = lltype.nullptr(S)
def f():
return A()
r = self.analyze(f, [], A.__del__.im_func)
assert not r
def test_c_call(self):
C = rffi.CArray(lltype.Signed)
c = rffi.llexternal('x', [lltype.Ptr(C)], lltype.Signed)
def g():
p = lltype.malloc(C, 3, flavor='raw')
f(p)
def f(p):
c(rffi.ptradd(p, 0))
lltype.free(p, flavor='raw')
r = self.analyze(g, [], f, backendopt=True)
assert r
def test_c_call_without_release_gil(self):
C = rffi.CArray(lltype.Signed)
c = rffi.llexternal('x', [lltype.Ptr(C)], lltype.Signed,
releasegil=False)
def g():
p = lltype.malloc(C, 3, flavor='raw')
f(p)
def f(p):
c(rffi.ptradd(p, 0))
lltype.free(p, flavor='raw')
r = self.analyze(g, [], f, backendopt=True)
assert not r
def test_chain(self):
class B(object):
def __init__(self):
self.counter = 1
class A(object):
def __init__(self):
self.x = B()
def __del__(self):
self.x.counter += 1
def f():
A()
r = self.analyze(f, [], A.__del__.im_func)
assert r
def test_must_be_light_finalizer_decorator(self):
S = lltype.GcStruct('S')
@rgc.must_be_light_finalizer
def f():
lltype.malloc(S)
@rgc.must_be_light_finalizer
def g():
pass
self.analyze(g, []) # did not explode
py.test.raises(FinalizerError, self.analyze, f, [])
def test_various_ops():
from rpython.flowspace.model import SpaceOperation, Constant
X = lltype.Ptr(lltype.GcStruct('X'))
Z = lltype.Ptr(lltype.Struct('Z'))
S = lltype.GcStruct('S', ('x', lltype.Signed),
('y', X),
('z', Z))
v1 = varoftype(lltype.Bool)
v2 = varoftype(lltype.Signed)
f = FinalizerAnalyzer(None)
r = f.analyze(SpaceOperation('cast_int_to_bool', [v2],
v1))
assert not r
v1 = varoftype(lltype.Ptr(S))
v2 = varoftype(lltype.Signed)
v3 = varoftype(X)
v4 = varoftype(Z)
assert not f.analyze(SpaceOperation('bare_setfield', [v1, Constant('x'),
v2], None))
assert f.analyze(SpaceOperation('bare_setfield', [v1, Constant('y'),
v3], None))
assert not f.analyze(SpaceOperation('bare_setfield', [v1, Constant('z'),
v4], None))
|