Commit e13fa642 authored by Stefan Behnel's avatar Stefan Behnel

avoid exit overhead in inlined generator expressions by directly returning the...

avoid exit overhead in inlined generator expressions by directly returning the result instead of raising a StopIteration with value
parent 13ace3a9
...@@ -7328,6 +7328,11 @@ class InlinedGeneratorExpressionNode(ExprNode): ...@@ -7328,6 +7328,11 @@ class InlinedGeneratorExpressionNode(ExprNode):
orig_func = None orig_func = None
type = py_object_type type = py_object_type
def __init__(self, pos, gen, **kwargs):
gen.def_node.gbody.is_inlined = True
kwargs['gen'] = gen
super(InlinedGeneratorExpressionNode, self).__init__(pos, **kwargs)
def may_be_none(self): def may_be_none(self):
return self.orig_func not in ('any', 'all') return self.orig_func not in ('any', 'all')
...@@ -7340,8 +7345,7 @@ class InlinedGeneratorExpressionNode(ExprNode): ...@@ -7340,8 +7345,7 @@ class InlinedGeneratorExpressionNode(ExprNode):
return self return self
def generate_result_code(self, code): def generate_result_code(self, code):
code.globalstate.use_utility_code(UtilityCode.load_cached("GetGenexpResult", "Coroutine.c")) code.putln("%s = __Pyx_Generator_Next(%s); %s" % (
code.putln("%s = __Pyx_Generator_GetGenexpResult(%s); %s" % (
self.result(), self.gen.result(), self.result(), self.gen.result(),
code.error_goto_if_null(self.result(), self.pos))) code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.result()) code.put_gotref(self.result())
......
...@@ -3995,6 +3995,7 @@ class GeneratorBodyDefNode(DefNode): ...@@ -3995,6 +3995,7 @@ class GeneratorBodyDefNode(DefNode):
# #
is_generator_body = True is_generator_body = True
is_inlined = False
def __init__(self, pos=None, name=None, body=None): def __init__(self, pos=None, name=None, body=None):
super(GeneratorBodyDefNode, self).__init__( super(GeneratorBodyDefNode, self).__init__(
...@@ -4090,12 +4091,15 @@ class GeneratorBodyDefNode(DefNode): ...@@ -4090,12 +4091,15 @@ class GeneratorBodyDefNode(DefNode):
# ----- Non-error return cleanup # ----- Non-error return cleanup
code.put_label(code.return_label) code.put_label(code.return_label)
code.put_xdecref(Naming.retval_cname, py_object_type) if self.is_inlined:
code.put_xgiveref(Naming.retval_cname)
else:
code.put_xdecref_clear(Naming.retval_cname, py_object_type)
code.putln('%s->resume_label = -1;' % Naming.generator_cname) code.putln('%s->resume_label = -1;' % Naming.generator_cname)
# clean up as early as possible to help breaking any reference cycles # clean up as early as possible to help breaking any reference cycles
code.putln('__Pyx_Coroutine_clear((PyObject*)%s);' % Naming.generator_cname) code.putln('__Pyx_Coroutine_clear((PyObject*)%s);' % Naming.generator_cname)
code.put_finish_refcount_context() code.put_finish_refcount_context()
code.putln('return NULL;') code.putln("return %s;" % Naming.retval_cname)
code.putln("}") code.putln("}")
# ----- Go back and insert temp variable declarations # ----- Go back and insert temp variable declarations
......
...@@ -1545,8 +1545,7 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform): ...@@ -1545,8 +1545,7 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform):
condition=condition, condition=condition,
body=Nodes.ReturnStatNode( body=Nodes.ReturnStatNode(
node.pos, node.pos,
value=ExprNodes.BoolNode(yield_expression.pos, value=is_any, constant_result=is_any), value=ExprNodes.BoolNode(yield_expression.pos, value=is_any, constant_result=is_any))
in_generator=True)
)] )]
) )
loop = loop_node loop = loop_node
...@@ -1560,8 +1559,7 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform): ...@@ -1560,8 +1559,7 @@ class EarlyReplaceBuiltinCalls(Visitor.EnvTransform):
loop = next_loop loop = next_loop
loop_node.else_clause = Nodes.ReturnStatNode( loop_node.else_clause = Nodes.ReturnStatNode(
node.pos, node.pos,
value=ExprNodes.BoolNode(yield_expression.pos, value=not is_any, constant_result=not is_any), value=ExprNodes.BoolNode(yield_expression.pos, value=not is_any, constant_result=not is_any))
in_generator=True)
Visitor.recursively_replace_node(loop_node, yield_stat_node, test_node) Visitor.recursively_replace_node(loop_node, yield_stat_node, test_node)
......
...@@ -246,28 +246,6 @@ static void __Pyx_Generator_Replace_StopIteration(void) { ...@@ -246,28 +246,6 @@ static void __Pyx_Generator_Replace_StopIteration(void) {
} }
//////////////////// GetGenexpResult.proto ////////////////////
static CYTHON_INLINE PyObject* __Pyx_Generator_GetGenexpResult(PyObject* gen); /*proto*/
//////////////////// GetGenexpResult ////////////////////
//@requires: Generator
static CYTHON_INLINE PyObject* __Pyx_Generator_GetGenexpResult(PyObject* gen) {
PyObject *result;
result = __Pyx_Generator_Next(gen);
if (unlikely(result)) {
PyErr_Format(PyExc_RuntimeError, "Generator expression returned with non-StopIteration result '%.100s'",
result ? Py_TYPE(result)->tp_name : "NULL");
Py_XDECREF(result);
return NULL;
}
if (unlikely(__Pyx_PyGen_FetchStopIterationValue(&result) < 0))
return NULL;
return result;
}
//////////////////// CoroutineBase.proto //////////////////// //////////////////// CoroutineBase.proto ////////////////////
typedef PyObject *(*__pyx_coroutine_body_t)(PyObject *, PyObject *); typedef PyObject *(*__pyx_coroutine_body_t)(PyObject *, PyObject *);
...@@ -323,6 +301,7 @@ static PyTypeObject *__pyx_GeneratorType = 0; ...@@ -323,6 +301,7 @@ static PyTypeObject *__pyx_GeneratorType = 0;
#define __Pyx_Generator_New(body, closure, name, qualname) \ #define __Pyx_Generator_New(body, closure, name, qualname) \
__Pyx__Coroutine_New(__pyx_GeneratorType, body, closure, name, qualname) __Pyx__Coroutine_New(__pyx_GeneratorType, body, closure, name, qualname)
static PyObject *__Pyx_Generator_Next(PyObject *self);
static int __pyx_Generator_init(void); /*proto*/ static int __pyx_Generator_init(void); /*proto*/
...@@ -337,7 +316,6 @@ static int __pyx_Generator_init(void); /*proto*/ ...@@ -337,7 +316,6 @@ static int __pyx_Generator_init(void); /*proto*/
#include <structmember.h> #include <structmember.h>
#include <frameobject.h> #include <frameobject.h>
static PyObject *__Pyx_Generator_Next(PyObject *self);
static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value); static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value);
static PyObject *__Pyx_Coroutine_Close(PyObject *self); static PyObject *__Pyx_Coroutine_Close(PyObject *self);
static PyObject *__Pyx_Coroutine_Throw(PyObject *gen, PyObject *args); static PyObject *__Pyx_Coroutine_Throw(PyObject *gen, PyObject *args);
......
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