package fr.lifl.stc.stan.signature; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import fr.lifl.stc.stan.util.Printer; import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.classfile.Method; import org.apache.bcel.generic.ConstantPoolGen; import org.apache.bcel.generic.InvokeInstruction; /** * * @author yann * */ public class SignatureDictionary { static final long serialVersionUID = 0; public static final int GLOBAL_SIGN_IDX = 0x01; public static final int EXACT_SIGN_IDX = 0x10; // Contains of the Signatures private HashMap exact_signatures = null; private HashMap global_signatures = null; private ClassHierarchy hierarchy; /** * contains a flas for each signature: final or not */ //private HashMap isFinal_exact_signatures = null; //private HashMap isFinal_global_signatures = null; private boolean updated = false; private String filename; @SuppressWarnings("unchecked") public SignatureDictionary(String filename) throws ClassNotFoundException { this.filename = filename; try { ObjectInputStream input = new ObjectInputStream(new FileInputStream(filename)); hierarchy = (ClassHierarchy) input.readObject(); exact_signatures = (HashMap) input.readObject(); global_signatures = (HashMap) input.readObject(); /*isFinal_global_signatures = new HashMap(); isFinal_exact_signatures = new HashMap(); Collection s = exact_signatures.keySet(); for (Iterator it = s.iterator(); it.hasNext();) { String name = (String) it.next(); isFinal_exact_signatures.put(name, true); //element.lock(); } */ //Iterator it = exact_signatures.` input.close(); } catch (IOException e){ hierarchy = new ClassHierarchy(); exact_signatures = new HashMap (); global_signatures = new HashMap (); //isFinal_global_signatures = new HashMap(); //isFinal_exact_signatures = new HashMap(); } lock(); } @SuppressWarnings("unchecked") public void addContent(String filename) throws ClassNotFoundException { try { ObjectInputStream input = new ObjectInputStream(new FileInputStream(filename)); this.hierarchy = (ClassHierarchy) input.readObject(); this.exact_signatures = (HashMap) input.readObject(); this.global_signatures = (HashMap) input.readObject(); input.close(); } catch (IOException e){ System.err.println("SignatureDictionary.addContent(): error reading file " + filename); } } public String[] getIndex() { Collection c = global_signatures.keySet(); String[] res = new String[c.size()]; Iterator it = c.iterator(); int i = 0; while (it.hasNext()) { String e = it.next(); res[i] = e; i++; } return res; } public String[] getExactIndex() { Collection c = exact_signatures.keySet(); String[] res = new String[c.size()]; Iterator it = c.iterator(); int i = 0; while (it.hasNext()) { String e = it.next(); res[i] = e; i++; } return res; } /** * Dump this dictionary into a file * Name of this file is given by the field name * @throws FileNotFoundException * @throws IOException */ public void dump() throws FileNotFoundException, IOException { lock(); ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(filename)); output.writeObject(hierarchy); output.writeObject(exact_signatures); output.writeObject(global_signatures); output.close(); } /** * @param _package a String * @param _class a String * @param _method a String * @return the signature wich correponds to _package._class._method method * or null if it does not yet exist. */ public Signature findSignature(String key, boolean exact) { Signature s = null; String clname = keyClassName(key); String methname = keyMethodName(key); if(exact) { s = exact_signatures.get(key); if(s != null) return s; if(this.hierarchy.containsLocalMethod(clname, methname)) return null; } else { s = global_signatures.get(key); if(s != null) return s; if(this.hierarchy.containsLocalMethod(clname, methname)) return null; } //FIXME take global signature of the superclass String superclass = hierarchy.getSuperClass(clname); while(superclass != null && superclass != clname ) //&& hierarchy.containsMethod(cl2_name,meth_name) //&& !hierarchy.isPrivate(cl2_name + "." + meth_name)) { //CHANGED 10.03.2006 //Signature target = (Signature) global_signatures.get(superclass + "." + methname); //to Signature target = exact_signatures.get(superclass + "." + methname); if (target != null) { return target; } clname = superclass; superclass = hierarchy.getSuperClass(clname); } return null; } /** * @param _package a String * @param _class a String * @param _method a String * @return the signature wich correponds to _package._class._method method * or null if it does not yet exist. */ public Signature findExactSignature(String key) { return exact_signatures.get(key); } /** * @param _package a String * @param _class a String * @param _method a String * @return the signature wich correponds to _package._class._method method * or null if it does not yet exist. */ public Signature findGlobalSignature(String key) { return global_signatures.get(key); } /** * * @param key * @param sign * @param lock flag that specifies if the signature of the method is final or not. A signature is final * if it doesn't depend on other signatures or if all the signatures on which it depends are final */ public void putSignatureForcively(String key, Signature sign, boolean lock) { exact_signatures.put(key, sign); updated = true; Signature global = global_signatures.get(key); if (global == null) { global = (Signature) sign.clone(); global.setFinal(false); global_signatures.put(key, global); } else if (!sign.compatibleWith(global)) { // update global to accept sign global.makeAccept(sign); } updateGlobalBranch(sign, key, lock); } public void putApproximateSignatureForcively(String key, Signature sign) { global_signatures.put(key,sign); } public void putSignature(String key, Signature sign, boolean lock) { if(exact_signatures.get(key) != null && exact_signatures.get(key).isLocked()) { Printer.println("This signature cannot be changed now or it has already reached a fixed-point"); return; } if(lock) sign.setFinal(true); if(!sign.equals(exact_signatures.get(key)) ){ //System.err.println("## Replacing : " + exact_signatures.get(key)); //System.err.println("## With : " + sign); putSignatureForcively(key,sign, lock); } } private void updateGlobalBranch(Signature sign, String key, boolean lock) { String cl_name = keyClassName(key); String meth_name = keyMethodName(key); String[] inames = hierarchy.getInterfacesClosure(cl_name); if(inames != null) { for(int i = 0; i < inames.length; i++) { if (hierarchy.containsMethod(inames[i],meth_name)) { Signature target = global_signatures.get(inames[i] + "." + meth_name); if (target == null) global_signatures.put(inames[i] + "." + meth_name,(Signature)sign.clone()); else{ lock = lock && target.isFinal(); if(!sign.compatibleWith(target)) target.makeAccept(sign); } // Printer.debugPrintln("### Unified : " + inames[i] + "." + meth_name); // Printer.debugPrintln(""+target); } } } LinkedList queue = new LinkedList(); // Add to end of queue queue.add(cl_name); while(!queue.isEmpty()) { //Get head of queue String name = queue.removeFirst(); String[] subnames = hierarchy.getSubClasses(name); if(subnames!=null) for(int i = 0; i < subnames.length; i++) { if (!hierarchy.containsLocalMethod(subnames[i],meth_name)) { Signature target = global_signatures.get(subnames[i] + "." + meth_name); if (target == null) global_signatures.put(subnames[i] + "." + meth_name,(Signature)sign.clone()); else { if(!sign.compatibleWith(target)) target.makeAccept(sign); } queue.add(subnames[i]); } } } // COMMENTED 8.03.2006 /* String[] subnames = hierarchy.getSubClassesClosure(cl_name); if(subnames != null) { for(int i = 0; i < subnames.length; i++) { if (hierarchy.containsMethod(subnames[i],meth_name)) { Signature target = (Signature) global_signatures.get(subnames[i] + "." + meth_name); if (target == null) global_signatures.put(subnames[i] + "." + meth_name,sign.clone()); else { lock = lock && target.isFinal(); if(!sign.compatibleWith(target)) target.makeAccept(sign); } } } } */ String cl2_name = hierarchy.getSuperClass(cl_name); while(cl2_name != null && cl2_name != cl_name && hierarchy.containsMethod(cl2_name,meth_name) && !hierarchy.isPrivate(cl2_name + "." + meth_name)) { Signature target = global_signatures.get(cl2_name + "." + meth_name); if (target == null) { String name = cl2_name + "." + meth_name; global_signatures.put(name,(Signature)sign.clone()); } else{ if(!sign.compatibleWith(target)) { target.makeAccept(sign); sign = target; } } cl_name = cl2_name; cl2_name = hierarchy.getSuperClass(cl_name); } } /** * @param key * @return true if this SignatureDictionary contains a signature mapped to * 'key'. */ public boolean contains(String key) { return this.exact_signatures.containsKey(key); } /** * @return */ public boolean isChanged() { return updated; } /** * */ public void setUnChanged() { updated = false; } public static String key(JavaClass c, Method m) { String name = c.getClassName() + "." + m.getName() + m.getSignature(); return key(name); } public static String key(String base) { return base.replaceAll("fr.lifl.rd2p.jits","java").replaceAll("fr/lifl/rd2p/jits","java"); } public ClassHierarchy getClassHierarchy() { return hierarchy; } public void registerClass(JavaClass cl) { hierarchy.register(cl); } public void registerMethods(JavaClass cl) { hierarchy.registerMethods(cl); } public static String key(String className, String methodName, String methodSign) { String name = className+"."+methodName+methodSign; //return name; return name.replaceAll("fr.lifl.rd2p.jits","java").replaceAll("fr/lifl/rd2p/jits","java"); } public static String keyClassName(String key) { return key.substring(0,key.lastIndexOf('.')); } public static String keyOnlyMethodName(String key) { return key.substring(key.lastIndexOf('.')+1, key.indexOf('(')); } public static String keyDescription(String key) { return key.substring(key.indexOf('(')); } public static String key(InvokeInstruction i, ConstantPoolGen cpg) { String name = i.getClassName(cpg) + "." + i.getMethodName(cpg) + i.getSignature(cpg); return key(name); } public static String keyMethodName(String key) { return key.substring(key.lastIndexOf('.')+1); } public static String keyFieldName(String key) { return key.substring(key.lastIndexOf('.')+1); } public static String keyJits(String key) { //return name; return key.replaceAll("java.", "fr.lifl.rd2p.jits.").replaceAll("java/","fr/lifl/rd2p/jits/"); } private void lock() { Collection s = exact_signatures.values(); for (Iterator it = s.iterator(); it.hasNext();) { Signature element = it.next(); element.lock(); } s = global_signatures.values(); for (Iterator it = s.iterator(); it.hasNext();) { Signature element = it.next(); element.lock(); } } public void printHierarchy(){ Printer.println(this.hierarchy.toString()); } }