1 cananian 1.1.2.1 // InitializerOrdering.java, created Thu Oct 14 12:42:50 1999 by cananian
 2 cananian 1.1.2.1 // Copyright (C) 1999 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.Backend.Analysis;
 5 cananian 1.1.2.1 
 6 cananian 1.1.2.3 import harpoon.Analysis.CallGraph;
 7 cananian 1.1.2.1 import harpoon.Analysis.ClassHierarchy;
 8 cananian 1.1.2.1 import harpoon.ClassFile.HClass;
 9 cananian 1.1.2.1 import harpoon.ClassFile.HInitializer;
10 cananian 1.1.2.1 import harpoon.ClassFile.HMethod;
11 cananian 1.5     import net.cscott.jutil.UniqueVector;
12 cananian 1.1.2.1 import harpoon.Util.Util;
13 cananian 1.5     import net.cscott.jutil.WorkSet;
14 cananian 1.1.2.1 
15 cananian 1.1.2.1 import java.util.ArrayList;
16 cananian 1.1.2.1 import java.util.Collections;
17 cananian 1.1.2.1 import java.util.HashSet;
18 cananian 1.1.2.1 import java.util.Iterator;
19 cananian 1.1.2.1 import java.util.List;
20 cananian 1.1.2.1 import java.util.Set;
21 cananian 1.1.2.1 /**
22 cananian 1.1.2.1  * <code>InitializerOrdering</code> computes a topological sort of
23 cananian 1.1.2.1  * the static initializer call graph designed to ensure that
24 cananian 1.1.2.1  * classes are initialized in the correct order.  Cycles in
25 cananian 1.1.2.1  * the initializer call graph will emit warnings; executing the
26 cananian 1.1.2.1  * static initializers in the order given is not guaranteed
27 cananian 1.1.2.1  * to produce the same results as executing them on demand
28 cananian 1.1.2.1  * in that case.
29 cananian 1.1.2.1  * 
30 cananian 1.1.2.1  * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
31 cananian 1.6      * @version $Id: InitializerOrdering.java,v 1.6 2004/02/08 03:20:42 cananian Exp $
32 cananian 1.1.2.1  */
33 cananian 1.1.2.1 public class InitializerOrdering {
34 cananian 1.1.2.1     public final List sorted;
35 cananian 1.1.2.1     /** Creates a <code>InitializerOrdering</code>. */
36 cananian 1.1.2.1     public InitializerOrdering(ClassHierarchy ch, CallGraph cg) {
37 cananian 1.1.2.1         List _sorted = new ArrayList();
38 cananian 1.1.2.1         Set touched = new HashSet(), added = new HashSet();
39 cananian 1.6             for (Object hcO : ch.classes()) {
40 cananian 1.6                 HClass hc = (HClass) hcO;
41 cananian 1.1.2.1             if (!added.contains(hc))
42 cananian 1.1.2.1                 examineClass(ch, cg, hc, touched, added, _sorted);
43 cananian 1.1.2.1         }
44 cananian 1.1.2.1         this.sorted = Collections.unmodifiableList(_sorted);
45 cananian 1.1.2.1     }
46 cananian 1.1.2.1     private void examineClass(ClassHierarchy ch, CallGraph cg, HClass c,
47 cananian 1.1.2.1                               Set touched, Set added, List _sorted) {
48 cananian 1.3.2.1         assert ch.classes().contains(c) : ("Being examined, although it's not in hierarchy:"+c);
49 cananian 1.3.2.1         assert !added.contains(c);
50 cananian 1.3.2.1         assert !touched.contains(c);
51 cananian 1.1.2.1         touched.add(c);
52 cananian 1.1.2.1         // first, all superclass initializers must be called.
53 cananian 1.1.2.1         for (HClass hcp=c.getSuperclass(); hcp!=null; hcp=hcp.getSuperclass())
54 cananian 1.1.2.1             if (!touched.contains(hcp))
55 cananian 1.1.2.1                 examineClass(ch, cg, hcp, touched, added, _sorted);
56 cananian 1.1.2.1             else if (!added.contains(hcp))
57 cananian 1.1.2.1                 warnCircle(hcp);
58 cananian 1.1.2.1         // now, all methods called by this static initializer must be examined
59 cananian 1.1.2.1         HMethod m = c.getClassInitializer();
60 cananian 1.1.2.4         if (m!=null && !touched.contains(m))
61 cananian 1.1.2.4             examineMethod(ch, cg, c, m, touched, added, _sorted);
62 cananian 1.1.2.1         // okay, all dependencies have been added, so now add this initializer
63 cananian 1.1.2.1         if (m!=null) _sorted.add(m);
64 cananian 1.1.2.1         added.add(c);
65 cananian 1.1.2.1     }
66 cananian 1.1.2.1     private void examineMethod(ClassHierarchy ch, CallGraph cg, 
67 cananian 1.1.2.1                                HClass initClass, HMethod m,
68 cananian 1.1.2.1                                Set touched, Set added, List _sorted) {
69 cananian 1.3.2.1         assert ch.callableMethods().contains(m) : ("Being examined, although it's not callable:"+m);
70 cananian 1.3.2.1         assert !touched.contains(m);
71 cananian 1.1.2.1         touched.add(m);
72 cananian 1.1.2.1         // first check that the class containing this method has been init'ed.
73 cananian 1.1.2.1         // this class is *being* init'ed if m is an initializer, so skip then.
74 cananian 1.1.2.1         HClass hc = m.getDeclaringClass();
75 cananian 1.1.2.1         if (hc != initClass) { // we're already initializing this class.
76 cananian 1.1.2.1             if (!touched.contains(hc))
77 cananian 1.1.2.1                 examineClass(ch, cg, hc, touched, added, _sorted);
78 cananian 1.1.2.1             else if (!added.contains(hc))
79 cananian 1.1.2.1                 warnCircle(hc);
80 cananian 1.1.2.1         }
81 cananian 1.1.2.1         // now recursively invoke all the methods which this guy calls.
82 cananian 1.1.2.1         HMethod[] deps = cg.calls(m);
83 cananian 1.1.2.1         for (int i=0; i<deps.length; i++) {
84 cananian 1.1.2.1             if (!touched.contains(deps[i]))// could be recursive functions here
85 cananian 1.1.2.1                 examineMethod(ch, cg, initClass, deps[i],
86 cananian 1.1.2.1                               touched, added, _sorted);
87 cananian 1.1.2.1         }
88 cananian 1.1.2.2         // XXX: ACCESSED FIELDS ALSO TRIGGER INITIALIZERS!
89 cananian 1.1.2.1         // okay, done looking at this method.
90 cananian 1.1.2.1     }
91 cananian 1.1.2.1     private void warnCircle(HClass hc) {
92 cananian 1.1.2.1         System.err.println("WARNING: circular dependency on " +
93 cananian 1.1.2.1                            hc.getName() + " in static initializers.");
94 cananian 1.1.2.1     }
95 cananian 1.2     }