Commit bf66352f authored by Robert Bradshaw's avatar Robert Bradshaw

merge

parents 23e8ad80 951fba0c
......@@ -305,7 +305,7 @@ def put_assign_to_buffer(lhs_cname, rhs_cname, buffer_aux, buffer_type,
for i in range(3)]
code.putln('PyErr_Fetch(&%s, &%s, &%s);' % (type, value, tb))
code.putln('if (%s) {' % code.unlikely("%s == -1" % (getbuffer % lhs_cname)))
code.putln('Py_XDECREF(%s); Py_XDECREF(%s); Py_XDECREF(%s);' % (type, value, tb))
code.putln('Py_XDECREF(%s); Py_XDECREF(%s); Py_XDECREF(%s);' % (type, value, tb)) # Do not refnanny these!
code.globalstate.use_utility_code(raise_buffer_fallback_code)
code.putln('__Pyx_RaiseBufferFallbackError();')
code.putln('} else {')
......@@ -323,7 +323,7 @@ def put_assign_to_buffer(lhs_cname, rhs_cname, buffer_aux, buffer_type,
# In this case, auxiliary vars should be set up right in initialization to a zero-buffer,
# so it suffices to set the buf field to NULL.
code.putln('if (%s) {' % code.unlikely("%s == -1" % (getbuffer % rhs_cname)))
code.putln('%s = %s; Py_INCREF(Py_None); %s.buf = NULL;' %
code.putln('%s = %s; __Pyx_INCREF(Py_None); %s.buf = NULL;' %
(lhs_cname,
PyrexTypes.typecast(buffer_type, PyrexTypes.py_object_type, "Py_None"),
bufstruct))
......
......@@ -320,7 +320,7 @@ class GlobalState(object):
def should_declare(self, cname, entry):
if cname in self.declared_cnames:
other = self.declared_cnames[cname]
assert entry.type == other.type
assert str(entry.type) == str(other.type)
assert entry.init == other.init
return False
else:
......@@ -749,6 +749,9 @@ class CCodeWriter(object):
def put_xgiveref(self, cname):
self.putln("__Pyx_XGIVEREF(%s);" % cname)
def put_xgotref(self, cname):
self.putln("__Pyx_XGOTREF(%s);" % cname)
def put_incref(self, cname, type, nanny=True):
if nanny:
self.putln("__Pyx_INCREF(%s);" % self.as_pyobject(cname, type))
......
......@@ -1333,6 +1333,8 @@ class NameNode(AtomicExprNode):
#print "...from", rhs ###
#print "...LHS type", self.type, "ctype", self.ctype() ###
#print "...RHS type", rhs.type, "ctype", rhs.ctype() ###
if entry.is_cglobal:
code.put_gotref(self.py_result())
if not self.lhs_of_first_assignment:
if entry.is_local and not Options.init_local_none:
initalized = entry.scope.control_flow.get_state((entry.name, 'initalized'), self.pos)
......@@ -1342,6 +1344,8 @@ class NameNode(AtomicExprNode):
code.put_xdecref(self.result(), self.ctype())
else:
code.put_decref(self.result(), self.ctype())
if entry.is_cglobal:
code.put_giveref(rhs.py_result())
code.putln('%s = %s;' % (self.result(), rhs.result_as(self.ctype())))
if debug_disposal_code:
print("NameNode.generate_assignment_code:")
......@@ -1874,10 +1878,12 @@ class IndexNode(ExprNode):
ptr = code.funcstate.allocate_temp(self.buffer_type.buffer_ptr_type, manage_ref=False)
rhs_code = rhs.result()
code.putln("%s = %s;" % (ptr, ptrexpr))
code.put_gotref("*%s" % ptr)
code.putln("__Pyx_DECREF(*%s); __Pyx_INCREF(%s);" % (
ptr, rhs_code
))
code.putln("*%s %s= %s;" % (ptr, op, rhs_code))
code.put_giveref("*%s" % ptr)
code.funcstate.release_temp(ptr)
else:
# Simple case
......@@ -2060,6 +2066,7 @@ class SliceIndexNode(ExprNode):
self.base.result(), start_offset, i,
rhs.result(), i))
self.generate_subexpr_disposal_code(code)
self.free_subexpr_temps(code)
rhs.generate_disposal_code(code)
rhs.free_temps(code)
......@@ -2882,6 +2889,8 @@ class AttributeNode(NewTempExprNode):
select_code = self.result()
if self.type.is_pyobject:
rhs.make_owned_reference(code)
code.put_giveref(rhs.py_result())
code.put_gotref(select_code)
code.put_decref(select_code, self.ctype())
code.putln(
"%s = %s;" % (
......@@ -3349,6 +3358,7 @@ class SetNode(NewTempExprNode):
"%s = PySet_New(0); %s" % (
self.result(),
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
for arg in self.args:
arg.generate_evaluation_code(code)
code.putln(
......
......@@ -1585,7 +1585,17 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("PyObject* %s;" % Naming.retval_cname)
tempdecl_code = code.insertion_point()
code.put_setup_refcount_context(header3)
code.putln("#ifdef CYTHON_REFNANNY")
code.putln("void* __pyx_refchk = NULL;")
code.putln("__Pyx_Refnanny = __Pyx_ImportRefcountAPI(\"refnanny\");")
code.putln("if (!__Pyx_Refnanny) {")
code.putln(" PyErr_Clear();")
code.putln(" __Pyx_Refnanny = __Pyx_ImportRefcountAPI(\"Cython.Runtime.refnanny\");")
code.putln(" if (!__Pyx_Refnanny)")
code.putln(" Py_FatalError(\"failed to import refnanny module\");")
code.putln("}")
code.putln("__pyx_refchk = __Pyx_Refnanny->NewContext(\"%s\", __LINE__);"% header3)
code.putln("#endif")
code.putln("%s = PyTuple_New(0); %s" % (Naming.empty_tuple, code.error_goto_if_null(Naming.empty_tuple, self.pos)));
......@@ -1640,8 +1650,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
env.use_utility_code(Nodes.traceback_utility_code)
code.putln("%s = NULL;" % Naming.retval_cname)
code.put_label(code.return_label)
code.put_finish_refcount_context(self.pos, env.qualified_name,
Naming.retval_cname, "NULL")
# Disabled because of confusion with refcount of global variables -- run ass2cglobal testcase to see
#code.put_finish_refcount_context(self.pos, env.qualified_name,
# Naming.retval_cname, "NULL")
code.putln("#if CYTHON_REFNANNY")
code.putln("if (__pyx_refchk) {};")
code.putln("#endif")
code.putln("#if PY_MAJOR_VERSION < 3")
code.putln("return;")
code.putln("#else")
......@@ -2319,29 +2333,35 @@ bad:
refcount_utility_code = UtilityCode(proto="""
#ifdef CYTHON_REFNANNY
void __Pyx_Refnanny_INCREF(void*, PyObject*, int);
void __Pyx_Refnanny_GOTREF(void*, PyObject*, int);
void __Pyx_Refnanny_GIVEREF(void*, PyObject*, int);
void __Pyx_Refnanny_INCREF(void*, PyObject*, int);
void __Pyx_Refnanny_DECREF(void*, PyObject*, int);
void* __Pyx_Refnanny_NewContext(char*, int);
int __Pyx_Refnanny_FinishContext(void*);
#define __Pyx_INCREF(r) __Pyx_Refnanny_INCREF(__pyx_refchk, r, __LINE__)
#define __Pyx_GOTREF(r) __Pyx_Refnanny_GOTREF(__pyx_refchk, r, __LINE__)
#define __Pyx_GIVEREF(r) __Pyx_Refnanny_GIVEREF(__pyx_refchk, r, __LINE__)
#define __Pyx_DECREF(r) __Pyx_Refnanny_DECREF(__pyx_refchk, r, __LINE__)
#define __Pyx_XDECREF(r) (r ? __Pyx_Refnanny_DECREF(__pyx_refchk, r, __LINE__) : 0)
typedef struct {
void (*INCREF)(void*, PyObject*, int);
void (*DECREF)(void*, PyObject*, int);
void (*GOTREF)(void*, PyObject*, int);
void (*GIVEREF)(void*, PyObject*, int);
void* (*NewContext)(const char*, int);
int (*FinishContext)(void**);
} __Pyx_RefnannyAPIStruct;
static __Pyx_RefnannyAPIStruct *__Pyx_Refnanny = NULL;
#define __Pyx_ImportRefcountAPI(name) \
(__Pyx_RefnannyAPIStruct *) PyCObject_Import((char *)name, (char *)\"RefnannyAPI\")
#define __Pyx_INCREF(r) __Pyx_Refnanny->INCREF(__pyx_refchk, (PyObject *)(r), __LINE__)
#define __Pyx_DECREF(r) __Pyx_Refnanny->DECREF(__pyx_refchk, (PyObject *)(r), __LINE__)
#define __Pyx_GOTREF(r) __Pyx_Refnanny->GOTREF(__pyx_refchk, (PyObject *)(r), __LINE__)
#define __Pyx_GIVEREF(r) __Pyx_Refnanny->GIVEREF(__pyx_refchk, (PyObject *)(r), __LINE__)
#define __Pyx_XDECREF(r) if((r) == NULL) ; else __Pyx_DECREF(r)
#define __Pyx_SetupRefcountContext(name) \
void* __pyx_refchk = __Pyx_Refnanny_NewContext(name, __LINE__)
#define __Pyx_FinishRefcountContext() __Pyx_Refnanny_FinishContext(__pyx_refchk)
void* __pyx_refchk = __Pyx_Refnanny->NewContext((name), __LINE__)
#define __Pyx_FinishRefcountContext() \
__Pyx_Refnanny->FinishContext(&__pyx_refchk)
#else
#define __Pyx_INCREF(r) Py_INCREF(r)
#define __Pyx_DECREF(r) Py_DECREF(r)
#define __Pyx_GOTREF(r)
#define __Pyx_GIVEREF(r)
#define __Pyx_DECREF(r) Py_DECREF(r)
#define __Pyx_XDECREF(r) Py_XDECREF(r)
#define __Pyx_SetupRefcountContext(name)
#define __Pyx_FinishRefcountContext() 0
#endif /* CYTHON_REFNANNY */
#define __Pyx_XGIVEREF(r) (r ? __Pyx_GIVEREF(r) : 0)
#define __Pyx_XGIVEREF(r) if((r) == NULL) ; else __Pyx_GIVEREF(r)
#define __Pyx_XGOTREF(r) if((r) == NULL) ; else __Pyx_GOTREF(r)
""")
......@@ -1068,10 +1068,10 @@ class FuncDefNode(StatNode, BlockNode):
if acquire_gil:
code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
# ----- Automatic lead-ins for certain special functions
if is_getbuffer_slot:
self.getbuffer_init(code)
if not lenv.nogil:
code.put_setup_refcount_context(self.entry.name)
if is_getbuffer_slot:
self.getbuffer_init(code)
# ----- Fetch arguments
self.generate_argument_parsing_code(env, code)
# If an argument is assigned to in the body, we must
......@@ -1181,8 +1181,7 @@ class FuncDefNode(StatNode, BlockNode):
for entry in lenv.arg_entries:
if entry.type.is_pyobject and lenv.control_flow.get_state((entry.name, 'source')) != 'arg':
code.put_var_decref(entry)
if acquire_gil:
code.putln("PyGILState_Release(_save);")
# code.putln("/* TODO: decref scope object */")
# ----- Return
# This code is duplicated in ModuleNode.generate_module_init_func
......@@ -1199,6 +1198,9 @@ class FuncDefNode(StatNode, BlockNode):
Naming.retval_cname,
err_val)
if acquire_gil:
code.putln("PyGILState_Release(_save);")
if not self.return_type.is_void:
code.putln("return %s;" % Naming.retval_cname)
......@@ -1254,16 +1256,20 @@ class FuncDefNode(StatNode, BlockNode):
# the following line should be removed when this bug is fixed.
code.putln("if (%s == NULL) return 0;" % info)
code.putln("%s->obj = Py_None; __Pyx_INCREF(Py_None);" % info)
code.put_giveref("%s->obj" % info) # Do not refnanny object within structs
def getbuffer_error_cleanup(self, code):
info = self.local_scope.arg_entries[1].cname
code.put_gotref("%s->obj" % info)
code.putln("__Pyx_DECREF(%s->obj); %s->obj = NULL;" %
(info, info))
def getbuffer_normal_cleanup(self, code):
info = self.local_scope.arg_entries[1].cname
code.putln("if (%s->obj == Py_None) { __Pyx_DECREF(Py_None); %s->obj = NULL; }" %
(info, info))
code.putln("if (%s->obj == Py_None) {" % info)
code.put_gotref("Py_None")
code.putln("__Pyx_DECREF(Py_None); %s->obj = NULL;" % info)
code.putln("}")
class CFuncDefNode(FuncDefNode):
# C function definition.
......@@ -2014,6 +2020,8 @@ class DefNode(FuncDefNode):
code.putln("if (unlikely(!%s)) return %s;" % (
self.starstar_arg.entry.cname, self.error_value()))
self.starstar_arg.entry.xdecref_cleanup = 0
code.put_gotref(self.starstar_arg.entry.cname)
if self.star_arg:
code.put_incref(Naming.args_cname, py_object_type)
......@@ -2145,6 +2153,7 @@ class DefNode(FuncDefNode):
self.starstar_arg.entry.cname,
self.starstar_arg.entry.cname,
self.error_value()))
code.put_gotref(self.starstar_arg.entry.cname)
if self.star_arg:
self.star_arg.entry.xdecref_cleanup = 0
code.putln('if (PyTuple_GET_SIZE(%s) > %d) {' % (
......@@ -2153,6 +2162,7 @@ class DefNode(FuncDefNode):
code.put('%s = PyTuple_GetSlice(%s, %d, PyTuple_GET_SIZE(%s)); ' % (
self.star_arg.entry.cname, Naming.args_cname,
max_positional_args, Naming.args_cname))
code.put_gotref(self.star_arg.entry.cname)
if self.starstar_arg:
code.putln("")
code.putln("if (unlikely(!%s)) {" % self.star_arg.entry.cname)
......@@ -3232,6 +3242,7 @@ class ExecStatNode(StatNode):
arg.free_temps(code)
code.putln(
code.error_goto_if_null(self.temp_result, self.pos))
code.put_gotref(self.temp_result)
code.put_decref_clear(self.temp_result, py_object_type)
def annotate(self, code):
......@@ -3895,9 +3906,15 @@ class ForFromStatNode(LoopNode, StatNode):
self.bound1.generate_evaluation_code(code)
self.bound2.generate_evaluation_code(code)
offset, incop = self.relation_table[self.relation1]
if incop == "++":
decop = "--"
else:
decop = "++"
if self.step is not None:
self.step.generate_evaluation_code(code)
incop = "%s=%s" % (incop[0], self.step.result())
step = self.step.result()
incop = "%s=%s" % (incop[0], step)
decop = "%s=%s" % (decop[0], step)
loopvar_name = self.loopvar_node.result()
code.putln(
"for (%s = %s%s; %s %s %s; %s%s) {" % (
......@@ -3910,7 +3927,11 @@ class ForFromStatNode(LoopNode, StatNode):
self.target.generate_assignment_code(self.py_loopvar_node, code)
self.body.generate_execution_code(code)
code.put_label(code.continue_label)
code.putln("}")
if getattr(self, "from_range", False):
# Undo last increment to maintain Python semantics:
code.putln("} %s%s;" % (loopvar_name, decop))
else:
code.putln("}")
break_label = code.break_label
code.set_loop_labels(old_loop_labels)
if self.else_clause:
......@@ -4026,6 +4047,8 @@ class TryExceptStatNode(StatNode):
', '.join(['*%s' % var for var in Naming.exc_save_vars]))
code.putln("__Pyx_ExceptionSave(%s);" %
', '.join(['&%s' % var for var in Naming.exc_save_vars]))
for var in Naming.exc_save_vars:
code.put_xgotref(var)
code.putln(
"/*try:*/ {")
code.return_label = try_return_label
......@@ -4066,12 +4089,14 @@ class TryExceptStatNode(StatNode):
if code.label_used(except_return_label):
code.put_label(except_return_label)
for var in Naming.exc_save_vars: code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s);" %
', '.join(Naming.exc_save_vars))
code.put_goto(old_return_label)
if code.label_used(except_end_label):
code.put_label(except_end_label)
for var in Naming.exc_save_vars: code.put_xgiveref(var)
code.putln("__Pyx_ExceptionReset(%s);" %
', '.join(Naming.exc_save_vars))
code.put_label(try_end_label)
......@@ -4170,6 +4195,8 @@ class ExceptClauseNode(Node):
exc_args = "&%s, &%s, &%s" % tuple(self.exc_vars)
code.putln("if (__Pyx_GetException(%s) < 0) %s" % (exc_args,
code.error_goto(self.pos)))
for x in self.exc_vars:
code.put_gotref(x)
if self.target:
self.exc_value.generate_evaluation_code(code)
self.target.generate_assignment_code(self.exc_value, code)
......
......@@ -144,7 +144,8 @@ class IterationTransform(Visitor.VisitorTransform):
relation2=relation2, bound2=bound2,
step=step, body=node.body,
else_clause=node.else_clause,
loopvar_node=node.target)
loopvar_node=node.target,
from_range=True)
return for_node
def _transform_dict_iteration(self, node, dict_obj, keys, values):
......
......@@ -3,7 +3,7 @@ from Cython.Compiler.ModuleNode import ModuleNode
from Cython.Compiler.Nodes import *
from Cython.Compiler.ExprNodes import *
from Cython.Compiler.UtilNodes import *
from Cython.Compiler.TreeFragment import TreeFragment
from Cython.Compiler.TreeFragment import TreeFragment, TemplateTransform
from Cython.Compiler.StringEncoding import EncodedString
from Cython.Compiler.Errors import CompileError
try:
......@@ -539,35 +539,39 @@ class WithTransform(CythonTransform, SkipDeclarations):
finally:
if EXC:
EXIT(None, None, None)
MGR = EXIT = VALUE = EXC = None
""", temps=[u'MGR', u'EXC', u"EXIT", u"VALUE"],
pipeline=[NormalizeTree(None)])
def visit_WithStatNode(self, node):
# TODO: Cleanup badly needed
TemplateTransform.temp_name_counter += 1
handle = "__tmpvar_%d" % TemplateTransform.temp_name_counter
self.visitchildren(node, ['body'])
# FIXME: excinfo_temp should be more local to the except
# clause that uses it, to avoid the presetting to None
excinfo_temp = TempHandle(Builtin.tuple_type)
excinfo_temp = NameNode(node.pos, name=handle)#TempHandle(Builtin.tuple_type)
if node.target is not None:
result = self.template_with_target.substitute({
u'EXPR' : node.manager,
u'BODY' : node.body,
u'TARGET' : node.target,
u'EXCINFO' : excinfo_temp.ref(node.pos)
u'EXCINFO' : excinfo_temp
}, pos=node.pos)
else:
result = self.template_without_target.substitute({
u'EXPR' : node.manager,
u'BODY' : node.body,
u'EXCINFO' : excinfo_temp.ref(node.pos)
u'EXCINFO' : excinfo_temp
}, pos=node.pos)
# Set except excinfo target to EXCINFO
try_except = result.body.stats[-1].body.stats[-1]
try_except.except_clauses[0].excinfo_target = (
excinfo_temp.ref(node.pos))
try_except = result.stats[-1].body.stats[-1]
try_except.except_clauses[0].excinfo_target = NameNode(node.pos, name=handle)
# excinfo_temp.ref(node.pos))
result.body.stats[-1].body.stats[-1] = TempsBlockNode(
node.pos, temps=[excinfo_temp], body=try_except)
# result.stats[-1].body.stats[-1] = TempsBlockNode(
# node.pos, temps=[excinfo_temp], body=try_except)
return result
......
......@@ -1399,14 +1399,18 @@ static INLINE Py_ssize_t __pyx_PyIndex_AsSsize_t(PyObject* b) {
static INLINE int __Pyx_PyObject_IsTrue(PyObject* x) {
if (x == Py_True) return 1;
else if (x == Py_False) return 0;
else if (x == Py_None) return 0;
else return PyObject_IsTrue(x);
}
static INLINE PY_LONG_LONG __pyx_PyInt_AsLongLong(PyObject* x) {
#if PY_VERSION_HEX < 0x03000000
if (PyInt_CheckExact(x)) {
return PyInt_AS_LONG(x);
}
else if (PyLong_CheckExact(x)) {
else
#endif
if (PyLong_CheckExact(x)) {
return PyLong_AsLongLong(x);
}
else {
......@@ -1419,19 +1423,22 @@ static INLINE PY_LONG_LONG __pyx_PyInt_AsLongLong(PyObject* x) {
}
static INLINE unsigned PY_LONG_LONG __pyx_PyInt_AsUnsignedLongLong(PyObject* x) {
#if PY_VERSION_HEX < 0x03000000
if (PyInt_CheckExact(x)) {
long val = PyInt_AS_LONG(x);
if (unlikely(val < 0)) {
PyErr_SetString(PyExc_TypeError, "Negative assignment to unsigned type.");
PyErr_SetString(PyExc_OverflowError, "can't convert negative value to unsigned long long");
return (unsigned PY_LONG_LONG)-1;
}
return val;
}
else if (PyLong_CheckExact(x)) {
else
#endif
if (PyLong_CheckExact(x)) {
return PyLong_AsUnsignedLongLong(x);
}
else {
PY_LONG_LONG val;
unsigned PY_LONG_LONG val;
PyObject* tmp = PyNumber_Int(x); if (!tmp) return (PY_LONG_LONG)-1;
val = __pyx_PyInt_AsUnsignedLongLong(tmp);
Py_DECREF(tmp);
......
......@@ -85,7 +85,7 @@ class TestNormalizeTree(TransformTest):
t = self.run_pipeline([NormalizeTree(None)], u"pass")
self.assert_(len(t.stats) == 0)
class TestWithTransform(TransformTest):
class TestWithTransform:#(TransformTest): Disabled
def test_simplified(self):
t = self.run_pipeline([WithTransform(None)], u"""
......
......@@ -48,17 +48,17 @@ class TestTreeFragments(CythonTest):
self.assertEquals(v.pos, a.pos)
def test_temps(self):
import Cython.Compiler.Visitor as v
v.tmpnamectr = 0
TemplateTransform.temp_name_counter = 0
F = self.fragment(u"""
TMP
x = TMP
""")
T = F.substitute(temps=[u"TMP"])
s = T.body.stats
self.assert_(isinstance(s[0].expr, TempRefNode))
self.assert_(isinstance(s[1].rhs, TempRefNode))
self.assert_(s[0].expr.handle is s[1].rhs.handle)
s = T.stats
self.assert_(s[0].expr.name == "__tmpvar_1")
# self.assert_(isinstance(s[0].expr, TempRefNode))
# self.assert_(isinstance(s[1].rhs, TempRefNode))
# self.assert_(s[0].expr.handle is s[1].rhs.handle)
if __name__ == "__main__":
import unittest
......
......@@ -111,21 +111,25 @@ class TemplateTransform(VisitorTransform):
recursively applied to every member node.
"""
temp_name_counter = 0
def __call__(self, node, substitutions, temps, pos):
self.substitutions = substitutions
self.pos = pos
tempmap = {}
temphandles = []
for temp in temps:
handle = UtilNodes.TempHandle(PyrexTypes.py_object_type)
TemplateTransform.temp_name_counter += 1
handle = "__tmpvar_%d" % TemplateTransform.temp_name_counter
# handle = UtilNodes.TempHandle(PyrexTypes.py_object_type)
tempmap[temp] = handle
temphandles.append(handle)
# temphandles.append(handle)
self.tempmap = tempmap
result = super(TemplateTransform, self).__call__(node)
if temps:
result = UtilNodes.TempsBlockNode(self.get_pos(node),
temps=temphandles,
body=result)
# if temps:
# result = UtilNodes.TempsBlockNode(self.get_pos(node),
# temps=temphandles,
# body=result)
return result
def get_pos(self, node):
......@@ -156,8 +160,10 @@ class TemplateTransform(VisitorTransform):
def visit_NameNode(self, node):
temphandle = self.tempmap.get(node.name)
if temphandle:
node.name = temphandle
return node
# Replace name with temporary
return temphandle.ref(self.get_pos(node))
#return temphandle.ref(self.get_pos(node))
else:
return self.try_substitution(node, node.name)
......
......@@ -164,14 +164,18 @@ class EvalWithTempExprNode(ExprNodes.NewTempExprNode):
def generate_evaluation_code(self, code):
self.temp_expression.generate_evaluation_code(code)
if self.temp_expression.is_temp:
result_in_temp = self.temp_expression.result_in_temp()
temp_type = self.temp_expression.type
if result_in_temp:
temp = self.temp_expression.result()
else:
self.temp_expression.make_owned_reference(code)
temp = code.funcstate.allocate_temp(
self.temp_expression.type, manage_ref=True)
temp_type, manage_ref=True)
code.putln("%s = %s;" % (temp, self.temp_expression.result()))
self.lazy_temp.result_code = temp
self.subexpression.generate_evaluation_code(code)
if not self.temp_expression.is_temp:
if not result_in_temp:
if temp_type.is_pyobject:
code.put_decref_clear(temp, temp_type)
code.funcstate.release_temp(temp)
# Temporary hacky script, should be replaced
# with distutils-based solution.
#PYTHONINC=/local/include/python2.5
PYTHONINC=/usr/include/python2.5
python ../../cython.py refnanny.pyx
gcc -shared -pthread -fPIC -fwrapv -g -Wall \
-fno-strict-aliasing -I$PYTHONINC \
-o refnanny.so -I. refnanny.c
from python_ref cimport Py_INCREF, Py_DECREF, Py_XDECREF
cimport python_exc as exc
from python_exc cimport PyObject, PyErr_Fetch, PyErr_Restore
loglevel = 0
......@@ -11,23 +11,29 @@ cdef log(level, action, obj, lineno):
LOG_NONE, LOG_ALL = range(2)
class RefnannyException(Exception):
class Error(Exception):
pass
class RefnannyContext(object):
class Context(object):
def __init__(self):
self.refs = {} # id -> (count, [lineno])
self.errors = []
def regref(self, obj, lineno):
log(LOG_ALL, 'regref', obj, lineno)
def regref(self, obj, lineno, is_null):
log(LOG_ALL, 'regref', "<NULL>" if is_null else obj, lineno)
if is_null:
self.errors.append("NULL argument on line %d" % lineno)
return
id_ = id(obj)
count, linenumbers = self.refs.get(id_, (0, []))
self.refs[id_] = (count + 1, linenumbers)
linenumbers.append(lineno)
def delref(self, obj, lineno):
log(LOG_ALL, 'delref', obj, lineno)
def delref(self, obj, lineno, is_null):
log(LOG_ALL, 'delref', "<NULL>" if is_null else obj, lineno)
if is_null:
self.errors.append("NULL argument on line %d" % lineno)
return
id_ = id(obj)
count, linenumbers = self.refs.get(id_, (0, []))
if count == 0:
......@@ -45,44 +51,108 @@ class RefnannyContext(object):
msg += "\n Acquired on lines: " + ", ".join(["%d" % x for x in linenos])
self.errors.append("References leaked: %s" % msg)
if self.errors:
print self.errors
# raise RefnannyException("\n".join(self.errors))
return "\n".join(self.errors)
else:
return None
cdef public void* __Pyx_Refnanny_NewContext(char* funcname, int lineno) except NULL:
ctx = RefnannyContext()
Py_INCREF(ctx)
return <void*>ctx
cdef public void __Pyx_Refnanny_GOTREF(void* ctx, object obj, int lineno):
cdef PyObject* NewContext(char* funcname, int lineno) except NULL:
cdef PyObject* type = NULL, *value = NULL, *tb = NULL
PyErr_Fetch(&type, &value, &tb)
try:
ctx = Context()
PyErr_Restore(<object>type, <object>value, <object>tb)
Py_INCREF(ctx)
return <PyObject*>ctx
except:
Py_XDECREF(<object>type)
Py_XDECREF(<object>value)
Py_XDECREF(<object>tb)
raise
cdef void GOTREF(PyObject* ctx, PyObject* p_obj, int lineno):
cdef PyObject* type = NULL, *value = NULL, *tb = NULL
if ctx == NULL: return
(<object>ctx).regref(obj, lineno)
PyErr_Fetch(&type, &value, &tb)
try:
if p_obj is NULL:
(<object>ctx).regref(None, lineno, True)
else:
(<object>ctx).regref(<object>p_obj, lineno, False)
PyErr_Restore(<object>type, <object>value, <object>tb)
except:
Py_XDECREF(<object>type)
Py_XDECREF(<object>value)
Py_XDECREF(<object>tb)
raise
cdef public void __Pyx_Refnanny_GIVEREF(void* ctx, object obj, int lineno):
cdef void GIVEREF(PyObject* ctx, PyObject* p_obj, int lineno):
cdef PyObject* type = NULL, *value = NULL, *tb = NULL
if ctx == NULL: return
(<object>ctx).delref(obj, lineno)
PyErr_Fetch(&type, &value, &tb)
try:
if p_obj is NULL:
(<object>ctx).delref(None, lineno, True)
else:
(<object>ctx).delref(<object>p_obj, lineno, False)
PyErr_Restore(<object>type, <object>value, <object>tb)
except:
Py_XDECREF(<object>type)
Py_XDECREF(<object>value)
Py_XDECREF(<object>tb)
raise
cdef public void __Pyx_Refnanny_INCREF(void* ctx, object obj, int lineno):
Py_INCREF(obj)
__Pyx_Refnanny_GOTREF(ctx, obj, lineno)
cdef public void __Pyx_Refnanny_DECREF(void* ctx, object obj, int lineno):
cdef void INCREF(PyObject* ctx, PyObject* obj, int lineno):
if obj is not NULL: Py_INCREF(<object>obj)
GOTREF(ctx, obj, lineno)
cdef void DECREF(PyObject* ctx, PyObject* obj, int lineno):
# GIVEREF raises exception if we hit 0
#
__Pyx_Refnanny_GIVEREF(ctx, obj, lineno)
Py_DECREF(obj)
cdef public int __Pyx_Refnanny_FinishContext(void* ctx) except -1:
# cdef exc.PyObject* type, *value, *tb
## if exc.PyErr_Occurred():
## exc.PyErr_Fetch(&type, &value, &tb)
## Py_XDECREF(<object>type); Py_XDECREF(<object>value); Py_XDECREF(<object>tb)
## print "cleared!"
## print (exc.PyErr_Occurred() == NULL)
obj = <object>ctx
GIVEREF(ctx, obj, lineno)
if obj is not NULL: Py_DECREF(<object>obj)
cdef int FinishContext(PyObject** ctx) except -1:
cdef PyObject* type = NULL, *value = NULL, *tb = NULL
if ctx == NULL: assert False
if ctx[0] == NULL: assert False # XXX What to do here?
cdef object errors = None
PyErr_Fetch(&type, &value, &tb)
try:
obj.end()
errors = (<object>ctx[0]).end()
PyErr_Restore(<object>type, <object>value, <object>tb)
except:
Py_XDECREF(<object>type)
Py_XDECREF(<object>value)
Py_XDECREF(<object>tb)
raise
finally:
Py_DECREF(obj)
Py_XDECREF(<object>ctx[0])
ctx[0] = NULL
if errors:
raise Error(errors)
return 0
cdef extern from "Python.h":
object PyCObject_FromVoidPtr(void*, void (*)(void*))
ctypedef struct RefnannyAPIStruct:
void (*INCREF)(PyObject*, PyObject*, int)
void (*DECREF)(PyObject*, PyObject*, int)
void (*GOTREF)(PyObject*, PyObject*, int)
void (*GIVEREF)(PyObject*, PyObject*, int)
PyObject* (*NewContext)(char*, int) except NULL
int (*FinishContext)(PyObject**) except -1
cdef RefnannyAPIStruct api
api.INCREF = INCREF
api.DECREF = DECREF
api.GOTREF = GOTREF
api.GIVEREF = GIVEREF
api.NewContext = NewContext
api.FinishContext = FinishContext
RefnannyAPI = PyCObject_FromVoidPtr(<void*>&api, NULL)
......@@ -14,6 +14,7 @@ clean:
@rm -f Cython/Compiler/Parsing.{c,so,pyd}
@rm -f Cython/Compiler/Scanning.{c,so,pyd}
@rm -f Cython/Compiler/Visitor.{c,so,pyd}
@rm -f Cython/Runtime/refnanny.{c,so,pyd}
@rm -f Cython/Plex/Scanners.{c,so,pyd}
@(cd Demos; $(MAKE) clean)
......
......@@ -482,9 +482,9 @@ if __name__ == '__main__':
parser.add_option("--cython-only", dest="cython_only",
action="store_true", default=False,
help="only compile pyx to c, do not run C compiler or run the tests")
parser.add_option("--refnanny", dest="with_refnanny",
action="store_true", default=False,
help="also test that Cython-generated code does correct reference counting")
parser.add_option("--no-refnanny", dest="with_refnanny",
action="store_false", default=True,
help="do not regression test reference counting")
parser.add_option("--sys-pyregr", dest="system_pyregr",
action="store_true", default=False,
help="run the regression tests of the CPython installation")
......@@ -531,14 +531,6 @@ if __name__ == '__main__':
from Cython.Compiler import Errors
Errors.LEVEL = 0 # show all warnings
if options.with_refnanny:
import ctypes
ctypes.PyDLL("Cython/Runtime/refnanny.so", mode=ctypes.RTLD_GLOBAL)
sys.path.append("Cython/Runtime")
import refnanny
del sys.path[-1]
CFLAGS.append("-DCYTHON_REFNANNY")
# RUN ALL TESTS!
ROOTDIR = os.path.join(os.getcwd(), os.path.dirname(sys.argv[0]), 'tests')
WORKDIR = os.path.join(os.getcwd(), 'BUILD')
......@@ -546,7 +538,9 @@ if __name__ == '__main__':
UNITTEST_ROOT = os.path.join(os.getcwd(), UNITTEST_MODULE)
if WITH_CYTHON:
if os.path.exists(WORKDIR):
shutil.rmtree(WORKDIR, ignore_errors=True)
for path in os.listdir(WORKDIR):
if path in ("support",): continue
shutil.rmtree(os.path.join(WORKDIR, path), ignore_errors=True)
if not os.path.exists(WORKDIR):
os.makedirs(WORKDIR)
......@@ -558,6 +552,14 @@ if __name__ == '__main__':
sys.stderr.write("Python %s\n" % sys.version)
sys.stderr.write("\n")
if options.with_refnanny:
from pyximport.pyxbuild import pyx_to_dll
libpath = pyx_to_dll(os.path.join("Cython", "Runtime", "refnanny.pyx"),
build_in_temp=True,
pyxbuild_dir=os.path.join(WORKDIR, "support"))
sys.path.insert(0, os.path.split(libpath)[0])
CFLAGS.append("-DCYTHON_REFNANNY")
test_bugs = False
if options.tickets:
for ticket_number in options.tickets:
......@@ -631,4 +633,5 @@ if __name__ == '__main__':
sys.stderr.write(" %s\n" % test)
if options.with_refnanny:
import refnanny
sys.stderr.write("\n".join([repr(x) for x in refnanny.reflog]))
......@@ -41,12 +41,17 @@ except ValueError:
compiled_modules = ["Cython.Plex.Scanners",
"Cython.Compiler.Scanning",
"Cython.Compiler.Parsing",
"Cython.Compiler.Visitor"]
"Cython.Compiler.Visitor",
"Cython.Runtime.refnanny"]
extensions = []
for module in compiled_modules:
source_file = os.path.join(source_root, *module.split('.'))
if os.path.exists(source_file + ".py"):
source_file = source_file + ".py"
else:
source_file = source_file + ".pyx"
print("Compiling module %s ..." % module)
result = compile(source_file + ".py")
result = compile(source_file)
if result.c_file:
extensions.append(
Extension(module, sources = [result.c_file])
......@@ -62,7 +67,7 @@ except ValueError:
setup(
name = 'Cython',
name = 'Cython',
version = version,
url = 'http://www.cython.org',
author = 'Greg Ewing, Robert Bradshaw, Stefan Behnel, Dag Seljebotn, et al.',
......@@ -101,6 +106,7 @@ setup(
packages=[
'Cython',
'Cython.Compiler',
'Cython.Runtime',
'Cython.Distutils',
'Cython.Mac',
'Cython.Unix',
......@@ -109,13 +115,13 @@ setup(
'Cython.Tests',
'Cython.Compiler.Tests',
],
# pyximport
py_modules = ["pyximport/__init__",
"pyximport/pyximport",
"pyximport/pyxbuild",
"pyximport/pyxbuild",
"cython"],
**setup_args
)
"""
>>> range_loop_indices()
** Calculating step **
(9, 9, 8, 1, 2)
>>> from_loop_indices()
** Calculating step **
** Calculating step **
** Calculating step **
** Calculating step **
** Calculating step **
(10, 10, 0)
"""
cdef int get_step():
"""
This should only be called once, when used in range().
"""
print "** Calculating step **"
return 2
def range_loop_indices():
"""
Optimized integer for loops using range() should follow Python behavior,
and leave the index variable with the last value of the range.
"""
cdef int i, j, k, l, m
for i in range(10): pass
for j in range(2,10): pass
for k in range(0,10,get_step()): pass
for l in range(10,0,-1): pass
for m in range(10,0,-2): pass
return i, j, k, l, m
def from_loop_indices():
"""
for-from-loops should follow C behavior, and leave the index variable
incremented one step after the last iteration.
"""
cdef int i, j, k
for i from 0 <= i < 10 by get_step(): pass
for j from 0 <= j < 10: pass
for k from 10 > k > 0: pass
return i, j, k
\ No newline at end of file
......@@ -53,7 +53,7 @@ def test_declare(n):
y = cython.declare(cython.int, n)
if cython.compiled:
cython.declare(xx=cython.int, yy=cython.long)
sizeof(xx)
i = sizeof(xx)
ptr = cython.declare(cython.p_int, cython.address(y))
return y, ptr[0]
......
......@@ -16,6 +16,9 @@ __doc__ = u"""
>>> j(1, [1,2,3,4], 2, 3)
[3]
>>> slice_of_temporary_smoketest()
[3, 2]
"""
def f(obj1, obj2, obj3, obj4):
......@@ -33,3 +36,12 @@ def h(obj1, obj2, obj3, obj4):
def j(obj1, obj2, obj3, obj4):
obj1 = obj2[obj3:obj4]
return obj1
class A(object):
pass
def slice_of_temporary_smoketest():
x = A()
x.a = [1, 2]
x.a[:] = [3,2]
return x.a
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