changeset 26:b30a0d29a62f

Debugging _travel_dex_type
author Thinker K.F. Li <thinker@codemud.net>
date Tue, 07 Jun 2011 15:02:42 +0800
parents 670167ed06bb
children 15cb829ac442
files paraspace/dex_deptracker.py paraspace/tests/dexfile_test.py
diffstat 2 files changed, 134 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/paraspace/dex_deptracker.py	Tue Jun 07 00:21:17 2011 +0800
+++ b/paraspace/dex_deptracker.py	Tue Jun 07 15:02:42 2011 +0800
@@ -35,7 +35,49 @@
     return obj, parent
 
 
+def _travel_dex_type(clazz, name_path):
+    if isinstance(clazz, _marker):
+        clazz = clazz.back_type
+        pass
+    
+    travel_queue = [(getattr(clazz, attr_name), name_path + '.' + attr_name)
+                    for attr_name in dir(clazz)
+                    if not attr_name.startswith('_')]
+    while travel_queue:
+        attr, name_path = travel_queue.pop(0)
+        yield attr, name_path
+
+        if isinstance(attr, _marker):
+            #
+            # transparent.  Enqueue back_type with the same name again.
+            #
+            child = attr.back_type
+            travel_queue.append((child, name_path))
+            continue
+
+        if isinstance(attr, _nest_types):
+            if isinstance(attr, dexfile.array):
+                child_name = name_path + '.items.*'
+                child = attr.child_type
+                travel_queue.append((child, child_name))
+            elif isinstance(attr, dexfile.cond):
+                child_name = name_path + '.value'
+                child = attr.child_type
+                travel_queue.append((child, child_name))
+            elif isinstance(attr, dexfile.switch):
+                for key in attr.map.keys():
+                    child_name = name_path + '.' + repr(key)
+                    child = attr.map[key]
+                    travel_queue.append((child, child_name))
+                    pass
+                pass
+            pass
+        pass
+    pass
+
+
 def _find_dep_decls_from_clazz(name_path, clazz, dex_types):
+    # XXX: implements the loop with _travel_dex_type()
     dep_decls = {}
 
     for attr in dir(clazz):
@@ -129,23 +171,31 @@
 
 def _travel_dex_relocatable(root_obj, parents=[]):
     stk = [(root_obj, parents, root_obj.__class__.__name__)]
-
+    
+    def make_travel_info(obj, obj_name, child_name):
+        child_parents = parents + [obj]
+        child_obj = _dex_tree_get_child(obj, child_name)
+        if isinstance(child_obj, dexfile.composite):
+            child_path = child_obj.__class__.__name__
+        else:
+            child_path = obj_name + '.' + child_name
+            pass
+        return (child_obj, child_parents, child_path)
+    
     while stk:
         obj, parents, obj_name = stk.pop(0)
         yield (obj, parents, obj_name)
         
         if isinstance(obj, list):
-            children = [(value, parents + [obj], obj_name + '.' + repr(idx))
-                        for idx, value in enumerate(obj)]
+            children = [make_travel_info(obj, obj_name, repr(idx))
+                        for idx in range(len(obj))]
             stk.extend(children)
             continue
         
         if not isinstance(obj, dexfile.relocatable):
             continue
 
