1 cananian 1.1.2.1  // CounterFactory.java, created Wed Feb 21 14:35:40 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.Counters;
  5 cananian 1.1.2.1  
  6 cananian 1.1.2.1  import harpoon.ClassFile.HClass;
  7 cananian 1.1.2.1  import harpoon.ClassFile.HClassMutator;
  8 cananian 1.1.2.3  import harpoon.ClassFile.HCodeFactory;
  9 cananian 1.1.2.1  import harpoon.ClassFile.HField;
 10 cananian 1.1.2.1  import harpoon.ClassFile.HFieldMutator;
 11 cananian 1.1.2.3  import harpoon.ClassFile.HMethod;
 12 cananian 1.1.2.1  import harpoon.ClassFile.Linker;
 13 cananian 1.1.2.4  import harpoon.IR.Quads.CJMP;
 14 cananian 1.1.2.1  import harpoon.IR.Quads.CONST;
 15 cananian 1.1.2.1  import harpoon.IR.Quads.Edge;
 16 cananian 1.1.2.1  import harpoon.IR.Quads.GET;
 17 cananian 1.1.2.1  import harpoon.IR.Quads.MONITORENTER;
 18 cananian 1.1.2.1  import harpoon.IR.Quads.MONITOREXIT;
 19 cananian 1.1.2.1  import harpoon.IR.Quads.OPER;
 20 cananian 1.1.2.4  import harpoon.IR.Quads.PHI;
 21 cananian 1.1.2.1  import harpoon.IR.Quads.Qop;
 22 cananian 1.1.2.1  import harpoon.IR.Quads.Quad;
 23 cananian 1.1.2.1  import harpoon.IR.Quads.QuadFactory;
 24 cananian 1.1.2.1  import harpoon.IR.Quads.SET;
 25 cananian 1.1.2.1  import harpoon.Temp.Temp;
 26 cananian 1.1.2.1  import harpoon.Util.Util;
 27 cananian 1.1.2.1  
 28 cananian 1.1.2.1  import java.lang.reflect.Modifier;
 29 cananian 1.1.2.3  import java.util.Iterator;
 30 cananian 1.1.2.1  /**
 31 cananian 1.1.2.1   * <code>CounterFactory</code> is a state-less instrumentation package,
 32 cananian 1.1.2.1   * with the goal of making it as easy as possible to add counters
 33 cananian 1.1.2.1   * and timers to executable code.  It comes in several parts: we have
 34 cananian 1.1.2.1   * a set of routines to splice in counter/time calls into Quad forms,
 35 cananian 1.1.2.3   * and we have a post-processing <code>HCodeFactory</code> available
 36 cananian 1.1.2.3   * from the <code>codeFactory()</code> method that will create the
 37 cananian 1.1.2.3   * appropriate epilog code to report the counter values at
 38 cananian 1.1.2.3   * program's end.
 39 cananian 1.1.2.1   * <p>
 40 cananian 1.1.2.1   * Counters are disabled by default.  All counters can be enabled by
 41 cananian 1.1.2.1   * setting the property <code>harpoon.counters.enabled.all</code> to
 42 cananian 1.1.2.1   * <code>"true"</code> and particular counters can be enabled by
 43 cananian 1.1.2.1   * setting the property <code>harpoon.counters.enabled.{counter-name}</code>
 44 cananian 1.1.2.1   * to <code>"true"</code>.  Particular counters can be disabled by
 45 cananian 1.1.2.1   * setting the property <code>harpoon.counters.disabled.{counter-name}</code>
 46 cananian 1.1.2.1   * to <code>"true"</code> and all counters can be disabled by setting
 47 cananian 1.1.2.1   * the property <code>harpoon.counters.disabled.all</code> to
 48 cananian 1.1.2.1   * <code>"true"</code>.
 49 cananian 1.1.2.1   * <p>
 50 cananian 1.1.2.1   * Counters can also be grouped into classes by naming them with
 51 cananian 1.1.2.1   * dot-separated strings.  For example, counters named 'foo.bar'
 52 cananian 1.1.2.1   * and 'foo.baz' are both enabled by setting 
 53 cananian 1.1.2.1   * <code>harpoon.counters.enabled.foo</code> to <code>"true"</code>;
 54 cananian 1.1.2.1   * the counters' actual name on output will be "foo_bar" and "foo_baz".
 55 cananian 1.1.2.1   * 
 56 cananian 1.1.2.1   * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 57 cananian 1.4       * @version $Id: CounterFactory.java,v 1.4 2002/04/10 02:58:58 cananian Exp $
 58 cananian 1.1.2.1   */
 59 cananian 1.1.2.1  public final class CounterFactory {
 60 cananian 1.1.2.1      /** default status for all counters. */
 61 cananian 1.1.2.1      private static boolean ENABLED = false;
 62 cananian 1.1.2.1      // don't allow object creation: all methods here are static.
 63 cananian 1.1.2.1      private CounterFactory() { }
 64 cananian 1.1.2.6      /** Returns the enabled/disabled status of the given
 65 cananian 1.1.2.6       *  <code>counter_name</code>.  This can be used so that
 66 cananian 1.1.2.6       *  counter-support code may be added only when the counter
 67 cananian 1.1.2.6       *  it supports is actually enabled. */
 68 cananian 1.1.2.6      public static boolean isEnabled(String counter_name) {
 69 cananian 1.1.2.1          if (Boolean.getBoolean("harpoon.counters.enabled.all"))
 70 cananian 1.1.2.1              return true;
 71 cananian 1.1.2.1          if (Boolean.getBoolean("harpoon.counters.disabled.all"))
 72 cananian 1.1.2.1              return false;
 73 cananian 1.1.2.1          if (Boolean.getBoolean("harpoon.counters.enabled."+counter_name))
 74 cananian 1.1.2.1              return true;
 75 cananian 1.1.2.1          if (Boolean.getBoolean("harpoon.counters.disabled."+counter_name))
 76 cananian 1.1.2.1              return false;
 77 cananian 1.1.2.1          // allow 'package' enable/disable by recursing to check package status
 78 cananian 1.1.2.1          int idx = counter_name.lastIndexOf('.');
 79 cananian 1.1.2.1          if (idx>=0) return isEnabled(counter_name.substring(0, idx));
 80 cananian 1.1.2.1          // okay, can't find any guidance at all.  Use "default".
 81 cananian 1.1.2.1          return ENABLED;
 82 cananian 1.1.2.1      }
 83 cananian 1.1.2.10     public static boolean inCounters(Edge e) {
 84 cananian 1.1.2.10         Quad q = (Quad) e.from();
 85 cananian 1.1.2.10         HMethod hm = q.getFactory().getMethod();
 86 cananian 1.1.2.10         return hm.getDeclaringClass().getName().equals
 87 cananian 1.1.2.10             ("harpoon.Runtime.Counters");
 88 cananian 1.1.2.10     }
 89 cananian 1.1.2.1      
 90 cananian 1.1.2.3      /** <code>HCodeFactory</code> that will add calls to the counter-printing
 91 cananian 1.1.2.3       *  epilog at the end of the given main method and before calls to
 92 cananian 1.1.2.3       *  <code>Runtime.exit()</code>. */
 93 cananian 1.1.2.3      public static HCodeFactory codeFactory(HCodeFactory parent,
 94 cananian 1.1.2.3                                      Linker linker, HMethod main) {
 95 cananian 1.1.2.3          // check whether *any* counters are enabled.
 96 cananian 1.1.2.3          boolean enabled = ENABLED;
 97 cananian 1.1.2.3          Iterator it=System.getProperties().keySet().iterator();
 98 cananian 1.1.2.3          while (it.hasNext())
 99 cananian 1.1.2.3              if (((String)it.next()).startsWith("harpoon.counters.enabled."))
100 cananian 1.1.2.3                  enabled = true;
101 cananian 1.1.2.3          if (Boolean.getBoolean("harpoon.counters.disabled.all"))
102 cananian 1.1.2.3              enabled = false;
103 cananian 1.1.2.3          if (Boolean.getBoolean("harpoon.counters.enabled.all"))
104 cananian 1.1.2.3              enabled = true;
105 cananian 1.1.2.3          // if nothing is enabled, don't bother splicing in our code factory.
106 cananian 1.1.2.3          if (!enabled) return parent;
107 cananian 1.1.2.3          // else do it!
108 cananian 1.1.2.9          parent = new RuntimeMethodCloner(parent, linker).codeFactory();
109 cananian 1.1.2.3          return new EpilogMutator(parent, linker, main).codeFactory();
110 cananian 1.1.2.3      }
111 cananian 1.1.2.3  
112 cananian 1.1.2.1      /** Increment the named counter by 1 on the given edge. */
113 cananian 1.1.2.1      public static Edge spliceIncrement(QuadFactory qf,
114 cananian 1.1.2.1                                         Edge e, String counter_name) {
115 cananian 1.1.2.1          return spliceIncrement(qf, e, counter_name, 1);
116 cananian 1.1.2.1      }
117 cananian 1.1.2.1      /** Increment the named counter by <code>value</code> on the given edge. */
118 cananian 1.1.2.1      public static Edge spliceIncrement(QuadFactory qf,
119 cananian 1.1.2.1                                         Edge e, String counter_name,
120 cananian 1.1.2.1                                         long value) {
121 cananian 1.1.2.1          if (!isEnabled(counter_name)) return e;
122 cananian 1.1.2.10         if (inCounters(e)) return e;
123 cananian 1.1.2.1          Temp t = new Temp(qf.tempFactory());
124 cananian 1.1.2.1          return spliceIncrement(qf,
125 cananian 1.1.2.1                                 addAt(e, new CONST(qf, null, t, new Long(value),
126 cananian 1.1.2.1                                                    HClass.Long)),
127 cananian 1.1.2.5                                 counter_name, t, true);
128 cananian 1.1.2.1      }
129 cananian 1.1.2.1      /** Increment the named counter by the amount in the <code>Temp</code>
130 cananian 1.1.2.5       *  <code>Tvalue</code> on the given edge.  If <code>isLong</code>
131 cananian 1.1.2.5       *  is <code>true</code>, then <code>Tvalue</code> should have type
132 cananian 1.1.2.5       *  <code>long</code>; else it should have type <code>int</code>. */
133 cananian 1.1.2.1      public static Edge spliceIncrement(QuadFactory qf,
134 cananian 1.1.2.1                                         Edge e, String counter_name,
135 cananian 1.1.2.5                                         Temp Tvalue, boolean isLong) {
136 cananian 1.1.2.7          Quad CJMP1, CJMP2, PHI1, PHI2;
137 cananian 1.1.2.1          if (!isEnabled(counter_name)) return e;
138 cananian 1.1.2.10         if (inCounters(e)) return e;
139 cananian 1.1.2.5          if (!isLong) {
140 cananian 1.1.2.5              Temp t = new Temp(qf.tempFactory());
141 cananian 1.1.2.5              e = addAt(e, new OPER(qf, null, Qop.I2L, t, new Temp[]{ Tvalue }));
142 cananian 1.1.2.5              Tvalue = t;
143 cananian 1.1.2.5          }
144 cananian 1.1.2.1          HField HFcounter = getCounterField(qf.getLinker(), counter_name);
145 cananian 1.1.2.3          HField HFlockobj = getLockField(qf.getLinker(), counter_name);
146 cananian 1.1.2.1          // first fetch the lock
147 cananian 1.1.2.1          Temp Tlck = new Temp(qf.tempFactory());
148 cananian 1.1.2.1          e = addAt(e, new GET(qf, null, Tlck, HFlockobj, null));
149 cananian 1.1.2.7          // if package not initialized, then we're still single-threaded.
150 cananian 1.1.2.7          // (i.e., we can safely skip the monitorenter)
151 cananian 1.1.2.4          Temp Tnul = new Temp(qf.tempFactory());
152 cananian 1.1.2.4          e = addAt(e, new CONST(qf, null, Tnul, null, HClass.Void));
153 cananian 1.1.2.4          Temp Tcmp = new Temp(qf.tempFactory());
154 cananian 1.1.2.4          e = addAt(e, new OPER(qf, null, Qop.ACMPEQ, Tcmp,
155 cananian 1.1.2.4                                new Temp[] { Tlck, Tnul }));
156 cananian 1.1.2.7          e = addAt(e, CJMP1=new CJMP(qf, null, Tcmp, new Temp[0]));
157 cananian 1.1.2.7          // lock if we can.
158 cananian 1.1.2.1          e = addAt(e, new MONITORENTER(qf, null, Tlck));
159 cananian 1.1.2.7          e = addAt(e, PHI1=new PHI(qf, null, new Temp[0], 2));
160 cananian 1.1.2.1          // then fetch the old counter value
161 cananian 1.1.2.1          Temp Tcnt = new Temp(qf.tempFactory());
162 cananian 1.1.2.1          e = addAt(e, new GET(qf, null, Tcnt, HFcounter, null));
163 cananian 1.1.2.1          // increment it, consistent with SSx forms.
164 cananian 1.1.2.1          Temp Tcnt2 = new Temp(qf.tempFactory());
165 cananian 1.1.2.1          e = addAt(e, new OPER(qf, null, Qop.LADD, Tcnt2,
166 cananian 1.1.2.1                                new Temp[] { Tcnt, Tvalue}));
167 cananian 1.1.2.1          // and store it back.
168 cananian 1.1.2.1          e = addAt(e, new SET(qf, null, HFcounter, null, Tcnt2));
169 cananian 1.1.2.7          // now release the lock (if we need to)
170 cananian 1.1.2.7          e = addAt(e, CJMP2=new CJMP(qf, null, Tcmp, new Temp[0]));
171 cananian 1.1.2.1          e = addAt(e, new MONITOREXIT(qf, null, Tlck));
172 cananian 1.1.2.4          // merge from bypass.
173 cananian 1.1.2.7          e = addAt(e, PHI2=new PHI(qf, null, new Temp[0], 2));
174 cananian 1.1.2.7          Quad.addEdge(CJMP1, 1, PHI1, 1);
175 cananian 1.1.2.7          Quad.addEdge(CJMP2, 1, PHI2, 1);
176 cananian 1.1.2.1          // done!
177 cananian 1.1.2.1          return e;
178 cananian 1.1.2.1      }
179 cananian 1.1.2.1  
180 cananian 1.1.2.1      // get counter and lock field, creating it if necessary.
181 cananian 1.1.2.1      static HField getCounterField(Linker l, String counter_name) {
182 cananian 1.1.2.1          return getField(l, "COUNTER_"+counter_name, "J");
183 cananian 1.1.2.1      }
184 cananian 1.1.2.1      static HField getLockField(Linker l, String counter_name) {
185 cananian 1.1.2.1          return getField(l, "LOCK_"+counter_name, "Ljava/lang/Object;");
186 cananian 1.1.2.1      }
187 cananian 1.1.2.1      private static HField getField(Linker l, String name, String descriptor) {
188 cananian 1.1.2.1          HClass hc = l.forName("harpoon.Runtime.Counters");
189 cananian 1.1.2.1          name = name.replace('.','_'); // allow '.' in name, but strip.
190 cananian 1.1.2.7          name = name.replace('-','_'); // likewise for '-'
191 cananian 1.1.2.1          try {
192 cananian 1.1.2.1            HField hf = hc.getDeclaredField(name);
193 cananian 1.3.2.1            assert hf.getDescriptor().equals(descriptor);
194 cananian 1.3.2.1            assert hf.isStatic();
195 cananian 1.1.2.1            return hf;
196 cananian 1.1.2.1          } catch (NoSuchFieldError e) {
197 cananian 1.1.2.1            // okay, have to create this field ourselves.
198 cananian 1.1.2.1            HField hf = hc.getMutator().addDeclaredField(name, descriptor);
199 cananian 1.1.2.1            // make public and static
200 cananian 1.1.2.1            hf.getMutator().setModifiers(Modifier.PUBLIC | Modifier.STATIC);
201 cananian 1.1.2.1            return hf;
202 cananian 1.1.2.1          }
203 cananian 1.1.2.1      }
204 cananian 1.1.2.1  
205 cananian 1.1.2.1      // private helper functions.
206 cananian 1.1.2.1      private static Edge addAt(Edge e, Quad q) { return addAt(e, 0, q, 0); }
207 cananian 1.1.2.1      private static Edge addAt(Edge e, int which_pred, Quad q, int which_succ) {
208 cananian 1.1.2.1              Quad frm = (Quad) e.from(); int frm_succ = e.which_succ();
209 cananian 1.1.2.1              Quad to  = (Quad) e.to();   int to_pred = e.which_pred();
210 cananian 1.1.2.1              Quad.addEdge(frm, frm_succ, q, which_pred);
211 cananian 1.1.2.1              Quad.addEdge(q, which_succ, to, to_pred);
212 cananian 1.1.2.1              return to.prevEdge(to_pred);
213 cananian 1.1.2.1          }
214 cananian 1.2      }