package lto.libinfo; import static lto.Utils.*; import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.classfile.Method; import org.apache.bcel.generic.ObjectType; import org.apache.bcel.generic.Type; public class LibInfo { private final Manifest manifest; public final Map<Method, Set<Method>> ELM = new HashMap<Method, Set<Method>>(); public final Map<Method, Map<String, Method>> VLM = new HashMap<Method, Map<String, Method>>(); public final Map<JavaClass, Set<JavaClass>> ET = new HashMap<JavaClass, Set<JavaClass>>(); public final Map<JavaClass, JavaClass> ETinv = new HashMap<JavaClass, JavaClass>(); public final Map<Method, Method> CLM = new HashMap<Method, Method>(); public final Map<Method, Method> CLS = new HashMap<Method, Method>(); public final Map<JavaClass, Map<JavaClass, Method>> FLS = new HashMap<JavaClass, Map<JavaClass, Method>>(); public final Set<JavaClass> BT = new HashSet<JavaClass>(); public final Set<Method> BLM = new HashSet<Method>(); public final Set<Method> LS = new HashSet<Method>(); //v(LM) : (ret(LM) + args(LM)) -> T //BT: BT -> {0, 1} base types //BLM: BLM -> {0, 1} base methods //LS: LS -> {0, 1} type transforms //ELM: BLM -> LM -> {0, 1} equivalent methods //VLM: BLM -> Vsig -> LM //ET: BT -> T equivalents types //ETinv: T -> BT //FLS: T -> T -> LS //CLM: LM -> ZC method costs //CLS: S -> ZC transformation costs //CS: S -> Z //CM: M -> X -> Z public LibInfo(String manifest) throws ClassNotFoundException, IllegalAccessException, InstantiationException { this.manifest = (Manifest) Class.forName(manifest).newInstance(); try{ setup(); } catch (Exception e) { System.out.println(e); e.printStackTrace(); System.exit(1);} } private void setup() throws Exception { // populate BT BT.addAll(manifest.getBaseTypes()); // populate BLM BLM.addAll(manifest.getBaseMethods()); // populate BLS LS.addAll(manifest.getTransformations()); // populate ELM for (Method blm : BLM) for (Annotation an : AnnotationReader.getAnnotations(blm.getAttributes())) { if (an instanceof Equivalents) { Set<Method> lms = new HashSet<Method>(); ELM.put(blm, lms); for (String lm_name : ((Equivalents) an).value().split(",")) lms.add(rlm(lm_name)); } } // populate ET, ETinv for (JavaClass bt : BT) for (Annotation an : AnnotationReader.getAnnotations(bt.getAttributes())) if (an instanceof Equivalents) { Set<JavaClass> tset = new HashSet<JavaClass>(); ET.put(bt, tset); for (String t_name : ((Equivalents) an).value().split(",")) tset.add(rlk(t_name)); for (JavaClass t : tset) { if (ETinv.containsKey(t)) throw new InvalidLibraryException("Bad type " + t + ": already equivalent to base method " + ETinv.get(t) + "."); ETinv.put(t, bt); } } // populate VLM for (Method blm : BLM) { VLM.put(blm, new HashMap<String, Method>()); for (Method lm : ELM.get(blm)) { String vsig = lm.getSignature(); VLM.get(blm).put(vsig, lm); } } // VLM type check for (Method blm : BLM) { Map<Integer, JavaClass> bv = method2v(blm); for (Method lm : ELM.get(blm)) { Map<Integer, JavaClass> v = method2v(lm); if (!v.keySet().equals(bv.keySet())) throw new InvalidLibraryException("Bad method " + lm + ": number of parameters differ from base method."); for (int i : v.keySet()) if (!ETinv.get(v.get(i)).equals(bv.get(i))) throw new InvalidLibraryException("Bad method " + lm + ": argument " + i + " is incompatible with base method."); } } // populate FLS for (JavaClass t : ETinv.keySet()) FLS.put(t, new HashMap<JavaClass, Method>()); for (Method ls : LS) { Map<Integer, JavaClass> v = method2v(ls); if (!v.containsKey(-1)) throw new InvalidLibraryException("Bad transform " + ls + ": must return an object."); if (v.size() != 2) throw new InvalidLibraryException("Bad transform " + ls + ": must take exactly one argument."); JavaClass tu = v.get(-1); JavaClass tv = v.get(0); if (!ETinv.containsKey(tu)) throw new InvalidLibraryException("Bad transform " + ls + ": invalid source type " + tu + "."); if (!ETinv.containsKey(tv)) throw new InvalidLibraryException("Bad transform " + ls + ": invalid dest type " + tu + "."); if (!ETinv.get(tu).equals(ETinv.get(tv))) throw new InvalidLibraryException("Bad transform " + ls + ": source and dest types not compatible."); FLS.get(tu).put(tv, ls); } // populate CLM for (Set<Method> lms : ELM.values()) for (Method lm : lms) for (Annotation an : AnnotationReader.getAnnotations(lm.getAttributes())) /* if (an instanceof Cost) czm.put(zm, ((Cost)an).value()); */ if (an instanceof CostFn) { String zc_name = ((CostFn) an).value(); Method zc = rlm(zc_name); CLM.put(lm, zc); } // populate CLS for (Method ls : LS) // TODO check that types are equivalent? for (Annotation an : AnnotationReader.getAnnotations(ls.getAttributes())) /* if (an instanceof Cost) czs.put(zs, ((Cost)an).value()); */ if (an instanceof CostFn) { String zc_name = ((CostFn) an).value(); Method zc = rlm(zc_name); CLS.put(ls, zc); } } /* Converts BCEL Types to BCEL JavaClass. Checks that type is an object. */ public static Map<Integer, JavaClass> method2v(Method m) { Map<Integer, JavaClass> v = new HashMap<Integer, JavaClass>(); Type[] ta = m.getArgumentTypes(); Type tr = m.getReturnType(); { Type t = tr; if (t instanceof ObjectType) { String sc = ((ObjectType)t).getClassName(); v.put(-1, rlk(sc)); } } for (int i = 0; i < ta.length; i++) { Type t = ta[i]; if (!(t instanceof ObjectType)) throw new InvalidLibraryException("Bad method " + m + ": Argument type " + i + " is not an object."); String sc = ((ObjectType)t).getClassName(); v.put(i, rlk(sc)); } return v; } @Override public String toString() { StringBuilder s = new StringBuilder(); String n = String.format("%n"); s.append("Equivalent methods:" + n); for (Method bzm : manifest.getBaseMethods()) { s.append(" " + bzm.getName() + " -> { "); for (Method zm : ELM.get(bzm)) s.append(zm.getReturnType() + ":" + zm.getName() + " "); // TODO fix this info s.append("}" + n); } s.append("Equivalent types:" + n); for (JavaClass bzt : manifest.getBaseTypes()) { s.append(" " + bzt.getClassName() + " -> { "); for (JavaClass zt : ET.get(bzt)) s.append(zt.getClassName() + " "); s.append("}" + n); } s.append("Method costs:" + n); for (Method zm : CLM.keySet()) s.append(" " + zm.getName() + " -> " + CLM.get(zm).getName() + n); s.append("Transformation costs:" + n); for (Method zs : CLS.keySet()) s.append(" " + zs.getName() + " -> " + CLS.get(zs).getName() + n); return s.toString(); } }