Mercurial > paraspace
view paraspace/injection.py @ 98:c0c127c7b37e
Check and fix issues of map sizes
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Mon, 25 Jul 2011 20:37:32 +0800 |
parents | 1769e52bdd9d |
children | 3898711adb2c |
line wrap: on
line source
def _relocatable_children(obj): from paraspace.dexfile import relocatable 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)] result = worker(obj) visit_log[id(obj)] = result rel_children = _relocatable_children(obj) for attr, value in rel_children: _travel_desc_relocatable(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 from paraspace.dex_deptracker import _marker def skip_marker_type(clazz): while isinstance(clazz, _marker): clazz = clazz.back_type pass return clazz attr_values = [(attr, getattr(DEXFile, attr)) for attr in dir(DEXFile)] type_2_attr = dict([(skip_marker_type(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 if count_name: count = _dex_tree_get_child(dex, count_name) _dex_tree_set_child(dex, count_name, count + 1) pass 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 clazz.classIdx in class_typeIds _travel_desc_relocatable(clazz, 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_classdef(clazz): raise RuntimeError, \ 'clone a class \'%s\'that is already in the DEXFile' % \ classdef_name(clazz) clone = visit_log[id(clazz)] return clone ## \brief Clone a class definition and insert into a DEXFile. # # This function clone a class definition from a linked DEXFile and # insert it into another one. # # \param dex is a DEXFile_linked to insert the clone. # \param class_def is a class definition going to be cloned. # def dexfile_insert_class(dex, class_def): clone = _clone_classdef(dex, class_def) return clone