Mercurial > paraspace
changeset 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 | 7a059ab408f0 |
files | paraspace/dex_deptracker.py paraspace/injection.py |
diffstat | 2 files changed, 172 insertions(+), 35 deletions(-) [+] |
line wrap: on
line diff
--- a/paraspace/dex_deptracker.py Sat Jul 23 23:02:39 2011 +0800 +++ b/paraspace/dex_deptracker.py Sun Jul 24 19:15:04 2011 +0800 @@ -680,6 +680,7 @@ pass +## \brief Link objects to their dependencies . def _link_dependencies(root_obj, all_dep_decls): markers_info = {} depon_src_map = {}
--- a/paraspace/injection.py Sat Jul 23 23:02:39 2011 +0800 +++ b/paraspace/injection.py Sun Jul 24 19:15:04 2011 +0800 @@ -1,47 +1,183 @@ -def _deep_travel(obj, cloner, adjuster, visit_log=None): - from paraspace.dexfile import _dex_type +def _relocatable_children(obj): + from paraspace.dexfile import relocatable - if not visit_log: - visit_log = {} - pass + attr_value_pairs = [(attr, getattr(obj, attr)) for attr in dir(obj)] + rel_children = [(attr, value) for attr, value in attr_value_pairs + if isinstance(value, relocatable)] + return rel_children + +## \brief Travel relocatable descendants. +# +# \param cloner is the function to return a clone. +# \param adjuster is called to adjust the clone. +# \param visit_log is a dictionary to keep clones. +# +def _travel_desc_relocatable(obj, worker, visit_log): if id(obj) in visit_log: return visit_log[id(obj)] - attrs = [attr for attr in dir(obj) - if not attr.startswith('_') and \ - isinstance(getattr(obj, attr), _dex_type)] + result = worker(obj) + visit_log[id(obj)] = result + + rel_children = _relocatable_children(obj) + for attr, value in rel_children: + _travel_conn_objs(value, worker, visit_log) + pass + pass + + +## \brief Return name string of a linked class definition item. +def classdef_name(classdef): + return classdef.classIdx.descriptorIdx.stringDataOff.data + + +## \brief Return a map that map type of a object to the list of a DEXFile. +def dex_type_2_array_attr_map(): + global dex_type_2_array_attr_map + from paraspace.dexfile import DEXFile, array + + attr_values = [(attr, getattr(DEXFile, attr)) + for attr in dir(DEXFile)] + type_2_attr = dict([(value.child_type, attr) + for attr, value in attr_values + if isinstance(value, array)]) + + dex_type_2_array_attr_map = lambda: type_2_attr + + return type_2_attr + + +## \brief Append a object to appropriate list of a DEXFile object. +# +# Skip the object if found no appropriate list. +# +def dex_append_obj_list(dex, obj): + from paraspace.dex_deptracker import _dex_tree_get_child + from paraspace.dex_deptracker import _dex_tree_set_child + + type_2_attr = dex_type_2_array_attr_map() + try: + attr = type_2_attr[obj.__class__] + except KeyError: + return + + array = getattr(dex, attr) + array.items.append(obj) + + count_name = array.count_name + count = _dex_tree_get_child(dex, count_name) + _dex_tree_set_child(dex, count_name, count + 1) + pass + + +## \brief Clone a class definition item +# +# \param dex is the DEXFile that clazz is cloning for. +# \param clazz is the class definition item that is cloning. +# +def _clone_classdef(dex, clazz): + from copy import copy + from paraspace.dexfile import _DEX_StringDataItem, _DEX_StringId + from paraspace.dexfile import _DEX_TypeId + + visit_log = {} + def cloner(obj): + clone = copy(obj) + return clone + + def relink_dependencies(clone): + rel_children = _relocatable_children(clone) + for attr, value in rel_children: + clone_value = visit_log[id(value)] + setattr(clone, attr, clone_value) + pass + pass + + def merge_unique_strdata(): + strdatas = [(obj_id, obj) + for obj_id, obj in visit_log.items() + if isinstance(obj, _DEX_StringDataItem)] + dex_str_2_strdata = dict([(strdata.data, strdata) + for strdata in dex.stringDataItems.items]) + for obj_id, strdata in strdatas: + if strdata.data in dex_str_2_strdata: + visit_log[obj_id] = dex_str_2_strdata[strdata] + else: + dex_append_obj_list(dex, strdata) + pass + pass + pass + + def merge_unique_strid(): + strids = [(obj_id, obj) + for obj_id, obj in visit_log.items() + if isinstance(obj, _DEX_StringId)] + + for obj_id, strid in strids: + relink_dependencies(strid) + pass + + strdata_2_strid = dict([(strid.stringDataOff, strid) + for strid in dex.stringIds.items]) + for obj_id, strid in strids: + if strid.stringDataOff in strdata_2_strid: + visit_log[obj_id] = strdata_2_strid[strid.stringDataOff] + else: + dex_append_obj_list(dex, strid) + pass + pass + pass + + def merge_unique_typeid(): + typeids = [(obj_id, obj) + for obj_id, obj in visit_log.items() + if isinstance(obj, _DEX_TypeId)] + + for obj_id, typeid in typeids: + relink_dependencies(typeid) + pass + + strid_2_typeid = dict([(typeid.descriptorIdx, typeid) + for typeid in dex.typeIds.items]) + for obj_id, typeid in typeids: + if typeid.descriptorIdx in strid_2_typeid: + visit_log[obj_id] = strid_2_typeid[typeid.descriptorIdx] + else: + dex_append_obj_list(dex, typeid) + pass + pass + pass + + def has_classdef(clazz): + class_typeIds = set([classdef.classIdx + for classdef in dex.classDefs.items]) + return dex.classIdx in class_typeIds + + _travel_desc_relocatable(obj, cloner, visit_log) + + merge_unique_strdata() + merge_unique_strid() + merge_unique_typeid() + + for obj in visit_log.values(): + if isinstance(obj, (_DEX_StringDataItem, + _DEX_StringId, + _DEX_TypeId)): + continue + relink_dependencies(obj) + dex_append_obj_list(dex, obj) + pass + + if has_classef(clazz): + raise RuntimeError, \ + 'clone a class \'%s\'that is already in the DEXFile' % \ + classdef_name(clazz) pass def dexfile_insert_class(dex, class_def): - classId_orig = class_def.classIdx - if dex_find_type(dex, class_orig): - raise RuntimeError, 'duplicated type' - classId = dex_dup_insert_type(dex, classId_orig) - - superclassId_orig = class_def.superclassId - superclassId = dex_find_type(dex, superclassId_orig) or \ - dex_dup_insert_type(dex, superclassId_orig) - - if dex.interfacesOffRef.is_true: - interfaces_orig = dex.interfacesOffRef.value - interfaces = dex_dup_insert_typelist(dex, interfaces_org) - pass - - sourceFileIdx_orig = dex.sourceFileIdx - sourceFileIdx = dex_find_type(dex, sourceFileIdx_orig) or \ - dex_dup_insert_type(dex, sourceFileIdx_orig) - - if dex.annotationsOffRef.is_true: - annotations_orig = dex.annotationsOffRef.value - annotations = dex_dup_insert(dex, annotations_orig) - pass - - if dex.classDataOffRef.is_true: - class_data_orig = dex.classDataOffRef.value - class_data = dex_dup_insert(dex, class_data_orig) - pass + _clone_classdef(dex, class_def) pass