From 46d62cb6d7e78a8ea8a0dcfefd17da99907652be Mon Sep 17 00:00:00 2001 From: bdemsky Date: Sat, 18 Apr 2009 00:58:57 +0000 Subject: [PATCH] computes which types can actually refer to the same objects as other types --- .../src/Analysis/Locality/TypeAnalysis.java | 180 ++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 Robust/src/Analysis/Locality/TypeAnalysis.java diff --git a/Robust/src/Analysis/Locality/TypeAnalysis.java b/Robust/src/Analysis/Locality/TypeAnalysis.java new file mode 100644 index 00000000..beba8203 --- /dev/null +++ b/Robust/src/Analysis/Locality/TypeAnalysis.java @@ -0,0 +1,180 @@ +package Analysis.Locality; + +import IR.Flat.*; +import java.util.Set; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Hashtable; +import Analysis.CallGraph.CallGraph; +import IR.State; +import IR.TypeUtil; +import IR.Operation; +import IR.TypeDescriptor; +import IR.MethodDescriptor; +import IR.FieldDescriptor; + +public class TypeAnalysis { + /* This analysis is essentially a dataflow analysis. + */ + LocalityAnalysis locality; + State state; + TypeUtil typeutil; + CallGraph cg; + Hashtable> map; + HashSet roottypes; + Hashtable> transmap; + Hashtable> namemap; + + public TypeAnalysis(LocalityAnalysis locality, State state, TypeUtil typeutil, CallGraph cg) { + this.state=state; + this.locality=locality; + this.typeutil=typeutil; + this.cg=cg; + map=new Hashtable>(); + transmap=new Hashtable>(); + namemap=new Hashtable>(); + roottypes=new HashSet(); + doAnalysis(); + } + + /* We use locality bindings to get calleable methods. This could be + * changed to use the callgraph starting from the main method. */ + + void doAnalysis() { + Set localityset=locality.getLocalityBindings(); + for(Iterator lb=localityset.iterator();lb.hasNext();) { + computeTypes(lb.next().getMethod()); + } + computeTrans(); + computeOtherNames(); + } + + void computeOtherNames() { + for(Iterator it=transmap.keySet().iterator();it.hasNext();) { + TypeDescriptor td=it.next(); + Set set=transmap.get(td); + for(Iterator it2=set.iterator();it2.hasNext();) { + TypeDescriptor type=it2.next(); + if (!namemap.containsKey(type)) + namemap.put(type, new HashSet()); + namemap.get(type).addAll(set); + } + } + } + + void computeTrans() { + //Idea: for each type we want to know all of the possible types it could be called + for(Iterator it=roottypes.iterator();it.hasNext();) { + TypeDescriptor td=it.next(); + HashSet tovisit=new HashSet(); + transmap.put(td, new HashSet()); + tovisit.add(td); + transmap.get(td).add(td); + + while(!tovisit.isEmpty()) { + TypeDescriptor type=tovisit.iterator().next(); + tovisit.remove(type); + //Is type a supertype of td...if not skip along + if (!typeutil.isSuperorType(type,td)) + continue; + //Check if we have seen it before + if (!transmap.get(td).contains(type)) { + //If not, add to set and continue processing + transmap.get(td).add(type); + tovisit.add(type); + } + } + } + } + + public Set expand(TypeDescriptor td) { + return namemap.get(td); + } + + public void addMapping(TypeDescriptor src, TypeDescriptor dst) { + if (!map.containsKey(src)) + map.put(src, new HashSet()); + map.get(src).add(dst); + } + + void computeTypes(MethodDescriptor md) { + FlatMethod fm=state.getMethodFlat(md); + for(Iterator fnit=fm.getNodeSet().iterator();fnit.hasNext();) { + FlatNode fn=fnit.next(); + switch(fn.kind()) { + case FKind.FlatOpNode: { + FlatOpNode fon=(FlatOpNode)fn; + if(fon.getOp().getOp()==Operation.ASSIGN) { + addMapping(fon.getLeft().getType(),fon.getDest().getType()); + } + break; + } + case FKind.FlatNew: { + FlatNew fnew=(FlatNew)fn; + roottypes.add(fnew.getType()); + break; + } + case FKind.FlatCastNode: { + FlatCastNode fcn=(FlatCastNode)fn; + addMapping(fcn.getSrc().getType(), fcn.getDst().getType()); + break; + } + case FKind.FlatFieldNode: { + FlatFieldNode ffn=(FlatFieldNode)fn; + addMapping(ffn.getField().getType(), ffn.getDst().getType()); + break; + } + case FKind.FlatSetFieldNode: { + FlatSetFieldNode fsfn=(FlatSetFieldNode) fn; + addMapping(fsfn.getSrc().getType(), fsfn.getField().getType()); + break; + } + case FKind.FlatElementNode: { + FlatElementNode fen=(FlatElementNode)fn; + addMapping(fen.getSrc().getType().dereference(), fen.getDst().getType()); + break; + } + case FKind.FlatSetElementNode: { + FlatSetElementNode fsen=(FlatSetElementNode)fn; + addMapping(fsen.getSrc().getType(), fsen.getDst().getType().dereference()); + break; + } + case FKind.FlatCall: { + FlatCall fc=(FlatCall)fn; + if (fc.getReturnTemp()!=null) { + addMapping(fc.getMethod().getReturnType(), fc.getReturnTemp().getType()); + } + if (fc.getThis()!=null) { + //complicated...need to deal with virtual dispatch here + MethodDescriptor callmd=fc.getMethod(); + Set methods=cg.getMethods(callmd); + for(Iterator mdit=methods.iterator();mdit.hasNext();) { + MethodDescriptor md2=(MethodDescriptor)mdit.next(); + if (fc.getThis()!=null) { + TypeDescriptor ttype=new TypeDescriptor(md2.getClassDesc()); + if (!typeutil.isSuperorType(fc.getThis().getType(),ttype)&& + !typeutil.isSuperorType(ttype,fc.getThis().getType())) + continue; + addMapping(fc.getThis().getType(), ttype); + } + } + } + for(int i=0;i