1 cananian 1.1.2.1 // SmallMethodInliner.java, created Mon Jun 18 13:28:16 2001 by cananian 2 cananian 1.1.2.1 // Copyright (C) 2000 C. Scott Ananian <cananian@alumni.princeton.edu> 3 cananian 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 cananian 1.1.2.1 package harpoon.Analysis.Quads; 5 cananian 1.1.2.1 6 cananian 1.1.2.1 import harpoon.Analysis.ClassHierarchy; 7 cananian 1.1.2.1 import harpoon.ClassFile.CachingCodeFactory; 8 cananian 1.1.2.1 import harpoon.ClassFile.HCode; 9 cananian 1.1.2.1 import harpoon.ClassFile.HCodeFactory; 10 cananian 1.1.2.1 import harpoon.ClassFile.HMethod; 11 cananian 1.1.2.1 import harpoon.IR.Quads.CALL; 12 cananian 1.1.2.1 import harpoon.IR.Quads.Quad; 13 cananian 1.6 import net.cscott.jutil.BinaryHeap; 14 cananian 1.6 import net.cscott.jutil.GenericMultiMap; 15 cananian 1.6 import net.cscott.jutil.Heap; 16 cananian 1.6 import net.cscott.jutil.MultiMap; 17 cananian 1.1.2.1 18 cananian 1.1.2.1 import java.lang.reflect.Modifier; 19 cananian 1.1.2.1 import java.util.Collection; 20 cananian 1.1.2.1 import java.util.HashMap; 21 cananian 1.1.2.1 import java.util.Iterator; 22 cananian 1.1.2.1 import java.util.List; 23 cananian 1.1.2.2 import java.util.Map; 24 cananian 1.1.2.1 import java.util.Set; 25 cananian 1.1.2.1 /** 26 cananian 1.1.2.1 * <code>SmallMethodInliner</code> will inline small methods until 27 cananian 1.1.2.1 * the code is bloated by the specified amount. 28 cananian 1.1.2.1 * 29 cananian 1.1.2.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 30 cananian 1.7 * @version $Id: SmallMethodInliner.java,v 1.7 2004/02/08 03:20:10 cananian Exp $ 31 cananian 1.1.2.1 */ 32 cananian 1.1.2.1 public class SmallMethodInliner extends MethodInliningCodeFactory { 33 salcianu 1.5 static final int NPERCENT= // default to 25 percent bloat. 34 cananian 1.1.2.3 Integer.parseInt(System.getProperty("harpoon.inliner.percent", "25")); 35 cananian 1.1.2.1 36 cananian 1.1.2.1 /** Creates a <code>SmallMethodInliner</code>. */ 37 cananian 1.1.2.1 public SmallMethodInliner(HCodeFactory hcf, ClassHierarchy ch) { 38 cananian 1.1.2.1 this(new CachingCodeFactory(hcf), ch); 39 cananian 1.1.2.1 } 40 cananian 1.1.2.1 // scan ccf for appropriate call sites. 41 cananian 1.1.2.1 private SmallMethodInliner(CachingCodeFactory ccf, ClassHierarchy ch) { 42 cananian 1.1.2.1 super(ccf); 43 cananian 1.1.2.1 long totalsize = 0; 44 cananian 1.1.2.2 45 cananian 1.1.2.2 IntMap methodSize = new IntMap(); 46 cananian 1.1.2.2 MultiMap callSites = new GenericMultiMap(); 47 cananian 1.1.2.2 Map call2caller = new HashMap(); 48 cananian 1.1.2.2 49 cananian 1.7 for (Object hmO : ch.callableMethods()) { 50 cananian 1.7 HMethod hm = (HMethod) hmO; 51 cananian 1.1.2.1 HCode hc = ccf.convert(hm); 52 cananian 1.1.2.1 // determine method sizes 53 cananian 1.1.2.1 if (hc==null) continue; 54 cananian 1.1.2.1 // size-4: CALL, HEADER, FOOTER, METHOD. 55 cananian 1.1.2.1 methodSize.putInt(hm, hc.getElementsL().size()-4); 56 cananian 1.1.2.1 // find call sites. 57 cananian 1.1.2.1 for (Iterator it2=hc.getElementsI(); it2.hasNext(); ) { 58 cananian 1.1.2.1 Quad q = (Quad) it2.next(); 59 cananian 1.1.2.1 if (!(q instanceof CALL)) continue; 60 cananian 1.1.2.1 CALL call = (CALL) q; 61 cananian 1.1.2.1 if (call.isVirtual()) continue; 62 cananian 1.1.2.1 callSites.add(call.method(), call); 63 cananian 1.1.2.2 call2caller.put(call, hm); 64 cananian 1.1.2.1 } 65 cananian 1.1.2.1 // keep track of total program size 66 cananian 1.1.2.1 totalsize+=methodSize.getInt(hm); 67 cananian 1.1.2.1 } 68 cananian 1.1.2.2 Heap h = new BinaryHeap(); 69 cananian 1.1.2.2 Map method2entry = new HashMap(); 70 cananian 1.7 for (Object hmO : ch.callableMethods()) { 71 cananian 1.7 HMethod hm = (HMethod) hmO; 72 cananian 1.1.2.2 // compute score for hm. 73 cananian 1.1.2.2 int score = score(hm, methodSize, callSites); 74 cananian 1.1.2.2 // add to heap, and to method-to-entry map. 75 cananian 1.1.2.2 if (callSites.getValues(hm).size()>0) // unless no sites to inline 76 cananian 1.1.2.2 method2entry.put(hm, h.insert(new Integer(score), hm)); 77 cananian 1.1.2.2 } 78 cananian 1.1.2.1 // inline to bloat the program by the specified percentage of 79 cananian 1.1.2.1 // total program size. 80 cananian 1.1.2.1 long bloat = 0; 81 cananian 1.1.2.2 while (bloat < (NPERCENT*totalsize/100)) { 82 cananian 1.1.2.2 if (h.isEmpty()) break; 83 cananian 1.1.2.2 HMethod hm = (HMethod) h.extractMinimum().getValue();//inline this! 84 cananian 1.1.2.2 method2entry.remove(hm); 85 cananian 1.1.2.1 if (Modifier.isNative(hm.getModifiers())) continue;//unless native 86 cananian 1.1.2.1 int size = methodSize.getInt(hm); 87 cananian 1.1.2.2 Iterator it2=callSites.getValues(hm).iterator(); 88 cananian 1.1.2.2 if (it2.hasNext()) 89 cananian 1.1.2.2 System.err.println("INLINING all nonvirtual calls to "+hm); 90 cananian 1.1.2.1 while (it2.hasNext()) { 91 cananian 1.1.2.2 CALL call = (CALL) it2.next(); 92 cananian 1.1.2.2 inline(call); 93 cananian 1.1.2.1 bloat+=size; 94 cananian 1.1.2.2 // add 'size' to caller's method size... 95 cananian 1.1.2.2 HMethod caller = (HMethod) call2caller.get(call); 96 cananian 1.1.2.2 methodSize.putInt(caller, methodSize.getInt(caller)+size); 97 cananian 1.1.2.2 // ...and adjust caller's key in pqueue. 98 cananian 1.1.2.2 Map.Entry me = (Map.Entry) method2entry.get(caller); 99 cananian 1.1.2.2 if (me!=null) { 100 cananian 1.1.2.2 int score = score(hm, methodSize, callSites); 101 cananian 1.1.2.2 h.updateKey(me, new Integer(score)); 102 cananian 1.1.2.2 } 103 cananian 1.1.2.1 } 104 cananian 1.1.2.1 } 105 cananian 1.1.2.1 // done! 106 cananian 1.1.2.2 System.out.println("ACTUAL INLINING BLOAT: " + 107 cananian 1.1.2.2 ((1+2*100*bloat)/(2*totalsize)) + "%"); 108 cananian 1.1.2.1 } 109 wbeebee 1.3 110 wbeebee 1.3 /** Override this if you want to define your own scoring function 111 wbeebee 1.3 * for inlining methods. 112 wbeebee 1.3 */ 113 wbeebee 1.3 protected int score(HMethod hm, IntMap methodSize, MultiMap callSites) 114 cananian 1.1.2.2 { 115 cananian 1.1.2.1 return methodSize.getInt(hm) * callSites.getValues(hm).size(); 116 cananian 1.1.2.1 } 117 cananian 1.1.2.1 118 wbeebee 1.4 protected static class IntMap extends HashMap { 119 cananian 1.1.2.1 IntMap() { super(); } 120 cananian 1.1.2.1 int getInt(Object key) { 121 cananian 1.1.2.1 Integer i = (Integer) get(key); 122 cananian 1.1.2.1 return (i==null)?0:i.intValue(); 123 cananian 1.1.2.1 } 124 cananian 1.1.2.1 void putInt(Object key, int val) { 125 cananian 1.1.2.1 put(key, new Integer(val)); 126 cananian 1.1.2.1 } 127 cananian 1.1.2.1 } 128 cananian 1.2 }