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):
else:
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(
"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:
code.putln(
"%s;"
......
......@@ -2142,17 +2142,32 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform):
Pyx_tp_new_func_type = PyrexTypes.CFuncType(
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),
])
Pyx_tp_new_kwargs_func_type = PyrexTypes.CFuncType(
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("kwargs", Builtin.dict_type, None),
])
def _handle_any_slot__new__(self, node, args, is_unbound_method, kwargs=None):
"""Replace 'exttype.__new__(exttype, ...)' by a call to exttype->tp_new()
"""
......@@ -2175,20 +2190,41 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform):
# different types - may or may not lead to an error at runtime
return node
# FIXME: we could potentially look up the actual tp_new C
# method of the extension type and call that instead of the
# generic slot. That would also allow us to pass parameters
# efficiently.
args_tuple = ExprNodes.TupleNode(node.pos, args=args[1:])
args_tuple = args_tuple.analyse_types(
self.current_env(), skip_children=True)
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
type_arg = type_arg.as_none_safe_node(
"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')
if kwargs:
return ExprNodes.PythonCapiCallNode(
......
......@@ -659,3 +659,9 @@ static CYTHON_INLINE PyObject* __Pyx_tp_new_kwargs(PyObject* type_obj, PyObject*
return (PyObject*) (((PyTypeObject*)(type_obj))->tp_new(
(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