-        child_parents = parents + [obj]
-        children = [(_dex_tree_get_child(obj, child_name),
-                     child_parents, obj_name + '.' + child_name)
+        children = [make_travel_info(obj, obj_name, child_name)
                     for child_name in obj.children()]
         stk.extend(children)
         pass
@@ -172,9 +222,12 @@
     return all_dep_decls
 
 
-class _uid_marker(dexfile.relocatable):
+class _marker(dexfile.relocatable):
+    back_type = None
+    pass
+
+class _uid_marker(_marker):
     uid_seq = 0
-    back_type = None
     
     def __init__(self, back_type, name_path):
         self.back_type = back_type
@@ -361,6 +414,49 @@
     pass
 
 
+def _patch_dex_type_markers(all_dep_decls):
+    import itertools
+    marked_types = dict([(marker.back_type, name)
+                         for name, marker in _all_dex_types().items()
+                         if isinstance(marker, _marker)])
+
+    travel_iters = [_travel_dex_type(dex_type, name_path)
+                    for name_path, dex_type in _all_dex_types().items()]
+    marked_type_refs = [(name_path, marked_types[attr])
+                        for attr, name_path in itertools.chain(*travel_iters)
+                        if type(attr) == type and
+                        issubclass(attr, dexfile.composite) and
+                        attr in marked_types]
+    print marked_type_refs
+    
+    def patch_ref(name_path, depon_path):
+        depon, depon_parent = _resolve_name_path(depon_path)
+        
+        path_elms = name_path.split('.')
+        parent_path = '.'.join(path_elms[:-1])
+        parent, grand = _resolve_name_path(parent_path)
+
+        if isinstance(grand, _nest_types):
+            if isinstance(grand, (dexfile.array, dexfile.cond)):
+                grand.child_type = depon
+            elif isinstance(grand, dexfile.switch):
+                key = eval(path_elms[-1])
+                grand.map[key] = depon
+            else:
+                raise RuntimeError, 'should not be here'
+            pass
+        else:
+            name = path_elms[-1]
+            setattr(parent, name, depon)
+            pass
+        pass
+    
+    for name_path, depon_path in marked_type_refs:
+        patch_ref(name_path, depon_path)
+        pass
+    pass
+
+
 def _link_dependencies(root_obj, all_dep_decls):
     markers_info = {}
     depon_src_map = {}
@@ -388,6 +484,7 @@
     #
     for obj, parents, name_path in \
             _travel_dex_relocatable(root_obj):
+        print name_path
         if name_path not in all_dep_decls:
             continue
 
@@ -396,20 +493,20 @@
         
         dep = all_dep_decls[name_path]
         dep_type = dep[0]
-        if isinstance(dep_type, dexfile.depend_off_rel):
+        if dep_type == dexfile.depend_off_rel:
             depon1 = _rel_offset_marker.find_depon(dep[1])
             depon2 = _rel_offset_marker.find_depon(dep[2])
 
             parent = parents[-1]
             name = name_path.split('.')[-1]
             _dex_tree_set_child(parent, name, (depon1, depon2))
-        elif isinstance(dep_type, dexfile.depend_off):
+        elif dep_type == dexfile.depend_off:
             depon_name_path = dep[1]
             depon = markers_info[depon_name_path]
             parent = parents[-1]
             name = name_path.split('.')[-1]
             _dex_tree_set_child(parent, name, depon)
-        elif isinstance(dep_type, dexfile.depend_idx):
+        elif dep_type == dexfile.depend_idx:
             depon_name_path = dep[1]
             depon = markers_info[depon_name_path]
             parent = parents[-1]
--- a/paraspace/tests/dexfile_test.py	Tue Jun 07 00:21:17 2011 +0800
+++ b/paraspace/tests/dexfile_test.py	Tue Jun 07 15:02:42 2011 +0800
@@ -130,10 +130,24 @@
     pass
 
 
+def travel_dex_type_test():
+    from paraspace.dex_deptracker import _travel_dex_type
+    
+    attr_infos = [attr_info
+                  for attr_info in \
+                      _travel_dex_type(dexfile._DEX_AnnotationsDirectoryItem,
+                                       '_DEX_AnnotationsDirectoryItem')
+                  ]
+    print attr_infos
+    assert len(attr_infos) == 10
+    pass
+
+
 def install_markers_test():
     from paraspace.dex_deptracker import collect_all_dep_decls
     from paraspace.dex_deptracker import _install_markers, _idx_marker
     from paraspace.dex_deptracker import _offset_marker, _rel_offset_marker
+    from paraspace.dex_deptracker import _patch_dex_type_markers
 
     _install_dexfile_4_deptracker()
 
@@ -143,19 +157,27 @@
     assert isinstance(dexfile._DEX_Code.back_type.handlers_size,
                       _rel_offset_marker)
     assert dexfile._DEX_TypeList.__class__ == _offset_marker
+
+    _patch_dex_type_markers(all_dep_decls)
+    print all_dep_decls.keys()
+    print dexfile.DEXFile.typeLists.child_type
+    assert isinstance(dexfile.DEXFile.typeLists.child_type, _offset_marker)
     pass
 
+
 def link_dependencies_test():
     from paraspace.dex_deptracker import collect_all_dep_decls
     from paraspace.dex_deptracker import _link_dependencies
     from paraspace.dex_deptracker import _install_markers, _idx_marker
     from paraspace.dex_deptracker import _offset_marker, _rel_offset_marker
+    from paraspace.dex_deptracker import _patch_dex_type_markers
 
     _install_dexfile_4_deptracker()
 
     all_dep_decls = collect_all_dep_decls()
     _install_markers(all_dep_decls)
     assert isinstance(dexfile.DEXFile.typeIds, _idx_marker)
+    _patch_dex_type_markers(all_dep_decls)
 
     srcdir = os.path.dirname(__file__)
     srcroot = os.path.join(srcdir, '..', '..')
@@ -163,4 +185,8 @@
     dex = dexfile.DEXFile.open(testdatapath)
 
     _link_dependencies(dex, all_dep_decls)
+    
+    code_item = dex.codeItems.items[0]
+    print code_item.debugInfoOff.__class__
+    assert code_item.debugInfoOff.__class__ == dexfile._DEX_DebugInfoItem
     pass