comparison paraspace/injection.py @ 88:bbe8d5cbe368

Clone objects with meta info
author Thinker K.F. Li <thinker@codemud.net>
date Sun, 24 Jul 2011 19:15:04 +0800
parents cd1ee85853f4
children 88645ab29aeb
comparison
equal deleted inserted replaced
87:cd1ee85853f4 88:bbe8d5cbe368
1 1
2 def _deep_travel(obj, cloner, adjuster, visit_log=None): 2 def _relocatable_children(obj):
3 from paraspace.dexfile import _dex_type 3 from paraspace.dexfile import relocatable
4 4
5 if not visit_log: 5 attr_value_pairs = [(attr, getattr(obj, attr)) for attr in dir(obj)]
6 visit_log = {} 6 rel_children = [(attr, value) for attr, value in attr_value_pairs
7 pass 7 if isinstance(value, relocatable)]
8 return rel_children
8 9
10
11 ## \brief Travel relocatable descendants.
12 #
13 # \param cloner is the function to return a clone.
14 # \param adjuster is called to adjust the clone.
15 # \param visit_log is a dictionary to keep clones.
16 #
17 def _travel_desc_relocatable(obj, worker, visit_log):
9 if id(obj) in visit_log: 18 if id(obj) in visit_log:
10 return visit_log[id(obj)] 19 return visit_log[id(obj)]
11 20
12 attrs = [attr for attr in dir(obj) 21 result = worker(obj)
13 if not attr.startswith('_') and \ 22 visit_log[id(obj)] = result
14 isinstance(getattr(obj, attr), _dex_type)]
15 23
24 rel_children = _relocatable_children(obj)
25 for attr, value in rel_children:
26 _travel_conn_objs(value, worker, visit_log)
27 pass
28 pass
29
30
31 ## \brief Return name string of a linked class definition item.
32 def classdef_name(classdef):
33 return classdef.classIdx.descriptorIdx.stringDataOff.data
34
35
36 ## \brief Return a map that map type of a object to the list of a DEXFile.
37 def dex_type_2_array_attr_map():
38 global dex_type_2_array_attr_map
39 from paraspace.dexfile import DEXFile, array
40
41 attr_values = [(attr, getattr(DEXFile, attr))
42 for attr in dir(DEXFile)]
43 type_2_attr = dict([(value.child_type, attr)
44 for attr, value in attr_values
45 if isinstance(value, array)])
46
47 dex_type_2_array_attr_map = lambda: type_2_attr
48
49 return type_2_attr
50
51
52 ## \brief Append a object to appropriate list of a DEXFile object.
53 #
54 # Skip the object if found no appropriate list.
55 #
56 def dex_append_obj_list(dex, obj):
57 from paraspace.dex_deptracker import _dex_tree_get_child
58 from paraspace.dex_deptracker import _dex_tree_set_child
59
60 type_2_attr = dex_type_2_array_attr_map()
61 try:
62 attr = type_2_attr[obj.__class__]
63 except KeyError:
64 return
65
66 array = getattr(dex, attr)
67 array.items.append(obj)
68
69 count_name = array.count_name
70 count = _dex_tree_get_child(dex, count_name)
71 _dex_tree_set_child(dex, count_name, count + 1)
72 pass
73
74
75 ## \brief Clone a class definition item
76 #
77 # \param dex is the DEXFile that clazz is cloning for.
78 # \param clazz is the class definition item that is cloning.
79 #
80 def _clone_classdef(dex, clazz):
81 from copy import copy
82 from paraspace.dexfile import _DEX_StringDataItem, _DEX_StringId
83 from paraspace.dexfile import _DEX_TypeId
84
85 visit_log = {}
86
87 def cloner(obj):
88 clone = copy(obj)
89 return clone
90
91 def relink_dependencies(clone):
92 rel_children = _relocatable_children(clone)
93 for attr, value in rel_children:
94 clone_value = visit_log[id(value)]
95 setattr(clone, attr, clone_value)
96 pass
97 pass
98
99 def merge_unique_strdata():
100 strdatas = [(obj_id, obj)
101 for obj_id, obj in visit_log.items()
102 if isinstance(obj, _DEX_StringDataItem)]
103 dex_str_2_strdata = dict([(strdata.data, strdata)
104 for strdata in dex.stringDataItems.items])
105 for obj_id, strdata in strdatas:
106 if strdata.data in dex_str_2_strdata:
107 visit_log[obj_id] = dex_str_2_strdata[strdata]
108 else:
109 dex_append_obj_list(dex, strdata)
110 pass
111 pass
112 pass
113
114 def merge_unique_strid():
115 strids = [(obj_id, obj)
116 for obj_id, obj in visit_log.items()
117 if isinstance(obj, _DEX_StringId)]
118
119 for obj_id, strid in strids:
120 relink_dependencies(strid)
121 pass
122
123 strdata_2_strid = dict([(strid.stringDataOff, strid)
124 for strid in dex.stringIds.items])
125 for obj_id, strid in strids:
126 if strid.stringDataOff in strdata_2_strid:
127 visit_log[obj_id] = strdata_2_strid[strid.stringDataOff]
128 else:
129 dex_append_obj_list(dex, strid)
130 pass
131 pass
132 pass
133
134 def merge_unique_typeid():
135 typeids = [(obj_id, obj)
136 for obj_id, obj in visit_log.items()
137 if isinstance(obj, _DEX_TypeId)]
138
139 for obj_id, typeid in typeids:
140 relink_dependencies(typeid)
141 pass
142
143 strid_2_typeid = dict([(typeid.descriptorIdx, typeid)
144 for typeid in dex.typeIds.items])
145 for obj_id, typeid in typeids:
146 if typeid.descriptorIdx in strid_2_typeid:
147 visit_log[obj_id] = strid_2_typeid[typeid.descriptorIdx]
148 else:
149 dex_append_obj_list(dex, typeid)
150 pass
151 pass
152 pass
153
154 def has_classdef(clazz):
155 class_typeIds = set([classdef.classIdx
156 for classdef in dex.classDefs.items])
157 return dex.classIdx in class_typeIds
158
159 _travel_desc_relocatable(obj, cloner, visit_log)
160
161 merge_unique_strdata()
162 merge_unique_strid()
163 merge_unique_typeid()
164
165 for obj in visit_log.values():
166 if isinstance(obj, (_DEX_StringDataItem,
167 _DEX_StringId,
168 _DEX_TypeId)):
169 continue
170 relink_dependencies(obj)
171 dex_append_obj_list(dex, obj)
172 pass
173
174 if has_classef(clazz):
175 raise RuntimeError, \
176 'clone a class \'%s\'that is already in the DEXFile' % \
177 classdef_name(clazz)
16 pass 178 pass
17 179
18 180
19 def dexfile_insert_class(dex, class_def): 181 def dexfile_insert_class(dex, class_def):
20 classId_orig = class_def.classIdx 182 _clone_classdef(dex, class_def)
21 if dex_find_type(dex, class_orig):
22 raise RuntimeError, 'duplicated type'
23 classId = dex_dup_insert_type(dex, classId_orig)
24
25 superclassId_orig = class_def.superclassId
26 superclassId = dex_find_type(dex, superclassId_orig) or \
27 dex_dup_insert_type(dex, superclassId_orig)
28
29 if dex.interfacesOffRef.is_true:
30 interfaces_orig = dex.interfacesOffRef.value
31 interfaces = dex_dup_insert_typelist(dex, interfaces_org)
32 pass
33
34 sourceFileIdx_orig = dex.sourceFileIdx
35 sourceFileIdx = dex_find_type(dex, sourceFileIdx_orig) or \
36 dex_dup_insert_type(dex, sourceFileIdx_orig)
37
38 if dex.annotationsOffRef.is_true:
39 annotations_orig = dex.annotationsOffRef.value
40 annotations = dex_dup_insert(dex, annotations_orig)
41 pass
42
43 if dex.classDataOffRef.is_true:
44 class_data_orig = dex.classDataOffRef.value
45 class_data = dex_dup_insert(dex, class_data_orig)
46 pass
47 pass 183 pass