Commit c2e502d9 authored by Stefan Behnel's avatar Stefan Behnel

optimise tp_new() for module-internally defined types by calling the tp_new slot function directly

parent f7a50b7d
...@@ -1033,11 +1033,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1033,11 +1033,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
else: else:
unused_marker = 'CYTHON_UNUSED ' unused_marker = 'CYTHON_UNUSED '
need_self_cast = type.vtabslot_cname or have_entries or cpp_class_attrs decls = code.globalstate['decls']
decls.putln("static PyObject *%s(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/" %
slot_func)
code.putln("") code.putln("")
code.putln( code.putln(
"static PyObject *%s(PyTypeObject *t, %sPyObject *a, %sPyObject *k) {" "static PyObject *%s(PyTypeObject *t, %sPyObject *a, %sPyObject *k) {"
% (scope.mangle_internal("tp_new"), unused_marker, unused_marker)) % (slot_func, unused_marker, unused_marker))
need_self_cast = type.vtabslot_cname or have_entries or cpp_class_attrs
if need_self_cast: if need_self_cast:
code.putln( code.putln(
"%s;" "%s;"
......
...@@ -2142,13 +2142,28 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform): ...@@ -2142,13 +2142,28 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform):
Pyx_tp_new_func_type = PyrexTypes.CFuncType( Pyx_tp_new_func_type = PyrexTypes.CFuncType(
PyrexTypes.py_object_type, [ PyrexTypes.py_object_type, [
PyrexTypes.CFuncTypeArg("type", Builtin.type_type, None), PyrexTypes.CFuncTypeArg("type", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("args", Builtin.tuple_type, None), PyrexTypes.CFuncTypeArg("args", Builtin.tuple_type, None),
]) ])
Pyx_tp_new_kwargs_func_type = PyrexTypes.CFuncType( Pyx_tp_new_kwargs_func_type = PyrexTypes.CFuncType(
PyrexTypes.py_object_type, [ PyrexTypes.py_object_type, [
PyrexTypes.CFuncTypeArg("type", Builtin.type_type, None), PyrexTypes.CFuncTypeArg("type", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("args", Builtin.tuple_type, None),
PyrexTypes.CFuncTypeArg("kwargs", Builtin.dict_type, None),
])
Pyx_call_tp_new_func_type = PyrexTypes.CFuncType(
PyrexTypes.py_object_type, [
PyrexTypes.CFuncTypeArg("tpnew_func", PyrexTypes.c_void_ptr_type, None),
PyrexTypes.CFuncTypeArg("type", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("args", Builtin.tuple_type, None),
])
Pyx_call_tp_new_kwargs_func_type = PyrexTypes.CFuncType(
PyrexTypes.py_object_type, [
PyrexTypes.CFuncTypeArg("tpnew_func", PyrexTypes.c_void_ptr_type, None),
PyrexTypes.CFuncTypeArg("type", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("args", Builtin.tuple_type, None), PyrexTypes.CFuncTypeArg("args", Builtin.tuple_type, None),
PyrexTypes.CFuncTypeArg("kwargs", Builtin.dict_type, None), PyrexTypes.CFuncTypeArg("kwargs", Builtin.dict_type, None),
]) ])
...@@ -2175,20 +2190,41 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform): ...@@ -2175,20 +2190,41 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform):
# different types - may or may not lead to an error at runtime # different types - may or may not lead to an error at runtime
return node return node
# FIXME: we could potentially look up the actual tp_new C args_tuple = ExprNodes.TupleNode(node.pos, args=args[1:])
# method of the extension type and call that instead of the args_tuple = args_tuple.analyse_types(
# generic slot. That would also allow us to pass parameters self.current_env(), skip_children=True)
# efficiently.
if not type_arg.type_entry: if type_arg.type_entry:
ext_type = type_arg.type_entry.type
if ext_type.is_extension_type and not ext_type.is_external:
utility_code = UtilityCode.load_cached(
'call_tp_new', 'ObjectHandling.c')
slot_func_cname = ext_type.scope.mangle_internal("tp_new")
slot_func = ExprNodes.RawCNameExprNode(
node.pos, cname=slot_func_cname,
type=PyrexTypes.c_void_ptr_type)
if kwargs:
return ExprNodes.PythonCapiCallNode(
node.pos, "__Pyx_call_tp_new_kwargs",
self.Pyx_call_tp_new_kwargs_func_type,
args=[slot_func, type_arg, args_tuple, kwargs],
utility_code=utility_code,
is_temp=node.is_temp
)
else:
return ExprNodes.PythonCapiCallNode(
node.pos, "__Pyx_call_tp_new",
self.Pyx_call_tp_new_func_type,
args=[slot_func, type_arg, args_tuple],
utility_code=utility_code,
is_temp=node.is_temp
)
else:
# arbitrary variable, needs a None check for safety # arbitrary variable, needs a None check for safety
type_arg = type_arg.as_none_safe_node( type_arg = type_arg.as_none_safe_node(
"object.__new__(X): X is not a type object (NoneType)") "object.__new__(X): X is not a type object (NoneType)")
args_tuple = ExprNodes.TupleNode(node.pos, args=args[1:])
args_tuple = args_tuple.analyse_types(
self.current_env(), skip_children=True)
utility_code = UtilityCode.load_cached('tp_new', 'ObjectHandling.c') utility_code = UtilityCode.load_cached('tp_new', 'ObjectHandling.c')
if kwargs: if kwargs:
return ExprNodes.PythonCapiCallNode( return ExprNodes.PythonCapiCallNode(
......
...@@ -659,3 +659,9 @@ static CYTHON_INLINE PyObject* __Pyx_tp_new_kwargs(PyObject* type_obj, PyObject* ...@@ -659,3 +659,9 @@ static CYTHON_INLINE PyObject* __Pyx_tp_new_kwargs(PyObject* type_obj, PyObject*
return (PyObject*) (((PyTypeObject*)(type_obj))->tp_new( return (PyObject*) (((PyTypeObject*)(type_obj))->tp_new(
(PyTypeObject*)(type_obj), args, kwargs)); (PyTypeObject*)(type_obj), args, kwargs));
} }
/////////////// call_tp_new.proto ///////////////
#define __Pyx_call_tp_new(tp_new_func, type_obj, args) __Pyx_call_tp_new_kwargs(tp_new_func, type_obj, args, NULL)
#define __Pyx_call_tp_new_kwargs(tp_new_func, type_obj, args, kwargs) tp_new_func((PyTypeObject*)type_obj, args, kwargs)
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