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