def setUp(self): super(SpMtxAggregate, self).setUp() from astvis import services core.registerServices(services.dataflow) core.registerServices(services.controlflow) core.registerServices(services.references) self.service = core.getService('DataflowService') subprogram = self.astModel.files[0].units[0].subprograms[0] cfService = core.getService('ControlflowService') self.flowModel = cfService.getModel(subprogram)
def showObject(self, obj): self.model.clear() resolver = core.getService("ReferenceResolver") refs = resolver.getReferringObjects(obj).keys() for ref in refs: print ref self.model.append((str(ref),))
def _notify(self, obj, event, args, dargs): """Notified when objects are added to or removed from diagram. @todo: reimplement calle[er]Names with ReferenceResolver""" LOG.debug('%s', obj) if event==ADDED_TO_DIAGRAM and args[0]==self: # add container connector if self.hasObject(obj.parent): connector = ContainerConnector(obj.parent, obj, self) self.addConnector(connector, connector) for child in obj.getChildren(): if self.hasObject(child): connector = ContainerConnector(obj, child, self) self.addConnector(connector, connector) # get all calls/callers for obj and add connectors resolver = core.getService('ReferenceResolver') refObjs = resolver.getReferencedObjects(obj) for refObj in refObjs: if not isinstance(refObj, (basic.ProgramUnit, basic.Subprogram)): continue callee = refObj.astObject if callee and self.hasObject(callee): connector = CallConnector(obj, callee, self) self.addConnector(connector, connector) basicObj = obj.model.basicModel.getObjectByASTObject(obj) refObjs = resolver.getReferringObjects(basicObj).keys() for refObj in refObjs: caller = refObj if caller and self.hasObject(caller): connector = CallConnector(caller, obj, self) self.addConnector(connector, connector)
def getLiveVariables(self, astNode, context=None): """For each basic block calculates (variable) uses that are reached from this code location. @return: (ins, outs) - uses on enter/leave of each basic block @rtype: (d, d) where d = {block: {name: set((block, indexInBlock))}} """ astScope = astNode.model.getScope(astNode, False) # check for cached version if self._liveVariables.has_key(astScope): return self._liveVariables[astScope] # else calculate localEntities = [] for decl in astScope.declarationBlock.statements: localEntities.extend(decl.entities) localNames = map(lambda e:e.name.lower(), localEntities) cfservice = core.getService('ControlflowService') flowModel = cfservice.getModel(astScope) ins = {} # { block: {name: set((block,indexInBlock,astNode))}} outs = {} # { block: {name: set((block,indexInBlock,astNode))}} # some help functions def IN(block, createNew=True): if not ins.has_key(block): if not createNew: return None ins[block] = df.LiveVariableDict() return ins[block] def OUT(block): if not outs.has_key(block): outs[block] = df.LiveVariableDict() return outs[block] # start main loop which works until converging of IN/OUT states working = [] # blocks that have their IN redefined working.append(flowModel._endBlock) while working: block = working.pop() outUses = OUT(block) oldInUses = IN(block, False) inUses = self._backTransform(outUses, block) changed = (inUses != oldInUses) if changed: ins[block] = inUses # IN has changed since the last try # add following basic blocks to the working set as their OUTs change for prevBlock in block.getPreviousBasicBlocks(): prevOutUses = OUT(prevBlock) prevOutUses.update(inUses) working.append(prevBlock) self._liveVariables[astScope] = (ins, outs) return ins, outs
def showUsedDefinitions(self, target, context): "Show used (variable) definitions for the block (Use-Definition chain)." ocItem = target dfService = core.getService('DataflowService') usedDefs = dfService.getUsedDefinitions(ocItem.block) self.project.root.openUsedDefinitionsList(self, ocItem.block, usedDefs)
def showActiveObjects(self, target, context): "Show active objects (used variables) in block." ocItem = target if ocItem.block!=None: block=ocItem.block service = core.getService('DataflowService') service.getActiveDefinitionsByBlock(block)
def showBlockDefinitions(self, target, context): "Show definitions that reach the block output (in Reaching Definitions)." ocItem = target block = ocItem.block diagram = context dfService = core.getService('DataflowService') blockDefs = dfService.getBlockDefinitions(block) print blockDefs
def _modifySubTags(self, obj, child, added, removed, isSource=False): if not isSource: # handle subtags subTags = self._subTags.get(obj, {}) # added and removed contain tags that were changed in child for tag in added.copy(): if not subTags.has_key(tag): subTags[tag] = set() # add object as a child that contains the tag if not child in subTags[tag]: if subTags[tag]: added.remove(tag) subTags[tag].add(child) else: added.remove(tag) for tag in removed.copy(): if subTags.has_key(tag): # remove object as containing the tag if child in subTags[tag]: subTags[tag].remove(child) if not subTags[tag]: # subtags empty del subTags[tag] if tag in self.get(obj, set()): # but tag is present removed.remove(tag) else: removed.remove(tag) # now added and removed contain tags that were changed in obj (ie parent) # and subTags are new obj sub-tags self._subTags[obj] = subTags # if it is callable follow call tags if isinstance(obj,ast.Subprogram): service = core.getService('ReferenceResolver') basicObj = obj.model.basicModel.getObjectByASTObject(obj) callers = service.getReferringObjects(basicObj) for caller,stmts in callers.items(): for stmt in stmts: self._modifyCallTags(stmt, obj, added.copy(), removed.copy(), isSource=True) # notify widgets event.manager.notifyObservers(self, event.PROPERTY_CHANGED, (None,event.PC_CHANGED,None,None), dargs={'key':obj}) # handle parent if added or removed: if hasattr(obj,'parent') and obj.parent!=None: self._modifySubTags(obj.parent, obj, added, removed)
def hideReferences(self, target, context): name = target service = core.getService('ReferenceResolver') astCode = self.flowModel.code basicModel = astCode.model.basicModel scope = basicModel.getObjectByASTObject(astCode) references = service.getReferringObjects(scope.variables[name]) for ref in references.get(astCode, []): blocks = self.flowModel.findBlocksByObject(ref) for block in blocks: isAssign = ref.isAssignment() op = isAssign is True and 'write' or isAssign is False and 'read' or 'unknown' self._tagGraph.removeTag((scope.variables[name],op), block, ref) self._referenceTags.remove(name)
def showOutDefinitions(self, target, context): "Show definitions that reach the block output (in Reaching Definitions)." ocItem = target block = ocItem.block code = block.model.code diagram = context dfService = core.getService('DataflowService') ins, outs = dfService.getReachingDefinitions(code) blockGraph = diagram._hgraph outDefs = set() for edge in blockGraph.outEdges[block]: for fromBlock, toBlock in blockGraph.edges[edge]: outDefs.update(outs[fromBlock].keys()) print outDefs
def showLVInDefinitions(self, target, context): "Show uses that the block input has (in Live Variables)." ocItem = target block = ocItem.block code = block.model.code diagram = context dfService = core.getService('DataflowService') ins, outs = dfService.getLiveVariables(code) blockGraph = diagram._hgraph inUses = set() for edge in blockGraph.inEdges[block]: for fromBlock, toBlock in blockGraph.edges[edge]: inUses.update(ins[toBlock].keys()) print inUses
def getReachingDefinitions(self, astNode, context=None): """For each basic block calculates (variable) definitions that reach this code location. @return: (ins, outs) - definitions on enter/leave of each basic block @rtype: (d, d) where d = {block: {name: set((block, indexInBlock))}} """ astScope = astNode.model.getScope(astNode, False) # check for cached version if self._reachingDefinitions.has_key(astScope): return self._reachingDefinitions[astScope] # else calculate cfservice = core.getService('ControlflowService') flowModel = cfservice.getModel(astScope) rd = ReachingDefinitions(flowModel) self._reachingDefinitions[astScope] = (rd.ins, rd.outs) return rd.ins, rd.outs
def _addObject(self, obj, refs, iParent, shown): data = factory.getRow((obj, refs)) iObj = self.model.append(iParent, data) if obj in shown: return else: shown.add(obj) resolver = core.getService('ReferenceResolver') references = resolver.getReferringObjects(obj) if LOG.isEnabledFor(FINER): LOG.log(FINER, "Number of referring objects for %s: %d", obj, len(references.keys())) for refScope, refs in references.items(): basicObj = refScope.model.basicModel.getObjectByASTObject(refScope) self._addObject(basicObj, refs, iObj, shown) self.view.expand_row(self.model.get_path(iObj), False)
def _dragDataRecv(self, widget, context, x, y, data, info, timestamp): if self.flowModel != None: return LOG.debug("GTK DnD data_recv with info=%d"%info) if info==INFO_OBJECT_PATH.number: clazz, path = pickle.loads(data.data) if issubclass(clazz, ast.Code): # get canvas coordinates m = cairo.Matrix(*widget.matrix) m.invert() cx, cy = m.transform_point(x,y) # add item obj = self.project.astModel.getObjectByPath(path) cfservice = core.getService('ControlflowService') self.setModel(cfservice.getModel(obj), (cx,cy)) context.drop_finish(True, timestamp) else: context.drop_finish(False, timestamp) else: context.drop_finish(False, timestamp)
def getActiveDefinitionsByBlock(self, block): """Return all references and calls in the control flow block. @type block: L{astvis.model.flow.Block} """ # collect AST objects objs = [] def cb(block): if isinstance(block, flow.BasicBlock): objs.extend(block.executions) block.itertree(cb) # find references in every AST object unknown = set() written = set() read = set() called = set() service = core.getService('ASTTreeWalker') for obj in objs: refs = service.getReferencesFrom(obj) for ref in refs: if isinstance(ref, ast.Statement) and ref.type=='call' \ or isinstance(ref, ast.Call): called.add(ref.name.lower()) elif ref.base==None: isA = ref.isAssignment() if isA is None: unknown.add(ref.name.lower()) elif isA: written.add(ref.name.lower()) else: read.add(ref.name.lower()) print 'called = ', called print 'unknown = ', unknown print 'written = ', written print 'read = ', read
def _getDefinitions(self, execution): "Return names that are assigned values with ast object as value." astWalkerService = core.getService('ASTTreeWalker') defs = {} refs = astWalkerService.getReferencesFrom(execution) for ref in refs: if isinstance(ref, ast.Statement) and ref.type=='call' \ or isinstance(ref, ast.Call): pass # ignore calls elif isinstance(ref, ast.Reference) and ref.isFinalComponent(): isA = ref.getPrimaryBase().isAssignment() if isA is None or isA: # consider unknown as write # replace the previous definition names = [] workRef = ref while workRef!=None: names.append(workRef.name.lower()) workRef = workRef.base names.reverse() assignName = tuple(names) defs[assignName]=ref return defs
def _backTransform(self, outUses, block): """Transform function for the 'live variables' algorithm. """ if isinstance(block, flow.EndBlock): return self._backTransformWithEndBlock(outUses, block) astWalkerService = core.getService('ASTTreeWalker') inUses = df.LiveVariableDict(outUses) executions = list(block.executions) n = len(executions) executions.reverse() for i,execution in enumerate(executions): refs = astWalkerService.getReferencesFrom(execution) for ref in refs: if isinstance(ref, ast.Statement) and ref.type=='call' \ or isinstance(ref, ast.Call): pass # ignore calls elif isinstance(ref, ast.Reference) and ref.isFinalComponent(): isA = ref.isAssignment() name = self._getFullName(ref) # if assignment, remove all uses that match if isA is None or isA==True: # consider unknown as write if not ref.isPartial(): inUses.remove(name) # if not assignment, add this use if isA is None or isA==False: # consider unknown as read # replace the previous use loc = cf.ASTLocation(block,n-1-i,ref) inUses.add(name,loc) return inUses
def showObject(self, obj): self._clearModel() black = gtk.gdk.color_parse("black") green = gtk.gdk.color_parse("darkgreen") data = factory.getRow(obj) data[3] = black # self.root.diagram.hasObject(obj) and green or black iObj = self.model.append(None, data) resolver = core.getService('ASTTreeWalker') references = resolver.getReferencesFrom(obj) LOG.log(FINE, "Number of references for %s: %d" %(obj, len(references))) for ref in references: # generate row for subprograms only if not (isinstance(ref, ast.Statement) and ref.type=='call'\ or isinstance(ref, ast.Call)): continue astModel = ref.getModel() astScope = astModel.getScope(ref) basicModel = astModel.basicModel scope = basicModel.getObjectByASTObject(astScope) callee = basicModel.getObjectByName(ref.name.lower(), scope) if callee is not None: callObj = callee.astObject data = factory.getRow(callObj) color = black #self.root.diagram.hasObject(callObj) and green or black data[3] = color else: data = (ref.name, None, None, black) self.model.append(iObj, data) self.view.expand_row(self.model.get_path(iObj), False) self.show()
def showDefinedUses(self, target, context): ocItem = target dfService = core.getService('DataflowService') defdUses = dfService.getDefinedUses(ocItem.block) self.project.root.openUsedDefinitionsList(self, ocItem.block, defdUses)
def _reloadService(name): import sys s=core.getService(name) reload(sys.modules[s.__module__]) clazz=getattr(sys.modules[s.__module__], s.__class__.__name__) core.registerService(name, clazz())