Optimize tp_new and tp_dealloc
authorRobert Bradshaw <robertwb@math.washington.edu>
Thu, 17 Jan 2008 13:09:49 +0000 (05:09 -0800)
committerRobert Bradshaw <robertwb@math.washington.edu>
Thu, 17 Jan 2008 13:09:49 +0000 (05:09 -0800)
Cython/Compiler/ModuleNode.py
Cython/Compiler/TypeSlots.py

index d53b500a421015fe1f733228c7e09b2fa49da0c0..680304af98e193f6ca18dcc496daa9ec896560f3 100644 (file)
@@ -608,6 +608,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 type.declaration_code("")))
     
     def generate_new_function(self, scope, code):
+        tp_slot = TypeSlots.ConstructorSlot("tp_new", '__new__')
+        slot_func = scope.mangle_internal("tp_new")
+        if tp_slot.slot_code(scope) != slot_func:
+            return # never used
         type = scope.parent_type
         base_type = type.base_type
         py_attrs = []
@@ -624,9 +628,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 "%s;"
                     % scope.parent_type.declaration_code("p"))
         if base_type:
+            entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
+            if scope.parent_scope is base_type.scope.parent_scope and entry.visibility != 'extern':
+                tp_new = TypeSlots.InternalMethodSlot("tp_new").slot_code(base_type.scope)
+            else:
+                tp_new = "%s->tp_new" % base_type.typeptr_cname
             code.putln(
-                "PyObject *o = %s->tp_new(t, a, k);" %
-                    base_type.typeptr_cname)
+                "PyObject *o = %s(t, a, k);" % tp_new)
         else:
             code.putln(
                 "PyObject *o = (*t->tp_alloc)(t, 0);")
@@ -662,7 +670,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
             "}")
     
     def generate_dealloc_function(self, scope, code):
+        tp_slot = TypeSlots.ConstructorSlot("tp_dealloc", '__dealloc__')
+        slot_func = scope.mangle_internal("tp_dealloc")
         base_type = scope.parent_type.base_type
+        if tp_slot.slot_code(scope) != slot_func:
+            return # never used
         code.putln("")
         code.putln(
             "static void %s(PyObject *o) {"
@@ -679,12 +691,16 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         for entry in py_attrs:
             code.put_xdecref("p->%s" % entry.cname, entry.type)
         if base_type:
+            entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
+            if scope.parent_scope is base_type.scope.parent_scope and entry.visibility != 'extern':
+                tp_dealloc = TypeSlots.InternalMethodSlot("tp_dealloc").slot_code(base_type.scope)
+            else:
+                tp_dealloc = "%s->tp_dealloc" % base_type.typeptr_cname
             code.putln(
-                "%s->tp_dealloc(o);" %
-                    base_type.typeptr_cname)
+                    "%s(o);" % tp_dealloc)
         else:
             code.putln(
-                "(*o->ob_type->tp_free)(o);")
+                    "(*o->ob_type->tp_free)(o);")
         code.putln(
             "}")
     
@@ -732,7 +748,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         if base_type:
             # want to call it explicitly if possible so inlining can be performed
             parent_slot = tp_slot.slot_code(base_type.scope)
-            if scope.parent_scope is base_type.scope.parent_scope and parent_slot != '0':
+            entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
+            if scope.parent_scope is base_type.scope.parent_scope and parent_slot != '0' and entry.visibility != 'extern':
                 code.putln("e = %s(o, v, a); if (e) return e;" % parent_slot)
             else:
                 code.putln("if (%s->tp_traverse) {" % base_type.typeptr_cname)
@@ -775,7 +792,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         if base_type:
             # want to call it explicitly if possible so inlining can be performed
             parent_slot = tp_slot.slot_code(base_type.scope)
-            if scope.parent_scope is base_type.scope.parent_scope and parent_slot != '0':
+            entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
+            if scope.parent_scope is base_type.scope.parent_scope and parent_slot != '0' and entry.visibility != 'extern':
                 code.putln("%s(o);" % parent_slot)
             else:
                 code.putln("if (%s->tp_clear) {" % base_type.typeptr_cname)
index f68daa0188cf12c07377a63d1e4a1cc49f5a4ae9..de94ab940edf6b099c792427e3fd991f47dc5633 100644 (file)
@@ -228,7 +228,31 @@ class GCDependentSlot(InternalMethodSlot):
             # 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:
-                return self.slot_code(parent_type_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 InternalMethodSlot.slot_code(self, scope)
+        
+        
+class ConstructorSlot(InternalMethodSlot):
+    #  Descriptor for tp_new and tp_dealloc.
+    
+    def __init__(self, slot_name, method):
+        InternalMethodSlot.__init__(self, slot_name)
+        self.method = method
+    
+    def slot_code(self, scope):
+        if scope.parent_type.base_type \
+            and not scope.has_pyobject_attrs \
+            and not scope.lookup_here(self.method):
+            # 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)
         return InternalMethodSlot.slot_code(self, scope)
 
 
@@ -558,7 +582,7 @@ PyBufferProcs = (
 #------------------------------------------------------------------------------------------
 
 slot_table = (
-    InternalMethodSlot("tp_dealloc"),
+    ConstructorSlot("tp_dealloc", '__dealloc__'),
     EmptySlot("tp_print"), #MethodSlot(printfunc, "tp_print", "__print__"),
     EmptySlot("tp_getattr"),
     EmptySlot("tp_setattr"),
@@ -606,7 +630,7 @@ slot_table = (
     
     MethodSlot(initproc, "tp_init", "__init__"),
     EmptySlot("tp_alloc"), #FixedSlot("tp_alloc", "PyType_GenericAlloc"),
-    InternalMethodSlot("tp_new"),
+    ConstructorSlot("tp_new", '__new__'),
     EmptySlot("tp_free"),
     
     EmptySlot("tp_is_gc"),