1 cananian 1.1 // AbstractClassFixupRelinker.java, created Fri Jul 5 20:25:45 2002 by cananian 2 cananian 1.1 // Copyright (C) 2000 C. Scott Ananian <cananian@alumni.princeton.edu> 3 cananian 1.1 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 cananian 1.1 package harpoon.Analysis; 5 cananian 1.1 6 cananian 1.1 import harpoon.ClassFile.HClass; 7 cananian 1.4 import harpoon.ClassFile.HInitializer; 8 cananian 1.5 import harpoon.ClassFile.HField; 9 cananian 1.1 import harpoon.ClassFile.HMethod; 10 cananian 1.1 import harpoon.ClassFile.Linker; 11 cananian 1.1 import harpoon.ClassFile.Relinker; 12 cananian 1.1 import harpoon.Util.ArrayIterator; 13 cananian 1.10 import net.cscott.jutil.UniqueVector; 14 cananian 1.10 import net.cscott.jutil.WorkSet; 15 cananian 1.1 16 cananian 1.1 import java.lang.reflect.Modifier; 17 cananian 1.9 import java.util.HashSet; 18 cananian 1.9 import java.util.Iterator; 19 cananian 1.9 import java.util.Set; 20 cananian 1.1 /** 21 cananian 1.1 * <code>AbstractClassFixupRelinker</code> is an extension of <code>Relinker</code> 22 cananian 1.1 * which fixes up abstract classes so that they implement all the methods 23 cananian 1.1 * of their interfaces (even if this implementation is via an abstract 24 cananian 1.1 * method declaration). The newer JDK1.4 compiler that Sun provides does 25 cananian 1.1 * not put these method declarations in by default, unlike earlier 26 cananian 1.1 * compilers, and this violates several assumptions made in FLEX. 27 cananian 1.1 * The <code>AbstractClassFixupRelinker</code> remedies the situation. 28 cananian 1.1 * 29 cananian 1.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 30 cananian 1.11 * @version $Id: AbstractClassFixupRelinker.java,v 1.11 2004/02/08 03:19:12 cananian Exp $ 31 cananian 1.1 */ 32 cananian 1.1 public class AbstractClassFixupRelinker extends Relinker { 33 cananian 1.1 34 cananian 1.1 /** Creates a <code>AbstractClassFixupRelinker</code>. */ 35 cananian 1.1 public AbstractClassFixupRelinker(Linker linker) { 36 cananian 1.1 super(linker); 37 cananian 1.1 } 38 wbeebee 1.7 39 cananian 1.1 public HClass forDescriptor(String descriptor) { 40 wbeebee 1.7 // We want to make sure that Linker.forDescriptor completes 41 wbeebee 1.7 // entirely (entering the new class in the descriptor cache) 42 wbeebee 1.7 // before we invoke it again. HOWEVER, Linker.forDescriptor 43 wbeebee 1.7 // will call *us* recursively e.g. to resolve arrays. So it's 44 wbeebee 1.7 // not safe to do our resolve() stuff (which will indirectly 45 wbeebee 1.7 // cause further calls to Linker.forDescriptor) until we're 46 wbeebee 1.7 // sure the top-level call to Linker.forDescriptor has finished. 47 wbeebee 1.7 // The 'depth' variable here basically just keeps track of 48 wbeebee 1.7 // whether this is a recursive invocation via Linker.forDescriptor 49 wbeebee 1.7 // or a 'top-level' one; we only resolve after top-level calls. 50 wbeebee 1.7 depth++; 51 cananian 1.1 HClass hc = super.forDescriptor(descriptor); 52 wbeebee 1.7 depth--; 53 wbeebee 1.7 deferred.add(hc); 54 wbeebee 1.7 if (depth==0) // this is a top-level call, it's safe to resolve. 55 wbeebee 1.7 while (!deferred.isEmpty()) 56 wbeebee 1.7 resolve(deferred.removeFirst()); 57 wbeebee 1.7 return hc; 58 wbeebee 1.7 } 59 wbeebee 1.7 /** Set of classes waiting to be fixed up. */ 60 wbeebee 1.7 WorkSet<HClass> deferred = new WorkSet<HClass>(); 61 wbeebee 1.7 /** Current level of recursion. */ 62 wbeebee 1.7 int depth=0; 63 wbeebee 1.7 64 wbeebee 1.7 public HClass resolve(HClass hc) { 65 cananian 1.1 // okay, now scan the class and fix it up. 66 cananian 1.1 if (!hc.isInterface() && !done.contains(hc)) { 67 cananian 1.2 done.add(hc);// properly handle incidental recursion inside fixup() 68 cananian 1.2 // we should first fix up the superclass(es), if any. 69 cananian 1.1 HClass sc = hc.getSuperclass(); 70 wbeebee 1.7 if (sc!=null) resolve(sc); // recurse! 71 cananian 1.1 // okay, now fix this class up. 72 cananian 1.1 fixup(hc); 73 cananian 1.6 74 cananian 1.6 // and to prevent fixup from happening at inopportune times 75 cananian 1.6 // (such as after we start modifying method signatures) 76 cananian 1.6 // we're going to be aggressive in fixing up other classes 77 cananian 1.6 // mentioned in fields and methods of this one. 78 cananian 1.6 79 cananian 1.6 // fix up classes mentioned in method signatures 80 cananian 1.11 for (HMethod hm : hc.getDeclaredMethods()) { 81 wbeebee 1.7 resolve(hm.getReturnType()); 82 cananian 1.5 for (Iterator<HClass> it2=new ArrayIterator<HClass> 83 cananian 1.5 (hm.getParameterTypes()); it2.hasNext(); ) 84 wbeebee 1.7 resolve(it2.next()); 85 cananian 1.5 } 86 cananian 1.5 // and those in field signatures. 87 cananian 1.5 for (Iterator<HField> it=new ArrayIterator<HField> 88 cananian 1.5 (hc.getDeclaredFields()); it.hasNext(); ) 89 wbeebee 1.7 resolve(it.next().getType()); 90 cananian 1.1 } 91 cananian 1.1 // done! 92 cananian 1.1 return hc; 93 cananian 1.1 } 94 cananian 1.3 private static Set<HClass> done = new HashSet<HClass>(); 95 cananian 1.1 96 cananian 1.1 private void fixup(HClass hc) { 97 cananian 1.1 for (Iterator<HClass> it=collectInterfaces(hc).iterator(); 98 cananian 1.1 it.hasNext(); ) 99 cananian 1.1 fixupOne(hc, it.next()); 100 cananian 1.1 } 101 cananian 1.1 private void fixupOne(HClass hc, HClass anInterface) { 102 cananian 1.1 assert !hc.isInterface(); 103 cananian 1.1 assert anInterface.isInterface(); 104 cananian 1.1 // get list of interface methods. 105 cananian 1.11 for (HMethod hm : anInterface.getDeclaredMethods()) { 106 cananian 1.4 // could be a static initializer of the interface. 107 cananian 1.4 if (hm instanceof HInitializer) continue; 108 cananian 1.4 // otherwise this should be an interface method. 109 cananian 1.1 assert hm.isInterfaceMethod(); 110 cananian 1.1 // okay, look this up as a method of hc. if it doesn't exist, 111 cananian 1.1 // create it as a public abstract method. 112 cananian 1.1 HMethod hmm = hc.getMethod(hm.getName(), hm.getParameterTypes()); 113 cananian 1.1 if (hmm.isInterfaceMethod()) { 114 cananian 1.1 // NOT IMPLEMENTED IN CLASS! this better be an abstract class: 115 cananian 1.1 assert Modifier.isAbstract(hc.getModifiers()) : 116 cananian 1.1 "interface method "+hm+" not implemented in non-abstract "+ 117 cananian 1.1 "class "+hc; 118 cananian 1.1 // okay, it's an abstract class, so make an abstract 119 cananian 1.1 // implementation method. 120 cananian 1.1 HMethod nm=hc.getMutator().addDeclaredMethod 121 cananian 1.1 (hm.getName(), hm.getDescriptor()); 122 cananian 1.1 nm.getMutator().setModifiers 123 cananian 1.1 (Modifier.PUBLIC | Modifier.ABSTRACT); 124 cananian 1.1 nm.getMutator().setExceptionTypes(hm.getExceptionTypes()); 125 cananian 1.1 } 126 cananian 1.1 } 127 cananian 1.1 } 128 cananian 1.1 129 cananian 1.1 private static Set<HClass> collectInterfaces(HClass hc) { 130 cananian 1.1 UniqueVector<HClass> uv = new UniqueVector<HClass>(); 131 cananian 1.1 for (Iterator<HClass> it=new ArrayIterator<HClass>(hc.getInterfaces()); 132 cananian 1.1 it.hasNext(); ) 133 cananian 1.1 uv.add(it.next()); 134 cananian 1.1 // okay, uv now has the basic interfaces. we just have to 135 cananian 1.1 // go through it from beginning to end to add all superinterfaces. 136 cananian 1.1 for (int i=0; i<uv.size(); i++) 137 cananian 1.1 for (Iterator<HClass> it=new ArrayIterator<HClass> 138 cananian 1.1 (uv.get(i).getInterfaces()); it.hasNext(); ) 139 cananian 1.1 uv.add(it.next()); 140 cananian 1.1 // done! 141 cananian 1.1 return uv; 142 cananian 1.1 } 143 cananian 1.1 }