1 cananian 1.1.2.1  // InitializerTransform.java, created Tue Oct 17 14:35:29 2000 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.7  import harpoon.Analysis.ClassHierarchy;
  7 cananian 1.1.2.9  import harpoon.ClassFile.CachingCodeFactory;
  8 cananian 1.1.2.4  import harpoon.ClassFile.HClass;
  9 cananian 1.1.2.4  import harpoon.ClassFile.HClassMutator;
 10 cananian 1.1.2.4  import harpoon.ClassFile.HCode;
 11 cananian 1.1.2.4  import harpoon.ClassFile.HCodeAndMaps;
 12 cananian 1.1.2.4  import harpoon.ClassFile.HCodeFactory;
 13 cananian 1.1.2.11 import harpoon.ClassFile.HConstructor;
 14 cananian 1.1.2.4  import harpoon.ClassFile.HField;
 15 cananian 1.1.2.4  import harpoon.ClassFile.HFieldMutator;
 16 cananian 1.1.2.4  import harpoon.ClassFile.HInitializer;
 17 cananian 1.1.2.4  import harpoon.ClassFile.HMethod;
 18 cananian 1.1.2.9  import harpoon.ClassFile.Linker;
 19 cananian 1.1.2.9  import harpoon.ClassFile.NoSuchClassException;
 20 cananian 1.1.2.14 import harpoon.ClassFile.SerializableCodeFactory;
 21 cananian 1.1.2.4  import harpoon.IR.Quads.ANEW;
 22 cananian 1.1.2.4  import harpoon.IR.Quads.CALL;
 23 cananian 1.1.2.4  import harpoon.IR.Quads.CJMP;
 24 cananian 1.1.2.11 import harpoon.IR.Quads.CONST;
 25 cananian 1.1.2.4  import harpoon.IR.Quads.Code;
 26 cananian 1.1.2.4  import harpoon.IR.Quads.Edge;
 27 cananian 1.1.2.4  import harpoon.IR.Quads.FOOTER;
 28 cananian 1.1.2.4  import harpoon.IR.Quads.GET;
 29 cananian 1.1.2.4  import harpoon.IR.Quads.HEADER;
 30 cananian 1.1.2.4  import harpoon.IR.Quads.METHOD;
 31 cananian 1.1.2.17 import harpoon.IR.Quads.MONITORENTER;
 32 cananian 1.1.2.17 import harpoon.IR.Quads.MONITOREXIT;
 33 cananian 1.1.2.4  import harpoon.IR.Quads.NEW;
 34 cananian 1.1.2.4  import harpoon.IR.Quads.PHI;
 35 cananian 1.1.2.4  import harpoon.IR.Quads.Quad;
 36 cananian 1.1.2.4  import harpoon.IR.Quads.QuadFactory;
 37 cananian 1.1.2.4  import harpoon.IR.Quads.QuadVisitor;
 38 cananian 1.1.2.4  import harpoon.IR.Quads.QuadWithTry;
 39 cananian 1.1.2.4  import harpoon.IR.Quads.RETURN;
 40 cananian 1.1.2.4  import harpoon.IR.Quads.SET;
 41 cananian 1.1.2.1  import harpoon.Temp.Temp;
 42 cananian 1.5      import net.cscott.jutil.Default;
 43 cananian 1.5      import net.cscott.jutil.Environment;
 44 cananian 1.5      import net.cscott.jutil.HashEnvironment;
 45 cananian 1.1.2.16 import harpoon.Util.ParseUtil;
 46 cananian 1.1.2.4  import harpoon.Util.Util;
 47 cananian 1.1.2.1  
 48 cananian 1.1.2.1  import java.lang.reflect.Modifier;
 49 cananian 1.1.2.10 import java.util.Collections;
 50 cananian 1.1.2.9  import java.util.Enumeration;
 51 cananian 1.1.2.5  import java.util.HashMap;
 52 cananian 1.1.2.4  import java.util.HashSet;
 53 cananian 1.1.2.5  import java.util.Iterator;
 54 cananian 1.1.2.5  import java.util.Map;
 55 cananian 1.1.2.9  import java.util.Properties;
 56 cananian 1.1.2.4  import java.util.Set;
 57 cananian 1.1.2.1  /**
 58 cananian 1.1.2.1   * <code>InitializerTransform</code> transforms class initializers so
 59 cananian 1.1.2.1   * that they are idempotent and so that they perform all needed
 60 cananian 1.1.2.1   * initializer ordering checks before accessing non-local data.
 61 cananian 1.1.2.1   * 
 62 cananian 1.1.2.1   * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 63 cananian 1.6       * @version $Id: InitializerTransform.java,v 1.6 2004/02/08 03:20:10 cananian Exp $
 64 cananian 1.1.2.1   */
 65 cananian 1.1.2.1  public class InitializerTransform
 66 cananian 1.1.2.1      extends harpoon.Analysis.Transformation.MethodSplitter {
 67 cananian 1.1.2.1      /** Token for the initializer-ordering-check version of a method. */
 68 cananian 1.1.2.13     public static final Token CHECKED = new Token("initcheck") {
 69 cananian 1.1.2.13         public Object readResolve() { return CHECKED; }
 70 cananian 1.1.2.13     };
 71 cananian 1.1.2.9      /** Set of dependent native methods.  We know the dependencies of
 72 cananian 1.1.2.9       *  these methods statically; this is a Map from HMethods to
 73 cananian 1.1.2.10      *  Sets of HInitializers. HMethods with no dependencies are
 74 cananian 1.1.2.10      *  "safe". */
 75 cananian 1.1.2.9      private final Map dependentMethods;
 76 cananian 1.1.2.9      /** Our version of the codefactory. */
 77 cananian 1.1.2.9      private final HCodeFactory hcf;
 78 cananian 1.1.2.17     /** Runtime property determining whether we should unsynchronize
 79 cananian 1.1.2.17      *  all initializer methods.  This works except when initializers
 80 cananian 1.1.2.17      *  create threads, which we don't currently allow.  The default
 81 cananian 1.1.2.17      *  is to unsynchronize initializer methods. */
 82 cananian 1.1.2.17     private final static boolean unsyncInitializers =
 83 cananian 1.1.2.17         System.getProperty("harpoon.inittrans.unsync", "yes")
 84 cananian 1.1.2.17         .equalsIgnoreCase("yes");
 85 cananian 1.1.2.1  
 86 cananian 1.1.2.9      /** Creates a <code>InitializerTransform</code> with no information
 87 cananian 1.1.2.9       *  about which native methods are 'safe'. */
 88 cananian 1.1.2.7      public InitializerTransform(HCodeFactory parent, ClassHierarchy ch) {
 89 cananian 1.1.2.10         this(parent, ch, Default.EMPTY_MAP);
 90 cananian 1.1.2.9      }
 91 cananian 1.1.2.9      /** Creates a <code>InitializerTransform</code> using the specified
 92 cananian 1.1.2.16      *  named resource to specify the safe and dependent
 93 cananian 1.1.2.9       *  native methods of this runtime. */
 94 cananian 1.1.2.9      public InitializerTransform(HCodeFactory parent, ClassHierarchy ch,
 95 cananian 1.1.2.16                                 Linker linker, String resourceName) {
 96 cananian 1.1.2.16         this(parent, ch, parseProperties(linker, resourceName));
 97 cananian 1.1.2.9      }
 98 cananian 1.1.2.9      /** Creates a <code>InitializerTransform</code> using the given
 99 cananian 1.1.2.9       *  information about safe and dependent methods.
100 cananian 1.1.2.9       *  @param parent The input code factory. Will be converted to QuadWithTry.
101 cananian 1.1.2.9       *  @param ch A class hierarchy for the application.
102 cananian 1.1.2.9       *  @param dependentMethods a map from <code>HMethod</code>s specifying
103 cananian 1.1.2.9       *         native methods to a <code>java.util.Set</code> of the 
104 cananian 1.1.2.9       *         <code>HInitializer</code>s of the classes whose static
105 cananian 1.1.2.10      *         data this method may reference.  <code>HMethod</code>s
106 cananian 1.1.2.10      *         which map to zero-size <code>Set</code>s are 'safe'
107 cananian 1.1.2.10      *         to call within initializers (that is, they do not reference
108 cananian 1.1.2.10      *         any static data).
109 cananian 1.1.2.10      */
110 cananian 1.1.2.9      public InitializerTransform(HCodeFactory parent, ClassHierarchy ch,
111 cananian 1.1.2.10                                 final Map dependentMethods) {
112 cananian 1.1.2.1          // we only allow quad with try as input.
113 cananian 1.1.2.15         super(QuadWithTry.codeFactory(parent), ch, true/*doesn't matter*/);
114 cananian 1.1.2.9          this.dependentMethods = dependentMethods;
115 cananian 1.1.2.9          final HCodeFactory superfactory = super.codeFactory();
116 cananian 1.3.2.1          assert superfactory.getCodeName().equals(QuadWithTry.codename);
117 cananian 1.1.2.14         this.hcf = new CachingCodeFactory(new SerializableCodeFactory() {
118 cananian 1.1.2.9              public String getCodeName() { return superfactory.getCodeName(); }
119 cananian 1.1.2.9              public void clear(HMethod m) { superfactory.clear(m); }
120 cananian 1.1.2.9              public HCode convert(HMethod m) {
121 cananian 1.1.2.9                  if (Modifier.isNative(m.getModifiers()) &&
122 cananian 1.1.2.9                      dependentMethods.containsKey(select(m, ORIGINAL)) &&
123 cananian 1.1.2.9                      select(select(m, ORIGINAL), CHECKED).equals(m))
124 cananian 1.1.2.9                      // call the initializers for the dependent classes,
125 cananian 1.1.2.9                      // then call the original method.
126 cananian 1.1.2.9                      return redirectCode(m);
127 cananian 1.1.2.9                  else return superfactory.convert(m);
128 cananian 1.1.2.9              }
129 cananian 1.1.2.18         }) {    // make sure method is in safety cache before we clear
130 cananian 1.1.2.18                 // it from top-level cache (since isSafe needs to refer
131 cananian 1.1.2.18                 // to copy stored in top-level cache)
132 cananian 1.1.2.18                 public void clear(HMethod hm) {
133 cananian 1.1.2.18                     if (select(hm, ORIGINAL).equals(hm) &&
134 cananian 1.1.2.18                         !(hm instanceof HInitializer))
135 cananian 1.1.2.18                         isSafe(hm);
136 cananian 1.1.2.18                     super.clear(hm);
137 cananian 1.1.2.18                 }
138 cananian 1.1.2.18         };
139 cananian 1.1.2.1      }
140 cananian 1.1.2.9      // override parent's codefactory with ours! (which uses theirs)
141 cananian 1.1.2.9      public HCodeFactory codeFactory() { return hcf; }
142 cananian 1.1.2.1      /** Checks the token types handled by this 
143 cananian 1.1.2.1       *  <code>MethodSplitter</code> subclass. */
144 cananian 1.1.2.1      protected boolean isValidToken(Token which) {
145 cananian 1.1.2.1          return which==CHECKED || super.isValidToken(which);
146 cananian 1.1.2.1      }
147 cananian 1.1.2.1      /** Mutate a given <code>HCode</code> to produce the version
148 cananian 1.1.2.1       *  specified by <code>which</code>. */
149 cananian 1.1.2.1      protected HCode mutateHCode(HCodeAndMaps input, Token which) {
150 cananian 1.1.2.1          Code hc = (QuadWithTry) input.hcode();
151 cananian 1.1.2.1          if (which==CHECKED)
152 cananian 1.1.2.1              return addChecks(hc);
153 cananian 1.1.2.1          else if (which==ORIGINAL && hc.getMethod() instanceof HInitializer)
154 cananian 1.1.2.1              return mutateInitializer(hc);
155 cananian 1.1.2.1          return hc;
156 cananian 1.1.2.1      }
157 cananian 1.1.2.1      /** Add idempotency to initializer and add checks. */
158 cananian 1.1.2.1      private Code mutateInitializer(Code hc) {
159 cananian 1.1.2.1          HMethod hm = hc.getMethod();
160 cananian 1.3.2.1          assert hm.getReturnType()==HClass.Void;
161 cananian 1.1.2.2          // add checks.
162 cananian 1.1.2.2          hc = addChecks(hc);
163 cananian 1.1.2.2          // make idempotent.
164 cananian 1.1.2.1          HEADER qH = (HEADER) hc.getRootElement();
165 cananian 1.1.2.1          FOOTER qF = (FOOTER) qH.next(0);
166 cananian 1.1.2.1          METHOD qM = (METHOD) qH.next(1);
167 cananian 1.1.2.1          QuadFactory qf = qH.getFactory();
168 cananian 1.1.2.1          HClass declcls = hc.getMethod().getDeclaringClass();
169 cananian 1.1.2.1          HField ifield = declcls.getMutator().addDeclaredField
170 cananian 1.1.2.1              ("$$has$been$initialized$$", HClass.Boolean);
171 cananian 1.1.2.1          ifield.getMutator().setSynthetic(true);
172 cananian 1.1.2.1          ifield.getMutator().setModifiers(Modifier.STATIC | Modifier.PUBLIC);
173 cananian 1.1.2.1          Temp tst = new Temp(qf.tempFactory(), "uniq");
174 cananian 1.1.2.1          Quad q0 = new GET(qf, qM, tst, ifield, null);
175 cananian 1.1.2.1          Quad q1= new CJMP(qf, qM, tst, new Temp[0]);
176 cananian 1.1.2.1          Quad q2 = new RETURN(qf, qM, null);
177 cananian 1.1.2.11         Quad q3 = new CONST(qf, qM, tst, new Integer(1), HClass.Int);
178 cananian 1.1.2.11         Quad q4 = new SET(qf, qM, ifield, null, tst);
179 cananian 1.1.2.1          Edge splitedge = qM.nextEdge(0);
180 cananian 1.1.2.11         Quad.addEdges(new Quad[] { qM, q0, q1, q3, q4 });
181 cananian 1.1.2.1          Quad.addEdge(q1, 1, q2, 0);
182 cananian 1.1.2.11         Quad.addEdge(q4, 0, (Quad)splitedge.to(), splitedge.which_pred());
183 cananian 1.1.2.1          qF = qF.attach(q2, 0);
184 cananian 1.1.2.1          // done.
185 cananian 1.1.2.1          return hc;
186 cananian 1.1.2.1      }
187 cananian 1.1.2.4      /** Determine if this method is 'safe' (will never need initializers
188 cananian 1.1.2.4       *  inserted) or not. */
189 cananian 1.1.2.5      private boolean isSafe(HMethod hm) {
190 cananian 1.1.2.5          if (safetyCache.containsKey(hm))
191 cananian 1.1.2.5              return ((Boolean) safetyCache.get(hm)).booleanValue();
192 cananian 1.1.2.5          safetyCache.put(hm, new Boolean(true));// deals with cycles.
193 cananian 1.1.2.8          boolean isSafe = _isSafe_(hm); // split to make caching more readable.
194 cananian 1.1.2.8          safetyCache.put(hm, new Boolean(isSafe));
195 cananian 1.1.2.8          return isSafe;
196 cananian 1.1.2.8      }
197 cananian 1.1.2.8      private boolean _isSafe_(HMethod hm) {
198 cananian 1.3.2.1          assert !(hm instanceof HInitializer) : hm;
199 cananian 1.1.2.5          final HClass hc = hm.getDeclaringClass();
200 cananian 1.1.2.8          if (hc.isArray()) return true; // all array methods (clone()) are safe.
201 cananian 1.1.2.10         // native methods are safe if they don't depend on anything.
202 cananian 1.1.2.10         if (dependentMethods.containsKey(hm) &&
203 cananian 1.1.2.10             ((Set) dependentMethods.get(hm)).size()==0)
204 cananian 1.1.2.10             return true;
205 cananian 1.1.2.10         // okay, scan the code for this method.
206 cananian 1.1.2.5          class BooleanVisitor extends QuadVisitor {
207 cananian 1.1.2.5              boolean unsafe = false;
208 cananian 1.1.2.5              public void visit(Quad q) { /* ignore */ }
209 cananian 1.1.2.5          }
210 cananian 1.1.2.5          BooleanVisitor bv = new BooleanVisitor() {
211 cananian 1.1.2.5              // look for static references outside 'hc' (GET/SET/ANEW/NEW/CALL)
212 cananian 1.1.2.5              public void visit(GET q) {
213 cananian 1.1.2.5                  if (q.isStatic()) check(q.field().getDeclaringClass());
214 cananian 1.1.2.5              }
215 cananian 1.1.2.5              public void visit(SET q) {
216 cananian 1.1.2.5                  if (q.isStatic()) check(q.field().getDeclaringClass());
217 cananian 1.1.2.5              }
218 cananian 1.1.2.5              public void visit(ANEW q) {
219 cananian 1.1.2.5                  check(q.hclass());
220 cananian 1.1.2.5              }
221 cananian 1.1.2.5              public void visit(NEW q) {
222 cananian 1.1.2.5                  check(q.hclass());
223 cananian 1.1.2.5              }
224 cananian 1.1.2.5              public void visit(CALL q) {
225 cananian 1.1.2.8                  if ( !isVirtual(q) ) {
226 cananian 1.1.2.5                      check(q.method().getDeclaringClass());
227 cananian 1.1.2.5                      unsafe = unsafe || !isSafe(q.method());
228 cananian 1.1.2.5                  } else unsafe = true; // virtual calls aren't safe.
229 cananian 1.1.2.5              }
230 cananian 1.1.2.5              void check(HClass c) {
231 cananian 1.1.2.5                  if (c==hc) return;
232 cananian 1.1.2.5                  if (c.getClassInitializer()==null) return;
233 cananian 1.1.2.5                  unsafe = true;
234 cananian 1.1.2.5              }
235 cananian 1.1.2.5          };
236 cananian 1.1.2.5          HCode code = codeFactory().convert(hm);
237 cananian 1.1.2.5          if (code==null) return false; // no clue what this does!
238 cananian 1.1.2.5          for (Iterator it=code.getElementsI();
239 cananian 1.1.2.5               (!bv.unsafe) && it.hasNext(); )
240 cananian 1.1.2.5              ((Quad) it.next()).accept(bv);
241 cananian 1.1.2.5          return !bv.unsafe;
242 cananian 1.1.2.5      }
243 cananian 1.1.2.5      /** Cache for safety tests. */
244 cananian 1.1.2.5      private Map safetyCache = new HashMap();
245 cananian 1.1.2.1      /** Add initialization checks to every static use of a class. */
246 cananian 1.1.2.1      private Code addChecks(Code hc) {
247 cananian 1.1.2.3          final HEADER qH = (HEADER) hc.getRootElement();
248 cananian 1.1.2.4          final Set phisSeen = new HashSet();
249 cananian 1.1.2.2          // static references are found in GET/SET/ANEW/NEW/CALL
250 cananian 1.1.2.2          QuadVisitor qv = new QuadVisitor() {
251 cananian 1.1.2.3              /** classes already initialized in this method. */
252 cananian 1.1.2.3              Environment seenSet = new HashEnvironment();
253 cananian 1.1.2.3              /* constructor */ { traverse((METHOD)qH.next(1)); }
254 cananian 1.1.2.3              // recursive traversal.
255 cananian 1.1.2.3              private void traverse(Quad q) {
256 cananian 1.1.2.4                  Quad[] nxt = q.next(); // cache before q is (possibly) replaced
257 cananian 1.1.2.3                  q.accept(this);
258 cananian 1.1.2.3                  Environment.Mark m = seenSet.getMark();
259 cananian 1.1.2.4                  for (int i=0; i<nxt.length; i++) {
260 cananian 1.1.2.4                      if (!phisSeen.contains(nxt[i]))
261 cananian 1.1.2.4                          traverse(nxt[i]);
262 cananian 1.1.2.3                      if (i+1<q.nextLength())
263 cananian 1.1.2.3                          seenSet.undoToMark(m);
264 cananian 1.1.2.3                  }
265 cananian 1.1.2.3              }
266 cananian 1.1.2.2              public void visit(Quad q) { /* default, do nothing. */ }
267 cananian 1.1.2.3              public void visit(PHI q) {
268 cananian 1.1.2.4                  phisSeen.add(q);
269 cananian 1.1.2.3                  // XXX: merging at phis (instead of throwing away
270 cananian 1.1.2.3                  // seenset) would lead to less unnecessary
271 cananian 1.1.2.3                  // initializations.  cost may be prohibitive?
272 cananian 1.1.2.3                  seenSet.clear();
273 cananian 1.1.2.3              }
274 cananian 1.1.2.3              public void visit(ANEW q) {
275 cananian 1.1.2.12                 addCheckBeforeAll(q, q.hclass(), seenSet);
276 cananian 1.1.2.3              }
277 cananian 1.1.2.2              public void visit(CALL q) {
278 cananian 1.1.2.12                 if (q.isStatic())
279 cananian 1.1.2.3                      addCheckBefore(q, q.method().getDeclaringClass(), seenSet);
280 cananian 1.1.2.8                  if ( (!isVirtual(q)) && isSafe(q.method()))
281 cananian 1.1.2.8                      return;
282 cananian 1.1.2.8  
283 cananian 1.1.2.8                  // use a 'checking' version of this method.
284 cananian 1.1.2.8                  Quad ncall = new CALL
285 cananian 1.1.2.8                      (q.getFactory(), q, select(q.method(), CHECKED),
286 cananian 1.1.2.8                       q.params(), q.retval(), q.retex(), q.isVirtual(),
287 cananian 1.1.2.8                       q.isTailCall(), q.dst(), q.src());
288 cananian 1.1.2.8                  Quad.replace(q, ncall);
289 cananian 1.1.2.8                  Quad.transferHandlers(q, ncall);
290 cananian 1.1.2.2              }
291 cananian 1.1.2.2              public void visit(GET q) {
292 cananian 1.1.2.2                  if (q.isStatic())
293 cananian 1.1.2.3                      addCheckBefore(q, q.field().getDeclaringClass(), seenSet);
294 cananian 1.1.2.3              }
295 cananian 1.1.2.3              public void visit(NEW q) {
296 cananian 1.1.2.12                 addCheckBeforeAll(q, q.hclass(), seenSet);
297 cananian 1.1.2.2              }
298 cananian 1.1.2.2              public void visit(SET q) {
299 cananian 1.1.2.2                  if (q.isStatic())
300 cananian 1.1.2.3                      addCheckBefore(q, q.field().getDeclaringClass(), seenSet);
301 cananian 1.1.2.17             }
302 cananian 1.1.2.17             // also (optionally) remove synchronization from initializers.
303 cananian 1.1.2.17             public void visit(MONITORENTER q) {
304 cananian 1.1.2.17                 if (unsyncInitializers) q.remove();
305 cananian 1.1.2.17             }
306 cananian 1.1.2.17             public void visit(MONITOREXIT q) {
307 cananian 1.1.2.17                 if (unsyncInitializers) q.remove();
308 cananian 1.1.2.2              }
309 cananian 1.1.2.2          };
310 cananian 1.1.2.1          return hc;
311 cananian 1.1.2.1      }
312 cananian 1.1.2.12     /** Recursive method to add checks for hc *and* all its superclasses
313 cananian 1.1.2.12      *  and interfaces. */
314 cananian 1.1.2.12     private static void addCheckBeforeAll(Quad q, HClass hc, Environment seen){
315 cananian 1.1.2.12         // first add check for superclass (and all its superclasses)
316 cananian 1.1.2.12         HClass su = hc.getSuperclass();
317 cananian 1.1.2.12         if (su!=null) addCheckBeforeAll(q, su, seen);
318 cananian 1.1.2.12         // then add checks for all interfaces (and all their interfaces)
319 cananian 1.1.2.12         HClass[] in = hc.getInterfaces();
320 cananian 1.1.2.12         for (int i=0; i<in.length; i++)
321 cananian 1.1.2.12             addCheckBeforeAll(q, in[i], seen);
322 cananian 1.1.2.12         // now finally, add check for this.
323 cananian 1.1.2.12         // (this order is important so that superclass initializers
324 cananian 1.1.2.12         //  get executed first)
325 cananian 1.1.2.12         addCheckBefore(q, hc, seen);
326 cananian 1.1.2.12     }
327 cananian 1.1.2.12     /** Add a call to this class initializer, if it exists and has not
328 cananian 1.1.2.12      *  already been invoked on all execution paths leading to q. */
329 cananian 1.1.2.3      private static void addCheckBefore(Quad q, HClass class2check,
330 cananian 1.1.2.3                                         Environment seenSet) {
331 cananian 1.1.2.2          QuadFactory qf = q.getFactory();
332 cananian 1.1.2.2          if (qf.getMethod().getDeclaringClass().equals(class2check))
333 cananian 1.1.2.2              return; // we've already initialized (or are initializing) this.
334 cananian 1.1.2.3          if (seenSet.containsKey(class2check))
335 cananian 1.1.2.3              return; // already checked on this execution path.
336 cananian 1.1.2.3          else seenSet.put(class2check, class2check); // don't double check.
337 cananian 1.1.2.2          HMethod clinit = class2check.getClassInitializer();
338 cananian 1.1.2.2          if (clinit==null) return; // no class initializer for this class.
339 cananian 1.3.2.1          assert q.prevLength()==1; // otherwise don't know where to link
340 cananian 1.1.2.2          Quad q0 = new CALL(qf, q, clinit, new Temp[0], null, null, false,
341 cananian 1.1.2.2                             false, new Temp[0]);
342 cananian 1.1.2.2          // insert the new call on an edge
343 cananian 1.1.2.2          Edge splitedge = q.prevEdge(0);
344 cananian 1.1.2.2          Quad.addEdge((Quad)splitedge.from(), splitedge.which_succ(), q0, 0);
345 cananian 1.1.2.2          Quad.addEdge(q0, 0, (Quad)splitedge.to(), splitedge.which_pred());
346 cananian 1.1.2.2          // cover this call with the handlers of q
347 cananian 1.1.2.2          q0.addHandlers(q.handlers());
348 cananian 1.1.2.2          // done.
349 cananian 1.1.2.2          return;
350 cananian 1.1.2.8      }
351 cananian 1.1.2.8      private boolean isVirtual(CALL q) {
352 cananian 1.1.2.8          return q.isVirtual() && isVirtual(q.method());
353 cananian 1.1.2.9      }
354 cananian 1.1.2.9      /** Create a redirection method for native methods we "know" the
355 cananian 1.1.2.9       *  dependencies of. */
356 cananian 1.1.2.9      private QuadWithTry redirectCode(final HMethod hm) {
357 cananian 1.1.2.9          final HMethod orig = select(hm, ORIGINAL);
358 cananian 1.1.2.9          final Set inits = (Set) dependentMethods.get(orig);
359 cananian 1.1.2.9          // make the Code for this method (note how we work around the
360 cananian 1.1.2.9          // protected fields).
361 cananian 1.1.2.9          return new QuadWithTry(hm, null) { /* constructor */ {
362 cananian 1.1.2.9              // figure out how many temps we need, then make them.
363 cananian 1.1.2.9              int nargs = hm.getParameterTypes().length + (hm.isStatic()? 0: 1);
364 cananian 1.1.2.9              Temp[] params = new Temp[nargs];
365 cananian 1.1.2.9              for (int i=0; i<params.length; i++)
366 cananian 1.1.2.9                  params[i] = new Temp(qf.tempFactory());
367 cananian 1.1.2.9              Temp retval = (hm.getReturnType()==HClass.Void) ? null :
368 cananian 1.1.2.9                  new Temp(qf.tempFactory());
369 cananian 1.1.2.9              // okay, make the dispatch core.
370 cananian 1.1.2.9              Quad q0 = new HEADER(qf, null);
371 cananian 1.1.2.9              Quad q1 = new METHOD(qf, null, params, 1);
372 cananian 1.1.2.9              Quad q2 = new CALL(qf, null, orig, params,
373 cananian 1.1.2.9                                 retval, null, false, true, new Temp[0]);
374 cananian 1.1.2.9              Quad q3 = new RETURN(qf, null, retval);
375 cananian 1.1.2.9              Quad q4 = new FOOTER(qf, null, 2);
376 cananian 1.1.2.9              Quad.addEdge(q0, 0, q4, 0);
377 cananian 1.1.2.9              Quad.addEdge(q0, 1, q1, 0);
378 cananian 1.1.2.9              // leaving out the edge from q1 to q2 for the moment.
379 cananian 1.1.2.9              Quad.addEdge(q2, 0, q3, 0);
380 cananian 1.1.2.9              Quad.addEdge(q3, 0, q4, 1);
381 cananian 1.1.2.9              this.quads = q0;
382 cananian 1.1.2.9              // now make the calls to the static initializers
383 cananian 1.1.2.9              Quad last = q1;
384 cananian 1.6                  for (Object hiO : inits) {
385 cananian 1.6                      HInitializer hi = (HInitializer) hiO;
386 cananian 1.1.2.9                  Quad qq = new CALL(qf, null, hi, new Temp[0], null, null,
387 cananian 1.1.2.9                                     false, false, new Temp[0]);
388 cananian 1.1.2.9                  Quad.addEdge(last, 0, qq, 0);
389 cananian 1.1.2.9                  last = qq;
390 cananian 1.1.2.9              }
391 cananian 1.1.2.9              // and the final link:
392 cananian 1.1.2.9              Quad.addEdge(last, 0, q2, 0);
393 cananian 1.1.2.9              // done!
394 cananian 1.1.2.9          } };
395 cananian 1.1.2.9      }
396 cananian 1.1.2.16     private static Map parseProperties(final Linker linker,
397 cananian 1.1.2.16                                        String resourceName) {
398 cananian 1.1.2.16         final Map result = new HashMap();
399 cananian 1.1.2.16         try {
400 cananian 1.1.2.16             ParseUtil.readResource(resourceName, new ParseUtil.StringParser() {
401 cananian 1.1.2.16                 public void parseString(String s)
402 cananian 1.1.2.16                     throws ParseUtil.BadLineException {
403 cananian 1.1.2.16                     int equals = s.indexOf('=');
404 cananian 1.1.2.16                     String mname = (equals<0)? s:s.substring(0, equals).trim();
405 cananian 1.1.2.16                     HMethod hm = ParseUtil.parseMethod(linker, mname);
406 cananian 1.1.2.16                     final Set dep = new HashSet();
407 cananian 1.1.2.16                     String depstr = (equals<0) ? "" : s.substring(equals+1);
408 cananian 1.1.2.16                     ParseUtil.parseSet(depstr, new ParseUtil.StringParser() {
409 cananian 1.1.2.16                         public void parseString(String ss)
410 cananian 1.1.2.16                             throws ParseUtil.BadLineException {
411 cananian 1.1.2.16                             HClass hc = ParseUtil.parseClass(linker, ss);
412 cananian 1.1.2.18                 // FIXME: SHOULD ADD ALL SUPERCLASS/INTERFACE INITIALIZERS
413 cananian 1.1.2.18                 // of hc to map, too, and 'dep' should be a *ordered list*
414 cananian 1.1.2.18                 // not just a set.
415 cananian 1.1.2.16                             HInitializer hi = hc.getClassInitializer();
416 cananian 1.1.2.16                             if (hi!=null) dep.add(hi);
417 cananian 1.1.2.16                         }
418 cananian 1.1.2.16                     });
419 cananian 1.1.2.16                     // if no dependencies, then it's a safe method.
420 cananian 1.1.2.16                     // (optimize for space by using a canonical EMPTY_SET)
421 cananian 1.1.2.16                     if (dep.size()==0) result.put(hm, Collections.EMPTY_SET);
422 cananian 1.1.2.16                     // otherwise, add set to dependent methods map.
423 cananian 1.1.2.16                     else result.put(hm, dep);
424 cananian 1.1.2.16                     // yay!
425 cananian 1.1.2.16                 }
426 cananian 1.1.2.16             });
427 cananian 1.1.2.16         } catch (java.io.IOException ex) {
428 cananian 1.1.2.16             System.err.println("ERROR READING PROPERTIES, SKIPPING.");
429 cananian 1.1.2.16             System.err.println(ex.toString());
430 cananian 1.1.2.9          }
431 cananian 1.1.2.16         // done.
432 cananian 1.1.2.10         return result;
433 cananian 1.1.2.1      }
434 cananian 1.2      }