summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2019-03-30 22:12:53 +0100
committerStefan Behnel <stefan_ml@behnel.de>2019-03-30 22:13:15 +0100
commit77098e74eb98f98704c4e4e661d4917ee42626bc (patch)
treeb54cc601fdb9804886c48af9bb971668102d281d
parent33707f2ee8f669a8d1e185707d900357525759ae (diff)
downloadcython-less_tp_new.tar.gz
Avoid generating empty tp_new() functions if we can copy the function pointer from the parent at init time.less_tp_new
See GH-1555.
-rw-r--r--Cython/Compiler/TypeSlots.py47
1 files changed, 38 insertions, 9 deletions
diff --git a/Cython/Compiler/TypeSlots.py b/Cython/Compiler/TypeSlots.py
index aeb773465..f7ea0e1e9 100644
--- a/Cython/Compiler/TypeSlots.py
+++ b/Cython/Compiler/TypeSlots.py
@@ -366,24 +366,53 @@ class ConstructorSlot(InternalMethodSlot):
InternalMethodSlot.__init__(self, slot_name, **kargs)
self.method = method
- def slot_code(self, scope):
- entry = scope.lookup_here(self.method) if self.method else None
+ def _needs_own(self, scope):
if (scope.parent_type.base_type
and not scope.has_pyobject_attrs
and not scope.has_memoryview_attrs
and not scope.has_cpp_class_attrs
- and not (self.slot_name == 'tp_new' and scope.parent_type.vtabslot_cname)
- and not (entry and entry.is_special)):
+ and not (self.slot_name == 'tp_new' and scope.parent_type.vtabslot_cname)):
+ entry = scope.lookup_here(self.method) if self.method else None
+ if not (entry and entry.is_special):
+ return False
+ # Unless we can safely delegate to the parent, all types need a tp_new().
+ return True
+
+ def _parent_slot_function(self, scope):
+ parent_type_scope = scope.parent_type.base_type.scope
+ if scope.parent_scope is parent_type_scope.parent_scope:
+ entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
+ if entry.visibility != 'extern':
+ return self.slot_code(parent_type_scope)
+ return None
+
+ def slot_code(self, scope):
+ if not self._needs_own(scope):
# if the type does not have object attributes, it can
# delegate GC methods to its parent - iff the parent
# functions are defined in the same module
- parent_type_scope = scope.parent_type.base_type.scope
- if scope.parent_scope is parent_type_scope.parent_scope:
- entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
- if entry.visibility != 'extern':
- return self.slot_code(parent_type_scope)
+ slot_code = self._parent_slot_function(scope)
+ return slot_code or '0'
return InternalMethodSlot.slot_code(self, scope)
+ def generate_dynamic_init_code(self, scope, code):
+ if self.slot_code(scope) != '0':
+ return
+ # If we don't have our own slot function and don't know the
+ # parent function statically, copy it dynamically.
+ base_type = scope.parent_type.base_type
+ if base_type.is_extension_type and base_type.typeobj_cname:
+ src = '%s.%s' % (base_type.typeobj_cname, self.slot_name)
+ elif base_type.typeptr_cname:
+ src = '%s->%s' % (base_type.typeptr_cname, self.slot_name)
+ else:
+ return
+
+ code.putln("%s.%s = %s;" % (
+ scope.parent_type.typeobj_cname,
+ self.slot_name,
+ src))
+
class SyntheticSlot(InternalMethodSlot):
# Type slot descriptor for a synthesized method which