Fix tabbing.... Please fix your editors so they do tabbing correctly!!! (Spaces...
[IRC.git] / Robust / src / IR / Flat / Inliner.java
1 package IR.Flat;
2 import java.util.Hashtable;
3 import java.util.Set;
4 import java.util.HashSet;
5 import java.util.Stack;
6 import java.util.Iterator;
7 import IR.ClassDescriptor;
8 import IR.Operation;
9 import IR.State;
10 import IR.TypeUtil;
11 import IR.MethodDescriptor;
12
13 public class Inliner {
14   public static void inlineAtomic(State state, TypeUtil typeutil, FlatMethod fm, int depth) {
15     Stack<FlatNode> toprocess=new Stack<FlatNode>();
16     HashSet<FlatNode> visited=new HashSet<FlatNode>();
17     Hashtable<FlatNode, Integer> atomictable=new Hashtable<FlatNode, Integer>();
18     HashSet<FlatNode> atomicset=new HashSet<FlatNode>();
19
20     toprocess.push(fm);
21     visited.add(fm);
22     atomictable.put(fm, new Integer(0));
23     while(!toprocess.isEmpty()) {
24       FlatNode fn=toprocess.pop();
25       int atomicval=atomictable.get(fn).intValue();
26       if (fn.kind()==FKind.FlatAtomicEnterNode)
27         atomicval++;
28       else if(fn.kind()==FKind.FlatAtomicExitNode)
29         atomicval--;
30       for(int i=0; i<fn.numNext(); i++) {
31         FlatNode fnext=fn.getNext(i);
32         if (!visited.contains(fnext)) {
33           atomictable.put(fnext, new Integer(atomicval));
34           if (atomicval>0)
35             atomicset.add(fnext);
36           visited.add(fnext);
37           toprocess.push(fnext);
38         }
39       }
40     }
41     //make depth 0 be depth infinity
42     if (depth==0)
43       depth=10000000;
44     if (atomicset.isEmpty())
45       return;
46     System.out.println("Inlining methods into "+fm.getMethod());
47     recursive(state, typeutil, atomicset, depth, new Stack<MethodDescriptor>());
48   }
49
50
51   public static void recursive(State state, TypeUtil typeutil, Set<FlatNode> fnset, int depth, Stack<MethodDescriptor> toexclude) {
52     for(Iterator<FlatNode> fnit=fnset.iterator(); fnit.hasNext(); ) {
53       FlatNode fn=fnit.next();
54       if (fn.kind()==FKind.FlatCall) {
55         FlatCall fc=(FlatCall)fn;
56         MethodDescriptor md=fc.getMethod();
57
58         if (toexclude.contains(md))
59           continue;
60
61         Set<FlatNode> inlinefnset=inline(fc, typeutil, state);
62         if (inlinefnset==null)
63           continue;
64
65         toexclude.push(md);
66         if (depth>1)
67           recursive(state, typeutil, inlinefnset, depth-1, toexclude);
68         toexclude.pop();
69       }
70     }
71   }
72
73   public static Set<FlatNode> inline(FlatCall fc, TypeUtil typeutil, State state) {
74     MethodDescriptor md=fc.getMethod();
75     if (md.getModifiers().isNative())
76       return null;
77
78     /* Do we need to do virtual dispatch? */
79     if (md.isStatic()||md.getReturnType()==null||singleCall(typeutil, fc.getThis().getType().getClassDesc(),md)) {
80       //just reuse temps...makes problem with inlining recursion
81       TempMap clonemap=new TempMap();
82       Hashtable<FlatNode, FlatNode> flatmap=new Hashtable<FlatNode, FlatNode>();
83       TempDescriptor rettmp=fc.getReturnTemp();
84       FlatNode aftercallnode=fc.getNext(0);
85       aftercallnode.removePrev(fc);
86       System.out.println("Inlining: "+md);
87
88       FlatMethod fm=state.getMethodFlat(md);
89       //Clone nodes
90       Set<FlatNode> nodeset=fm.getNodeSet();
91       nodeset.remove(fm);
92
93       HashSet<FlatNode> newnodes=new HashSet<FlatNode>();
94
95       //Build the clones
96       for(Iterator<FlatNode> fnit=nodeset.iterator(); fnit.hasNext(); ) {
97         FlatNode fn=fnit.next();
98         if (fn.kind()==FKind.FlatReturnNode) {
99           //Convert FlatReturn node into move
100           TempDescriptor rtmp=((FlatReturnNode)fn).getReturnTemp();
101           if (rtmp!=null) {
102             FlatOpNode fon=new FlatOpNode(rettmp, rtmp, null, new Operation(Operation.ASSIGN));
103             flatmap.put(fn, fon);
104           } else {
105             flatmap.put(fn, aftercallnode);
106           }
107         } else {
108           FlatNode clone=fn.clone(clonemap);
109           newnodes.add(clone);
110           flatmap.put(fn,clone);
111         }
112       }
113       //Build the move chain
114       FlatNode first=new FlatNop();;
115       newnodes.add(first);
116       FlatNode last=first;
117       {
118         int i=0;
119         if (fc.getThis()!=null) {
120           FlatOpNode fon=new FlatOpNode(fm.getParameter(i++), fc.getThis(), null, new Operation(Operation.ASSIGN));
121           newnodes.add(fon);
122           last.addNext(fon);
123           last=fon;
124         }
125         for(int j=0; j<fc.numArgs(); i++,j++) {
126           FlatOpNode fon=new FlatOpNode(fm.getParameter(i), fc.getArg(j), null, new Operation(Operation.ASSIGN));
127           newnodes.add(fon);
128           last.addNext(fon);
129           last=fon;
130         }
131       }
132
133       //Add the edges
134       for(Iterator<FlatNode> fnit=nodeset.iterator(); fnit.hasNext(); ) {
135         FlatNode fn=fnit.next();
136         FlatNode fnclone=flatmap.get(fn);
137
138         if (fn.kind()!=FKind.FlatReturnNode) {
139           //don't build old edges out of a flat return node
140           for(int i=0; i<fn.numNext(); i++) {
141             FlatNode fnnext=fn.getNext(i);
142             FlatNode fnnextclone=flatmap.get(fnnext);
143             fnclone.setNewNext(i, fnnextclone);
144           }
145         } else {
146           if (fnclone!=aftercallnode)
147             fnclone.addNext(aftercallnode);
148         }
149       }
150
151       //Add edges to beginning of move chain
152       for(int i=0; i<fc.numPrev(); i++) {
153         FlatNode fnprev=fc.getPrev(i);
154         for(int j=0; j<fnprev.numNext(); j++) {
155           if (fnprev.getNext(j)==fc) {
156             //doing setnewnext to avoid changing the node we are
157             //iterating over
158             fnprev.setNewNext(j, first);
159             break;
160           }
161         }
162       }
163
164       //Add in the edge from move chain to callee
165       last.addNext(flatmap.get(fm.getNext(0)));
166       return newnodes;
167     } else return null;
168   }
169
170   private static boolean singleCall(TypeUtil typeutil, ClassDescriptor thiscd, MethodDescriptor md) {
171     Set subclasses=typeutil.getSubClasses(thiscd);
172     if (subclasses==null)
173       return true;
174     for(Iterator classit=subclasses.iterator(); classit.hasNext(); ) {
175       ClassDescriptor cd=(ClassDescriptor)classit.next();
176       Set possiblematches=cd.getMethodTable().getSet(md.getSymbol());
177       for(Iterator matchit=possiblematches.iterator(); matchit.hasNext(); ) {
178         MethodDescriptor matchmd=(MethodDescriptor)matchit.next();
179         if (md.matches(matchmd))
180           return false;
181       }
182     }
183     return true;
184   }
185 }