Rev 158: Implement collapsing old-style classes. in http://bazaar.launchpad.net/~jameinel/meliae/mem-object-collection

John Arbash Meinel john at arbash-meinel.com
Tue Dec 29 22:00:22 GMT 2009


At http://bazaar.launchpad.net/~jameinel/meliae/mem-object-collection

------------------------------------------------------------
revno: 158
revision-id: john at arbash-meinel.com-20091229215959-s26x0ut338x5oku2
parent: john at arbash-meinel.com-20091229213640-b76sv0ynf82hhxlb
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: mem-object-collection
timestamp: Tue 2009-12-29 15:59:59 -0600
message:
  Implement collapsing old-style classes.
  
  This means that we get proper type names as well as the dict itself being
  part of the instance.
-------------- next part --------------
=== modified file 'meliae/_loader.pyx'
--- a/meliae/_loader.pyx	2009-12-29 21:34:51 +0000
+++ b/meliae/_loader.pyx	2009-12-29 21:59:59 +0000
@@ -327,6 +327,13 @@
         def __get__(self):
             return <object>(self._obj.type_str)
 
+        def __set__(self, value):
+            cdef PyObject *ptr
+            ptr = <PyObject *>value
+            Py_INCREF(ptr)
+            Py_DECREF(self._obj.type_str)
+            self._obj.type_str = ptr
+
     property size:
         """The number of bytes allocated for this object."""
         def __get__(self):

=== modified file 'meliae/loader.py'
--- a/meliae/loader.py	2009-12-29 21:36:40 +0000
+++ b/meliae/loader.py	2009-12-29 21:59:59 +0000
@@ -406,20 +406,27 @@
                     sys.stderr.write('checked %8d / %8d collapsed %8d    \r'
                                      % (item_idx, total, collapsed))
             if obj.type_str == 'module' and len(obj) == 1:
-                (dict_ref,) = obj.ref_list
+                (dict_obj,) = obj
+                if dict_obj.type_str != 'dict':
+                    continue
                 extra_refs = []
             else:
                 if len(obj) != 2:
                     continue
-                (dict_ref, type_ref) = obj.ref_list
-                type_obj = self.objs[type_ref]
-                if (type_obj.type_str != 'type'
-                    or type_obj.value != obj.type_str):
+                obj_1, obj_2 = obj
+                if obj_1.type_str == 'dict' and obj_2.type_str == 'type':
+                    # This is a new-style class
+                    dict_obj = obj_1
+                    type_obj = obj_2
+                elif (obj.type_str == 'instance'
+                      and obj_1.type_str == 'classobj'
+                      and obj_2.type_str == 'dict'):
+                    # This is an old-style class
+                    type_obj = obj_1
+                    dict_obj = obj_2
+                else:
                     continue
-                extra_refs = [type_ref]
-            dict_obj = self.objs[dict_ref]
-            if dict_obj.type_str != 'dict':
-                continue
+                extra_refs = [type_obj.address]
             if (dict_obj.num_referrers != 1
                 or dict_obj.referrers[0] != address):
                 continue
@@ -428,9 +435,11 @@
             obj.ref_list = dict_obj.ref_list + extra_refs
             obj.size = obj.size + dict_obj.size
             obj.total_size = 0
+            if obj.type_str == 'instance':
+                obj.type_str = type_obj.value
             # Now that all the data has been moved into the instance, remove
             # the dict from the collection
-            del self.objs[dict_ref]
+            del self.objs[dict_obj.address]
         if self.show_progress:
             sys.stderr.write('checked %8d / %8d collapsed %8d    \n'
                              % (item_idx, total, collapsed))

=== modified file 'meliae/tests/test__loader.py'
--- a/meliae/tests/test__loader.py	2009-12-29 21:34:51 +0000
+++ b/meliae/tests/test__loader.py	2009-12-29 21:59:59 +0000
@@ -228,6 +228,12 @@
         mop.value = 'a str'
         self.assertEqual('a str', mop.value)
 
+    def test_type_str(self):
+        mop = self.moc.add(1234, 'type', 256, value='testval')
+        self.assertEqual('type', mop.type_str)
+        mop.type_str = 'difftype'
+        self.assertEqual('difftype', mop.type_str)
+
     def test_name(self):
         mop = self.moc.add(1234, 'type', 256, name='the name')
         # 'name' entries get mapped as value

=== modified file 'meliae/tests/test_loader.py'
--- a/meliae/tests/test_loader.py	2009-12-29 21:34:51 +0000
+++ b/meliae/tests/test_loader.py	2009-12-29 21:59:59 +0000
@@ -72,6 +72,20 @@
 '{"address": 15, "type": "dict", "size": 140, "len": 2, "refs": [5, 6, 9, 6]}',
 ]
 
+_old_instance_dump = [
+'{"address": 1, "type": "instance", "size": 36, "refs": [2, 3]}',
+'{"address": 3, "type": "dict", "size": 140, "len": 2, "refs": [4, 5, 6, 7]}',
+'{"address": 7, "type": "int", "size": 12, "value": 2, "refs": []}',
+'{"address": 6, "type": "str", "size": 25, "len": 1, "value": "b", "refs": []}',
+'{"address": 5, "type": "int", "size": 12, "value": 1, "refs": []}',
+'{"address": 4, "type": "str", "size": 25, "len": 1, "value": "a", "refs": []}',
+'{"address": 2, "type": "classobj", "size": 48, "name": "OldStyle"'
+ ', "refs": [8, 43839680, 9]}',
+'{"address": 9, "type": "str", "size": 32, "len": 8, "value": "OldStyle"'
+ ', "refs": []}',
+'{"address": 8, "type": "tuple", "size": 28, "len": 0, "refs": []}',
+]
+
 
 class TestLoad(tests.TestCase):
 
@@ -270,6 +284,25 @@
         self.assertEqual([5, 6, 9, 6], mod.ref_list)
         self.assertFalse(15 in manager.objs)
 
+    def test_collapse_old_instance_dicts(self):
+        manager = loader.load(_old_instance_dump, show_prog=False)
+        instance = manager.objs[1]
+        self.assertEqual('instance', instance.type_str)
+        self.assertEqual(36, instance.size)
+        self.assertEqual([2, 3], instance.ref_list)
+        inst_dict = manager[3]
+        self.assertEqual(140, inst_dict.size)
+        self.assertEqual([4, 5, 6, 7], inst_dict.ref_list)
+        manager.compute_referrers()
+        manager.collapse_instance_dicts()
+        # The instance dict has been removed, and its references moved into the
+        # instance, further, the type has been updated from generic 'instance'
+        # to being 'OldStyle'.
+        self.assertFalse(3 in manager.objs)
+        self.assertEqual(176, instance.size)
+        self.assertEqual([4, 5, 6, 7, 2], instance.ref_list)
+        self.assertEqual('OldStyle', instance.type_str)
+
     def test_expand_refs_as_dict(self):
         manager = loader.load(_instance_dump, show_prog=False)
         as_dict = manager.refs_as_dict(manager[15])



More information about the bazaar-commits mailing list