1 salcianu 1.1 // CachingCallGraph.java, created Tue Apr  2 19:16:43 2002 by salcianu
  2 salcianu 1.1 // Copyright (C) 2000 Alexandru SALCIANU <salcianu@MIT.EDU>
  3 salcianu 1.1 // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 salcianu 1.1 package harpoon.Analysis.Quads;
  5 salcianu 1.1 
  6 salcianu 1.1 import java.util.Set;
  7 salcianu 1.1 import java.util.Map;
  8 salcianu 1.1 import java.util.HashMap;
  9 salcianu 1.2 import java.util.Iterator;
 10 salcianu 1.1 
 11 salcianu 1.1 import harpoon.ClassFile.HMethod;
 12 salcianu 1.1 import harpoon.IR.Quads.CALL;
 13 salcianu 1.1 
 14 salcianu 1.1 /** <code>CachingCallGraph</code> is a caching wrapper for a call
 15 salcianu 1.1     graph.  In general, multiple stages in the compiler will use the
 16 salcianu 1.1     call graph so it is good to cache it.  You should manually take
 17 salcianu 1.1     care of constructing a new call graph when you modify the code in
 18 salcianu 1.1     some way that might invalidate the old call graph.
 19 salcianu 1.1 
 20 salcianu 1.1     @author  Alexandru SALCIANU <salcianu@MIT.EDU>
 21 cananian 1.5     @version $Id: CachingCallGraph.java,v 1.5 2004/02/08 03:20:10 cananian Exp $ */
 22 salcianu 1.4 public class CachingCallGraph extends CallGraph {
 23 salcianu 1.1     
 24 salcianu 1.1     /** Creates a <code>CachingCallGraph</code> that caches the results
 25 salcianu 1.1         of <code>cg</code>.
 26 salcianu 1.1 
 27 salcianu 1.1         @param cg underlying call graph (the one actually doing the job)
 28 salcianu 1.1         @param m_cache specifies whether to cache the results of
 29 salcianu 1.1         <code>calls(HMethod hm)</code>
 30 salcianu 1.1         @param cs_cache specifies whether to cache the results of
 31 salcianu 1.1         <code>calls(HMethod hm, CALL cs)</code>   */
 32 salcianu 1.1     public CachingCallGraph(CallGraph cg, boolean m_cache, boolean cs_cache) {
 33 salcianu 1.1         constr(cg, m_cache, cs_cache);
 34 salcianu 1.1     }
 35 salcianu 1.1 
 36 salcianu 1.1     // does the real job for a constructor
 37 salcianu 1.1     private void constr(CallGraph cg, boolean m_cache, boolean cs_cache) {
 38 salcianu 1.1         this.cg = cg;
 39 salcianu 1.1         this.m_cache  = m_cache;
 40 salcianu 1.1         this.cs_cache = cs_cache;
 41 salcianu 1.1 
 42 salcianu 1.1         if(m_cache)  m2callees  = new HashMap();
 43 salcianu 1.1         if(cs_cache) cs2callees = new HashMap();
 44 salcianu 1.1     }
 45 salcianu 1.1 
 46 salcianu 1.1     /** Convenient to use constructor. If <code>cg</code> is a
 47 salcianu 1.1         subclass of <code>CallGraphImpl</code>, it is equivalent to
 48 salcianu 1.1         <code>CallGraphImpl(cg, false, true)</code>
 49 salcianu 1.1         (<code>CallGraphImpl</code> already caches the callees of a method.
 50 salcianu 1.1         Otherwise, it is equivalent to
 51 salcianu 1.1         <code>CallGraphImpl(cg, true, true)</code> (full caching).
 52 salcianu 1.1 
 53 salcianu 1.1         @param cg underlying call graph */
 54 salcianu 1.1     public CachingCallGraph(CallGraph cg) {
 55 salcianu 1.1         // funny thing: the use of this(...) to call another constructor
 56 salcianu 1.1         // is restricted to the first line, so we cannot use it here.
 57 salcianu 1.1         if(cg instanceof CallGraphImpl)
 58 salcianu 1.1             constr(cg, false, true);
 59 salcianu 1.1         else
 60 salcianu 1.1             constr(cg, true, true);
 61 salcianu 1.1     }
 62 salcianu 1.1 
 63 salcianu 1.1     private CallGraph cg;     // underlying call graph
 64 salcianu 1.1     private boolean m_cache;  // should we cache calls(hm) ?
 65 salcianu 1.1     private Map m2callees;    // cache for calls(hm)
 66 salcianu 1.1     private boolean cs_cache; // should we cache calls(hm, call) ?
 67 salcianu 1.1     private Map cs2callees;   // cache for calls(hm, call)
 68 salcianu 1.1     
 69 salcianu 1.1     public HMethod[] calls(final HMethod hm) {
 70 salcianu 1.1         if(!m_cache) return cg.calls(hm);
 71 salcianu 1.1 
 72 salcianu 1.1         HMethod[] result = (HMethod[]) m2callees.get(hm);
 73 salcianu 1.1         if(result == null) {
 74 salcianu 1.1             result = cg.calls(hm);
 75 salcianu 1.1             m2callees.put(hm, result);
 76 salcianu 1.1         }
 77 salcianu 1.1         return result;
 78 salcianu 1.1     }
 79 salcianu 1.1 
 80 salcianu 1.1     public HMethod[] calls(final HMethod hm, final CALL cs) {
 81 salcianu 1.1         if(!cs_cache) return cg.calls(hm, cs);
 82 salcianu 1.1 
 83 salcianu 1.1         HMethod[] result = (HMethod[]) cs2callees.get(cs);
 84 salcianu 1.1         if(result == null) {
 85 salcianu 1.1             result = cg.calls(hm, cs);
 86 salcianu 1.1             cs2callees.put(cs, result);
 87 salcianu 1.1         }
 88 salcianu 1.1         return result;
 89 salcianu 1.1     }
 90 salcianu 1.1 
 91 salcianu 1.1     public CALL[] getCallSites(HMethod hm) {
 92 salcianu 1.1         return cg.getCallSites(hm);
 93 salcianu 1.1     }
 94 salcianu 1.1 
 95 salcianu 1.1     public Set callableMethods() {
 96 salcianu 1.1         return cg.callableMethods();
 97 salcianu 1.2     }
 98 salcianu 1.2 
 99 salcianu 1.3     public Set getRunMethods() {
100 salcianu 1.3         return cg.getRunMethods();
101 salcianu 1.3     }
102 salcianu 1.3 
103 salcianu 1.2     public void load_caches() {
104 cananian 1.5         for(Object hmO : callableMethods()) {
105 cananian 1.5             HMethod hm = (HMethod) hmO;
106 salcianu 1.2             
107 salcianu 1.3             if(m_cache || (cg instanceof CallGraphImpl)) calls(hm);
108 salcianu 1.2             if(cs_cache) {
109 salcianu 1.2                 CALL[] calls = getCallSites(hm);
110 salcianu 1.2                 for(int i = 0; i < calls.length; i++)
111 salcianu 1.2                     calls(hm, calls[i]);
112 salcianu 1.2             }
113 salcianu 1.2         }
114 salcianu 1.1     }
115 salcianu 1.1 
116 salcianu 1.1 }