Commit 72698b0b authored by Stefan Behnel's avatar Stefan Behnel

optimise object.append() only when return value is not used and adapt signature accordingly

parent b1ffafb1
...@@ -2357,24 +2357,26 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform): ...@@ -2357,24 +2357,26 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform):
### methods of builtin types ### methods of builtin types
PyObject_Append_func_type = PyrexTypes.CFuncType( PyObject_Append_func_type = PyrexTypes.CFuncType(
PyrexTypes.py_object_type, [ PyrexTypes.c_returncode_type, [
PyrexTypes.CFuncTypeArg("list", PyrexTypes.py_object_type, None), PyrexTypes.CFuncTypeArg("list", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("item", PyrexTypes.py_object_type, None), PyrexTypes.CFuncTypeArg("item", PyrexTypes.py_object_type, None),
]) ],
exception_value="-1")
def _handle_simple_method_object_append(self, node, function, args, is_unbound_method): def _handle_simple_method_object_append(self, node, function, args, is_unbound_method):
"""Optimistic optimisation as X.append() is almost always """Optimistic optimisation as X.append() is almost always
referring to a list. referring to a list.
""" """
if len(args) != 2: if len(args) != 2 or node.result_is_used:
return node return node
return ExprNodes.PythonCapiCallNode( return ExprNodes.PythonCapiCallNode(
node.pos, "__Pyx_PyObject_Append", self.PyObject_Append_func_type, node.pos, "__Pyx_PyObject_Append", self.PyObject_Append_func_type,
args = args, args=args,
may_return_none = True, may_return_none=False,
is_temp = node.is_temp, is_temp=node.is_temp,
utility_code = load_c_utility('append') result_is_used=False,
utility_code=load_c_utility('append')
) )
PyObject_Pop_func_type = PyrexTypes.CFuncType( PyObject_Pop_func_type = PyrexTypes.CFuncType(
......
...@@ -8,20 +8,22 @@ ...@@ -8,20 +8,22 @@
/////////////// append.proto /////////////// /////////////// append.proto ///////////////
static CYTHON_INLINE PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x); /*proto*/ static CYTHON_INLINE int __Pyx_PyObject_Append(PyObject* L, PyObject* x); /*proto*/
/////////////// append /////////////// /////////////// append ///////////////
//@requires: ListAppend //@requires: ListAppend
//@requires: ObjectHandling.c::PyObjectCallMethod //@requires: ObjectHandling.c::PyObjectCallMethod
static CYTHON_INLINE PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x) { static CYTHON_INLINE int __Pyx_PyObject_Append(PyObject* L, PyObject* x) {
if (likely(PyList_CheckExact(L))) { if (likely(PyList_CheckExact(L))) {
if (unlikely(__Pyx_PyList_Append(L, x) < 0)) return NULL; if (unlikely(__Pyx_PyList_Append(L, x) < 0)) return -1;
Py_INCREF(Py_None);
return Py_None; /* this is just to have an accurate signature */
} else { } else {
return __Pyx_PyObject_CallMethod1(L, PYIDENT("append"), x); PyObject* retval = __Pyx_PyObject_CallMethod1(L, PYIDENT("append"), x);
if (unlikely(!retval))
return -1;
Py_DECREF(retval);
} }
return 0;
} }
/////////////// ListAppend.proto /////////////// /////////////// ListAppend.proto ///////////////
......
class A: class A:
def append(self, x): def append(self, x):
print u"appending" print u"appending", x
return x return x
class B(list): class B(list):
...@@ -8,6 +8,7 @@ class B(list): ...@@ -8,6 +8,7 @@ class B(list):
for arg in args: for arg in args:
list.append(self, arg) list.append(self, arg)
def test_append(L): def test_append(L):
""" """
>>> test_append([]) >>> test_append([])
...@@ -17,11 +18,11 @@ def test_append(L): ...@@ -17,11 +18,11 @@ def test_append(L):
got error got error
[1, 2, (3, 4)] [1, 2, (3, 4)]
>>> _ = test_append(A()) >>> _ = test_append(A())
appending appending 1
1 1
appending appending 2
2 2
appending appending (3, 4)
(3, 4) (3, 4)
got error got error
>>> test_append(B()) >>> test_append(B())
...@@ -39,3 +40,26 @@ def test_append(L): ...@@ -39,3 +40,26 @@ def test_append(L):
except TypeError: except TypeError:
print u"got error" print u"got error"
return L return L
def append_unused_retval(L):
"""
>>> append_unused_retval([])
got error
[1, 2, (3, 4)]
>>> _ = append_unused_retval(A())
appending 1
appending 2
appending (3, 4)
got error
>>> append_unused_retval(B())
[1, 2, (3, 4), 5, 6]
"""
L.append(1)
L.append(2)
L.append((3,4))
try:
L.append(5,6)
except TypeError:
print u"got error"
return L
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