Commit cc4f7dae authored by Stefan Behnel's avatar Stefan Behnel

use constant flags to move wraparound/boundscheck evaluation into inlined...

use constant flags to move wraparound/boundscheck evaluation into inlined Get/Set/DelItemInt() utility functions
parent 496c0fd9
...@@ -3132,13 +3132,24 @@ class IndexNode(ExprNode): ...@@ -3132,13 +3132,24 @@ class IndexNode(ExprNode):
return "(%s[%s])" % ( return "(%s[%s])" % (
self.base.result(), self.index.result()) self.base.result(), self.index.result())
def extra_index_params(self): def extra_index_params(self, code):
if self.index.type.is_int: if self.index.type.is_int:
if self.original_index_type.signed: if self.original_index_type.signed:
size_adjustment = "" size_adjustment = ""
else: else:
size_adjustment = "+1" size_adjustment = "+1"
return ", sizeof(%s)%s, %s" % (self.original_index_type.declaration_code(""), size_adjustment, self.original_index_type.to_py_function) is_list = self.base.type is list_type
wraparound = (
bool(code.globalstate.directives['wraparound']) and
self.original_index_type.signed and
not (isinstance(self.index.constant_result, (int, long))
and self.index.constant_result >= 0))
boundscheck = bool(code.globalstate.directives['boundscheck'])
return ", sizeof(%s)%s, %s, %d, %d, %d" % (
self.original_index_type.declaration_code(""),
size_adjustment,
self.original_index_type.to_py_function,
is_list, wraparound, boundscheck)
else: else:
return "" return ""
...@@ -3206,7 +3217,7 @@ class IndexNode(ExprNode): ...@@ -3206,7 +3217,7 @@ class IndexNode(ExprNode):
function, function,
self.base.py_result(), self.base.py_result(),
index_code, index_code,
self.extra_index_params(), self.extra_index_params(code),
self.result(), self.result(),
code.error_goto(self.pos))) code.error_goto(self.pos)))
code.put_gotref(self.py_result()) code.put_gotref(self.py_result())
...@@ -3222,18 +3233,12 @@ class IndexNode(ExprNode): ...@@ -3222,18 +3233,12 @@ class IndexNode(ExprNode):
function, function,
self.base.py_result(), self.base.py_result(),
index_code, index_code,
self.extra_index_params(), self.extra_index_params(code),
self.result(), self.result(),
code.error_goto(self.pos))) code.error_goto(self.pos)))
def generate_setitem_code(self, value_code, code): def generate_setitem_code(self, value_code, code):
if self.index.type.is_int: if self.index.type.is_int:
if (self.base.type.is_builtin_type
and self.base.type.name == "list"
and not code.globalstate.directives['wraparound']
and not code.globalstate.directives['boundscheck']):
function = "__Pyx_SetItemListInt_NoCheck"
else:
function = "__Pyx_SetItemInt" function = "__Pyx_SetItemInt"
index_code = self.index.result() index_code = self.index.result()
code.globalstate.use_utility_code( code.globalstate.use_utility_code(
...@@ -3257,7 +3262,7 @@ class IndexNode(ExprNode): ...@@ -3257,7 +3262,7 @@ class IndexNode(ExprNode):
self.base.py_result(), self.base.py_result(),
index_code, index_code,
value_code, value_code,
self.extra_index_params(), self.extra_index_params(code),
code.error_goto(self.pos))) code.error_goto(self.pos)))
def generate_buffer_setitem_code(self, rhs, code, op=""): def generate_buffer_setitem_code(self, rhs, code, op=""):
...@@ -3330,7 +3335,7 @@ class IndexNode(ExprNode): ...@@ -3330,7 +3335,7 @@ class IndexNode(ExprNode):
function, function,
self.base.py_result(), self.base.py_result(),
index_code, index_code,
self.extra_index_params(), self.extra_index_params(code),
code.error_goto(self.pos))) code.error_goto(self.pos)))
self.generate_subexpr_disposal_code(code) self.generate_subexpr_disposal_code(code)
self.free_subexpr_temps(code) self.free_subexpr_temps(code)
......
...@@ -247,22 +247,20 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j ...@@ -247,22 +247,20 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j
} }
{{for type in ['List', 'Tuple']}} {{for type in ['List', 'Tuple']}}
#define __Pyx_GetItemInt_{{type}}(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \ #define __Pyx_GetItemInt_{{type}}(o, i, size, to_py_func, is_list, wraparound, boundscheck) \
__Pyx_GetItemInt_{{type}}_Fast(o, i) : \ (((size) <= sizeof(Py_ssize_t)) ? \
__Pyx_GetItemInt_{{type}}_Fast(o, i, wraparound, boundscheck) : \
__Pyx_GetItemInt_Generic(o, to_py_func(i))) __Pyx_GetItemInt_Generic(o, to_py_func(i)))
static CYTHON_INLINE PyObject *__Pyx_GetItemInt_{{type}}_Fast(PyObject *o, Py_ssize_t i) { static CYTHON_INLINE PyObject *__Pyx_GetItemInt_{{type}}_Fast(PyObject *o, Py_ssize_t i,
int wraparound, int boundscheck) {
#if CYTHON_COMPILING_IN_CPYTHON #if CYTHON_COMPILING_IN_CPYTHON
if (likely((0 <= i) & (i < Py{{type}}_GET_SIZE(o)))) { if (wraparound & unlikely(i < 0)) i += Py{{type}}_GET_SIZE(o);
if ((!boundscheck) || likely((0 <= i) & (i < Py{{type}}_GET_SIZE(o)))) {
PyObject *r = Py{{type}}_GET_ITEM(o, i); PyObject *r = Py{{type}}_GET_ITEM(o, i);
Py_INCREF(r); Py_INCREF(r);
return r; return r;
} }
else if ((-Py{{type}}_GET_SIZE(o) <= i) & (i < 0)) {
PyObject *r = Py{{type}}_GET_ITEM(o, Py{{type}}_GET_SIZE(o) + i);
Py_INCREF(r);
return r;
}
return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i)); return __Pyx_GetItemInt_Generic(o, PyInt_FromSsize_t(i));
#else #else
return PySequence_GetItem(o, i); return PySequence_GetItem(o, i);
...@@ -270,23 +268,25 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_{{type}}_Fast(PyObject *o, Py_ss ...@@ -270,23 +268,25 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_{{type}}_Fast(PyObject *o, Py_ss
} }
{{endfor}} {{endfor}}
#define __Pyx_GetItemInt(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \ #define __Pyx_GetItemInt(o, i, size, to_py_func, is_list, wraparound, boundscheck) \
__Pyx_GetItemInt_Fast(o, i) : \ (((size) <= sizeof(Py_ssize_t)) ? \
__Pyx_GetItemInt_Fast(o, i, is_list, wraparound, boundscheck) : \
__Pyx_GetItemInt_Generic(o, to_py_func(i))) __Pyx_GetItemInt_Generic(o, to_py_func(i)))
static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i) { static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
int is_list, int wraparound, int boundscheck) {
#if CYTHON_COMPILING_IN_CPYTHON #if CYTHON_COMPILING_IN_CPYTHON
if (PyList_CheckExact(o)) { if (is_list || PyList_CheckExact(o)) {
Py_ssize_t n = (likely(i >= 0)) ? i : i + PyList_GET_SIZE(o); Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o);
if (likely((n >= 0) & (n < PyList_GET_SIZE(o)))) { if ((!boundscheck) || (likely((n >= 0) & (n < PyList_GET_SIZE(o))))) {
PyObject *r = PyList_GET_ITEM(o, n); PyObject *r = PyList_GET_ITEM(o, n);
Py_INCREF(r); Py_INCREF(r);
return r; return r;
} }
} }
else if (PyTuple_CheckExact(o)) { else if (PyTuple_CheckExact(o)) {
Py_ssize_t n = (likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o); Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o);
if (likely((n >= 0) & (n < PyTuple_GET_SIZE(o)))) { if ((!boundscheck) || likely((n >= 0) & (n < PyTuple_GET_SIZE(o)))) {
PyObject *r = PyTuple_GET_ITEM(o, n); PyObject *r = PyTuple_GET_ITEM(o, n);
Py_INCREF(r); Py_INCREF(r);
return r; return r;
...@@ -294,7 +294,7 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i) ...@@ -294,7 +294,7 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i)
} else { /* inlined PySequence_GetItem() */ } else { /* inlined PySequence_GetItem() */
PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence; PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence;
if (likely(m && m->sq_item)) { if (likely(m && m->sq_item)) {
if (unlikely(i < 0) && likely(m->sq_length)) { if (wraparound && unlikely(i < 0) && likely(m->sq_length)) {
Py_ssize_t l = m->sq_length(o); Py_ssize_t l = m->sq_length(o);
if (unlikely(l < 0)) return NULL; if (unlikely(l < 0)) return NULL;
i += l; i += l;
...@@ -303,7 +303,7 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i) ...@@ -303,7 +303,7 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i)
} }
} }
#else #else
if (PySequence_Check(o)) { if (is_list || PySequence_Check(o)) {
return PySequence_GetItem(o, i); return PySequence_GetItem(o, i);
} }
#endif #endif
...@@ -312,8 +312,9 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i) ...@@ -312,8 +312,9 @@ static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i)
/////////////// SetItemInt.proto /////////////// /////////////// SetItemInt.proto ///////////////
#define __Pyx_SetItemInt(o, i, v, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \ #define __Pyx_SetItemInt(o, i, v, size, to_py_func, is_list, wraparound, boundscheck) \
__Pyx_SetItemInt_Fast(o, i, v) : \ (((size) <= sizeof(Py_ssize_t)) ? \
__Pyx_SetItemInt_Fast(o, i, v, is_list, wraparound, boundscheck) : \
__Pyx_SetItemInt_Generic(o, to_py_func(i), v)) __Pyx_SetItemInt_Generic(o, to_py_func(i), v))
static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v) { static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyObject *v) {
...@@ -324,11 +325,12 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyOb ...@@ -324,11 +325,12 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Generic(PyObject *o, PyObject *j, PyOb
return r; return r;
} }
static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v) { static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObject *v,
int is_list, int wraparound, int boundscheck) {
#if CYTHON_COMPILING_IN_CPYTHON #if CYTHON_COMPILING_IN_CPYTHON
if (PyList_CheckExact(o)) { if (is_list || PyList_CheckExact(o)) {
Py_ssize_t n = (likely(i >= 0)) ? i : i + PyList_GET_SIZE(o); Py_ssize_t n = (!wraparound) ? i : ((likely(i >= 0)) ? i : i + PyList_GET_SIZE(o));
if (likely((n >= 0) & (n < PyList_GET_SIZE(o)))) { if ((!boundscheck) || likely((n >= 0) & (n < PyList_GET_SIZE(o)))) {
PyObject* old = PyList_GET_ITEM(o, n); PyObject* old = PyList_GET_ITEM(o, n);
Py_INCREF(v); Py_INCREF(v);
PyList_SET_ITEM(o, n, v); PyList_SET_ITEM(o, n, v);
...@@ -338,7 +340,7 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje ...@@ -338,7 +340,7 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje
} else { /* inlined PySequence_SetItem() */ } else { /* inlined PySequence_SetItem() */
PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence; PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence;
if (likely(m && m->sq_ass_item)) { if (likely(m && m->sq_ass_item)) {
if (unlikely(i < 0) && likely(m->sq_length)) { if (wraparound && unlikely(i < 0) && likely(m->sq_length)) {
Py_ssize_t l = m->sq_length(o); Py_ssize_t l = m->sq_length(o);
if (unlikely(l < 0)) return -1; if (unlikely(l < 0)) return -1;
i += l; i += l;
...@@ -348,9 +350,9 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje ...@@ -348,9 +350,9 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje
} }
#else #else
#if CYTHON_COMPILING_IN_PYPY #if CYTHON_COMPILING_IN_PYPY
if (PySequence_Check(o) && !PyDict_Check(o)) { if (is_list || (PySequence_Check(o) && !PyDict_Check(o))) {
#else #else
if (PySequence_Check(o)) { if (is_list || PySequence_Check(o)) {
#endif #endif
return PySequence_SetItem(o, i, v); return PySequence_SetItem(o, i, v);
} }
...@@ -359,22 +361,11 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje ...@@ -359,22 +361,11 @@ static CYTHON_INLINE int __Pyx_SetItemInt_Fast(PyObject *o, Py_ssize_t i, PyObje
} }
#define __Pyx_SetItemListInt_NoCheck(o, i, v, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \
__Pyx_SetItemIntList_NoCheck(o, i, v) : \
__Pyx_SetItemInt_Generic(o, to_py_func(i), v))
static CYTHON_INLINE int __Pyx_SetItemIntList_NoCheck(PyObject *o, Py_ssize_t n, PyObject *v) {
PyObject* old = PyList_GET_ITEM(o, n);
Py_INCREF(v);
PyList_SET_ITEM(o, n, v);
Py_DECREF(old);
return 1;
}
/////////////// DelItemInt.proto /////////////// /////////////// DelItemInt.proto ///////////////
#define __Pyx_DelItemInt(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \ #define __Pyx_DelItemInt(o, i, size, to_py_func, is_list, wraparound, boundscheck) \
__Pyx_DelItemInt_Fast(o, i) : \ (((size) <= sizeof(Py_ssize_t)) ? \
__Pyx_DelItemInt_Fast(o, i, is_list, wraparound, boundscheck) : \
__Pyx_DelItem_Generic(o, to_py_func(i))) __Pyx_DelItem_Generic(o, to_py_func(i)))
static CYTHON_INLINE int __Pyx_DelItem_Generic(PyObject *o, PyObject *j) { static CYTHON_INLINE int __Pyx_DelItem_Generic(PyObject *o, PyObject *j) {
...@@ -385,16 +376,17 @@ static CYTHON_INLINE int __Pyx_DelItem_Generic(PyObject *o, PyObject *j) { ...@@ -385,16 +376,17 @@ static CYTHON_INLINE int __Pyx_DelItem_Generic(PyObject *o, PyObject *j) {
return r; return r;
} }
static CYTHON_INLINE int __Pyx_DelItemInt_Fast(PyObject *o, Py_ssize_t i) { static CYTHON_INLINE int __Pyx_DelItemInt_Fast(PyObject *o, Py_ssize_t i,
int is_list, int wraparound, int boundscheck) {
#if CYTHON_COMPILING_IN_PYPY #if CYTHON_COMPILING_IN_PYPY
if (PySequence_Check(o)) { if (is_list || PySequence_Check(o)) {
return PySequence_DelItem(o, i); return PySequence_DelItem(o, i);
} }
#else #else
/* inlined PySequence_DelItem() */ /* inlined PySequence_DelItem() */
PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence; PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence;
if (likely(m && m->sq_ass_item)) { if (likely(m && m->sq_ass_item)) {
if (unlikely(i < 0) && likely(m->sq_length)) { if (wraparound && unlikely(i < 0) && likely(m->sq_length)) {
Py_ssize_t l = m->sq_length(o); Py_ssize_t l = m->sq_length(o);
if (unlikely(l < 0)) return -1; if (unlikely(l < 0)) return -1;
i += l; i += l;
......
...@@ -229,29 +229,35 @@ static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int eq ...@@ -229,29 +229,35 @@ static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int eq
//////////////////// GetItemIntUnicode.proto //////////////////// //////////////////// GetItemIntUnicode.proto ////////////////////
#define __Pyx_GetItemInt_Unicode(o, i, size, to_py_func) (((size) <= sizeof(Py_ssize_t)) ? \ #define __Pyx_GetItemInt_Unicode(o, i, size, to_py_func, is_list, wraparound, boundscheck) \
__Pyx_GetItemInt_Unicode_Fast(o, i) : \ (((size) <= sizeof(Py_ssize_t)) ? \
__Pyx_GetItemInt_Unicode_Fast(o, i, wraparound, boundscheck) : \
__Pyx_GetItemInt_Unicode_Generic(o, to_py_func(i))) __Pyx_GetItemInt_Unicode_Generic(o, to_py_func(i)))
static CYTHON_INLINE Py_UCS4 __Pyx_GetItemInt_Unicode_Fast(PyObject* ustring, Py_ssize_t i); static CYTHON_INLINE Py_UCS4 __Pyx_GetItemInt_Unicode_Fast(PyObject* ustring, Py_ssize_t i,
int wraparound, int boundscheck);
static CYTHON_INLINE Py_UCS4 __Pyx_GetItemInt_Unicode_Generic(PyObject* ustring, PyObject* j); static CYTHON_INLINE Py_UCS4 __Pyx_GetItemInt_Unicode_Generic(PyObject* ustring, PyObject* j);
//////////////////// GetItemIntUnicode //////////////////// //////////////////// GetItemIntUnicode ////////////////////
static CYTHON_INLINE Py_UCS4 __Pyx_GetItemInt_Unicode_Fast(PyObject* ustring, Py_ssize_t i) { static CYTHON_INLINE Py_UCS4 __Pyx_GetItemInt_Unicode_Fast(PyObject* ustring, Py_ssize_t i,
int wraparound, int boundscheck) {
Py_ssize_t length; Py_ssize_t length;
#if CYTHON_PEP393_ENABLED #if CYTHON_PEP393_ENABLED
if (unlikely(__Pyx_PyUnicode_READY(ustring) < 0)) return (Py_UCS4)-1; if (unlikely(__Pyx_PyUnicode_READY(ustring) < 0)) return (Py_UCS4)-1;
#endif #endif
if (wraparound | boundscheck) {
length = __Pyx_PyUnicode_GET_LENGTH(ustring); length = __Pyx_PyUnicode_GET_LENGTH(ustring);
if (likely((0 <= i) & (i < length))) { if (wraparound & unlikely(i < 0)) i += length;
if ((!boundscheck) || likely((0 <= i) & (i < length))) {
return __Pyx_PyUnicode_READ_CHAR(ustring, i); return __Pyx_PyUnicode_READ_CHAR(ustring, i);
} else if ((-length <= i) & (i < 0)) {
return __Pyx_PyUnicode_READ_CHAR(ustring, i + length);
} else { } else {
PyErr_SetString(PyExc_IndexError, "string index out of range"); PyErr_SetString(PyExc_IndexError, "string index out of range");
return (Py_UCS4)-1; return (Py_UCS4)-1;
} }
} else {
return __Pyx_PyUnicode_READ_CHAR(ustring, i);
}
} }
static CYTHON_INLINE Py_UCS4 __Pyx_GetItemInt_Unicode_Generic(PyObject* ustring, PyObject* j) { static CYTHON_INLINE Py_UCS4 __Pyx_GetItemInt_Unicode_Generic(PyObject* ustring, PyObject* j) {
......
...@@ -119,11 +119,35 @@ def test_long_long(): ...@@ -119,11 +119,35 @@ def test_long_long():
assert len(D) == 0 assert len(D) == 0
@cython.boundscheck(False) @cython.boundscheck(False)
def test_boundscheck(list L, tuple t, object o, unsigned long ix): def test_boundscheck_unsigned(list L, tuple t, object o, unsigned long ix):
""" """
>>> test_boundscheck([1, 2, 4], (1, 2, 4), [1, 2, 4], 2) >>> test_boundscheck_unsigned([1, 2, 4], (1, 2, 4), [1, 2, 4], 2)
(4, 4, 4) (4, 4, 4)
>>> test_boundscheck([1, 2, 4], (1, 2, 4), "", 2) >>> test_boundscheck_unsigned([1, 2, 4], (1, 2, 4), "", 2)
Traceback (most recent call last):
...
IndexError: string index out of range
"""
return L[ix], t[ix], o[ix]
@cython.boundscheck(False)
def test_boundscheck_signed(list L, tuple t, object o, long ix):
"""
>>> test_boundscheck_signed([1, 2, 4], (1, 2, 4), [1, 2, 4], 2)
(4, 4, 4)
>>> test_boundscheck_signed([1, 2, 4], (1, 2, 4), "", 2)
Traceback (most recent call last):
...
IndexError: string index out of range
"""
return L[ix], t[ix], o[ix]
@cython.wraparound(False)
def test_wraparound_signed(list L, tuple t, object o, long ix):
"""
>>> test_wraparound_signed([1, 2, 4], (1, 2, 4), [1, 2, 4], 2)
(4, 4, 4)
>>> test_wraparound_signed([1, 2, 4], (1, 2, 4), "", 2)
Traceback (most recent call last): Traceback (most recent call last):
... ...
IndexError: string index out of range IndexError: string index out of range
......
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