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 }