/** caching infrastructure around 'doOne' */ Map classifyMethod(HMethod hm) { assert isConstructor(hm); if (!cache.containsKey(hm)) { HCode hc = hcf.convert(hm); assert hc != null; cache.put(hm, doOne(hc)); } return (Map) cache.get(hm); }
/** Find fields which are *not* subclass-final. */ private Set findBadFields(HCodeFactory hcf, ClassHierarchy ch) { Set badFields = new HashSet(); // for each callable method... for (Iterator it = ch.callableMethods().iterator(); it.hasNext(); ) { HMethod hm = (HMethod) it.next(); HCode hc = hcf.convert(hm); if (hc == null) continue; // xxx: native methods may write fields! // construct a must-param oracle for constructors. MustParamOracle mpo = isConstructor(hm) ? new MustParamOracle(hc) : null; // examine this method for writes HClass thisClass = hc.getMethod().getDeclaringClass(); for (Iterator it2 = hc.getElementsI(); it2.hasNext(); ) { Quad q = (Quad) it2.next(); if (q instanceof SET) { SET qq = (SET) q; // ignore writes of static fields. if (qq.isStatic()) continue; // if this is a constructor, than it may write only // to fields of 'this' if (isConstructor(hm) && mpo.isMustParam(qq.objectref()) && mpo.whichMustParam(qq.objectref()) == 0) continue; // this is a permitted write. // writes by subclass methods to superclass fields are // okay. (but not writes by 'this' methods to 'this' // fields, unless the method is a constructor) if (qq.field().getDeclaringClass().isInstanceOf(thisClass) && // XXX i think the presence of the 'isConstructor' // clause here is a bug. constructor writes // should be taken care of by clause above. (isConstructor(hm) || !thisClass.equals(qq.field().getDeclaringClass()))) continue; // subclass writes are permitted. // non-permitted write! badFields.add(qq.field()); } } // on to the next! } // done! we have set of all bad (not subclass-final) fields. return Collections.unmodifiableSet(badFields); }
/** * Code factory for applying <code>DynamicWBTreePass</code> to a canonical tree. Clones the tree * before doing transformation in-place. */ public static HCodeFactory codeFactory( final HCodeFactory parent, final Frame frame, final Linker linker) { final HMethod clearHM = linker .forName("harpoon.Runtime.PreciseGC.WriteBarrier") .getMethod("clearBit", new HClass[] {linker.forName("java.lang.Object")}); assert parent.getCodeName().equals(CanonicalTreeCode.codename); return Canonicalize.codeFactory( new HCodeFactory() { public HCode convert(HMethod m) { HCode hc = parent.convert(m); if (hc != null) { harpoon.IR.Tree.Code code = (harpoon.IR.Tree.Code) hc; // clone code... code = (harpoon.IR.Tree.Code) code.clone(m).hcode(); DerivationGenerator dg = null; try { dg = (DerivationGenerator) code.getTreeDerivation(); } catch (ClassCastException ex) { /* i guess not */ } // ...do analysis and modify cloned code in-place. simplify((Stm) code.getRootElement(), dg, HCE_RULES(frame, clearHM)); hc = code; } return hc; } public String getCodeName() { return parent.getCodeName(); } public void clear(HMethod m) { parent.clear(m); } }); }