Commit 5fcc3e2e authored by Stefan Behnel's avatar Stefan Behnel

speed up refnanny

parent 019ef377
from cpython.ref cimport PyObject, Py_INCREF, Py_DECREF, Py_XDECREF from cpython.ref cimport PyObject, Py_INCREF, Py_DECREF, Py_XDECREF, Py_XINCREF
from cpython.exc cimport PyErr_Fetch, PyErr_Restore from cpython.exc cimport PyErr_Fetch, PyErr_Restore
from cpython.pystate cimport PyThreadState_Get from cpython.pystate cimport PyThreadState_Get
cimport cython
loglevel = 0 loglevel = 0
reflog = [] reflog = []
...@@ -12,7 +13,13 @@ cdef log(level, action, obj, lineno): ...@@ -12,7 +13,13 @@ cdef log(level, action, obj, lineno):
LOG_NONE, LOG_ALL = range(2) LOG_NONE, LOG_ALL = range(2)
class Context(object): @cython.final
cdef class Context(object):
cdef object name, filename
cdef dict refs
cdef list errors
cdef Py_ssize_t start
def __init__(self, name, line=0, filename=None): def __init__(self, name, line=0, filename=None):
self.name = name self.name = name
self.start = line self.start = line
...@@ -20,7 +27,7 @@ class Context(object): ...@@ -20,7 +27,7 @@ class Context(object):
self.refs = {} # id -> (count, [lineno]) self.refs = {} # id -> (count, [lineno])
self.errors = [] self.errors = []
def regref(self, obj, lineno, is_null): cdef regref(self, obj, lineno, bint is_null):
log(LOG_ALL, u'regref', u"<NULL>" if is_null else obj, lineno) log(LOG_ALL, u'regref', u"<NULL>" if is_null else obj, lineno)
if is_null: if is_null:
self.errors.append(u"NULL argument on line %d" % lineno) self.errors.append(u"NULL argument on line %d" % lineno)
...@@ -30,7 +37,7 @@ class Context(object): ...@@ -30,7 +37,7 @@ class Context(object):
self.refs[id_] = (count + 1, linenumbers) self.refs[id_] = (count + 1, linenumbers)
linenumbers.append(lineno) linenumbers.append(lineno)
def delref(self, obj, lineno, is_null): cdef bint delref(self, obj, lineno, bint is_null) except -1:
# returns whether it is ok to do the decref operation # returns whether it is ok to do the decref operation
log(LOG_ALL, u'delref', u"<NULL>" if is_null else obj, lineno) log(LOG_ALL, u'delref', u"<NULL>" if is_null else obj, lineno)
if is_null: if is_null:
...@@ -49,8 +56,8 @@ class Context(object): ...@@ -49,8 +56,8 @@ class Context(object):
self.refs[id_] = (count - 1, linenumbers) self.refs[id_] = (count - 1, linenumbers)
return True return True
def end(self): cdef end(self):
if len(self.refs) > 0: if self.refs:
msg = u"" msg = u""
for count, linenos in self.refs.itervalues(): for count, linenos in self.refs.itervalues():
msg += u"\n Acquired on lines: " + u", ".join([u"%d" % x for x in linenos]) msg += u"\n Acquired on lines: " + u", ".join([u"%d" % x for x in linenos])
...@@ -99,9 +106,9 @@ cdef void GOTREF(PyObject* ctx, PyObject* p_obj, int lineno): ...@@ -99,9 +106,9 @@ cdef void GOTREF(PyObject* ctx, PyObject* p_obj, int lineno):
try: try:
try: try:
if p_obj is NULL: if p_obj is NULL:
(<object>ctx).regref(None, lineno, True) (<Context>ctx).regref(None, lineno, True)
else: else:
(<object>ctx).regref(<object>p_obj, lineno, False) (<Context>ctx).regref(<object>p_obj, lineno, False)
except: except:
report_unraisable() report_unraisable()
except: except:
...@@ -117,9 +124,9 @@ cdef int GIVEREF_and_report(PyObject* ctx, PyObject* p_obj, int lineno): ...@@ -117,9 +124,9 @@ cdef int GIVEREF_and_report(PyObject* ctx, PyObject* p_obj, int lineno):
try: try:
try: try:
if p_obj is NULL: if p_obj is NULL:
decref_ok = (<object>ctx).delref(None, lineno, True) decref_ok = (<Context>ctx).delref(None, lineno, True)
else: else:
decref_ok = (<object>ctx).delref(<object>p_obj, lineno, False) decref_ok = (<Context>ctx).delref(<object>p_obj, lineno, False)
except: except:
report_unraisable() report_unraisable()
except: except:
...@@ -132,34 +139,36 @@ cdef void GIVEREF(PyObject* ctx, PyObject* p_obj, int lineno): ...@@ -132,34 +139,36 @@ cdef void GIVEREF(PyObject* ctx, PyObject* p_obj, int lineno):
GIVEREF_and_report(ctx, p_obj, lineno) GIVEREF_and_report(ctx, p_obj, lineno)
cdef void INCREF(PyObject* ctx, PyObject* obj, int lineno): cdef void INCREF(PyObject* ctx, PyObject* obj, int lineno):
if obj is not NULL: Py_INCREF(<object>obj) Py_XINCREF(obj)
PyThreadState_Get() PyThreadState_Get()
GOTREF(ctx, obj, lineno) GOTREF(ctx, obj, lineno)
cdef void DECREF(PyObject* ctx, PyObject* obj, int lineno): cdef void DECREF(PyObject* ctx, PyObject* obj, int lineno):
if GIVEREF_and_report(ctx, obj, lineno): if GIVEREF_and_report(ctx, obj, lineno):
if obj is not NULL: Py_DECREF(<object>obj) Py_XDECREF(obj)
PyThreadState_Get() PyThreadState_Get()
cdef void FinishContext(PyObject** ctx): cdef void FinishContext(PyObject** ctx):
if ctx == NULL or ctx[0] == NULL: return if ctx == NULL or ctx[0] == NULL: return
cdef PyObject* type = NULL, *value = NULL, *tb = NULL cdef PyObject* type = NULL, *value = NULL, *tb = NULL
cdef object errors = None cdef object errors = None
cdef Context context
PyThreadState_Get() PyThreadState_Get()
PyErr_Fetch(&type, &value, &tb) PyErr_Fetch(&type, &value, &tb)
try: try:
try: try:
errors = (<object>ctx[0]).end() context = <Context>ctx[0]
pos = (<object>ctx[0]).filename, (<object>ctx[0]).name errors = context.end()
if errors: if errors:
print u"%s: %s()" % pos print u"%s: %s()" % (context.filename, context.name)
print errors print errors
context = None
except: except:
report_unraisable() report_unraisable()
except: except:
# __Pyx_GetException may itself raise errors # __Pyx_GetException may itself raise errors
pass pass
Py_DECREF(<object>ctx[0]) Py_XDECREF(ctx[0])
ctx[0] = NULL ctx[0] = NULL
PyErr_Restore(type, value, tb) PyErr_Restore(type, value, tb)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment