1 cananian 1.1 // ImplMagic.java, created Fri Oct 16 00:29:13 1998 by cananian 2 cananian 1.5 // Copyright (C) 1998 C. Scott Ananian <cananian@alumni.princeton.edu> 3 cananian 1.5 // Licensed under the terms of the GNU GPL; see COPYING for details. 4 cananian 1.1 package harpoon.ClassFile; 5 cananian 1.1 6 cananian 1.5.2.5 import harpoon.IR.RawClass.AttributeCode; 7 cananian 1.5.2.5 import harpoon.IR.RawClass.AttributeConstantValue; 8 cananian 1.5.2.5 import harpoon.IR.RawClass.AttributeExceptions; 9 cananian 1.5.2.5 import harpoon.IR.RawClass.AttributeSourceFile; 10 cananian 1.5.2.5 import harpoon.IR.RawClass.AttributeSynthetic; 11 cananian 1.5.2.5 import harpoon.IR.RawClass.ConstantClass; 12 cananian 1.5.2.5 import harpoon.IR.RawClass.ConstantValue; 13 cananian 1.1 import harpoon.Util.Util; 14 cananian 1.1 15 cananian 1.1 import java.lang.reflect.Modifier; 16 cananian 1.5.2.10 import java.util.ArrayList; 17 cananian 1.5.2.10 import java.util.HashMap; 18 cananian 1.5.2.10 import java.util.List; 19 cananian 1.5.2.10 import java.util.Map; 20 cananian 1.5.2.2 21 cananian 1.1 /** 22 cananian 1.1 * <code>ImplMagic</code> provides concrete implementation for 23 cananian 1.1 * <code>HClass</code>, <code>HMethod</code>, <code>HConstructor</code>, 24 cananian 1.5.2.5 * and <code>HField</code> using the <code>harpoon.IR.RawClass</code> 25 cananian 1.1 * package. 26 cananian 1.1 * 27 cananian 1.1 * @author C. Scott Ananian <cananian@alumni.princeton.edu> 28 cananian 1.8 * @version $Id: ImplMagic.java,v 1.8 2002/04/10 03:04:15 cananian Exp $ 29 cananian 1.1 */ 30 cananian 1.1 abstract class ImplMagic { // wrapper for the Real McCoy. 31 cananian 1.1 32 cananian 1.5.2.9 static HClass forStream(Linker linker, java.io.InputStream is) 33 cananian 1.5.2.9 throws java.io.IOException { 34 cananian 1.5.2.5 harpoon.IR.RawClass.ClassFile raw = 35 cananian 1.5.2.5 new harpoon.IR.RawClass.ClassFile(is); 36 cananian 1.5.2.9 return new MagicClass(linker, raw); 37 cananian 1.1 } 38 cananian 1.1 39 cananian 1.1 static class MagicClass extends HClassCls { 40 cananian 1.1 /** Creates a <code>MagicClass</code> from a 41 cananian 1.5.2.5 * <code>harpoon.IR.RawClass.ClassFile</code>. */ 42 cananian 1.5.2.9 MagicClass(Linker linker, harpoon.IR.RawClass.ClassFile classfile) { 43 cananian 1.5.2.9 super(linker); 44 cananian 1.1 this.name = classfile.this_class().name().replace('/','.'); 45 cananian 1.1 this.superclass = (classfile.super_class == 0)?null: 46 cananian 1.5.2.9 new ClassPointer(linker, 47 cananian 1.5.2.9 "L"+classfile.super_class().name()+";"); 48 cananian 1.5.2.2 this.interfaces = new HPointer[classfile.interfaces_count()]; 49 cananian 1.1 for (int i=0; i<interfaces.length; i++) 50 cananian 1.1 interfaces[i] = 51 cananian 1.5.2.9 new ClassPointer(linker, 52 cananian 1.5.2.9 "L"+classfile.interfaces(i).name()+";"); 53 cananian 1.1 this.modifiers = classfile.access_flags.access_flags; 54 cananian 1.1 this.declaredFields = new HField[classfile.fields.length]; 55 cananian 1.1 for (int i=0; i<declaredFields.length; i++) 56 cananian 1.1 declaredFields[i] = new MagicField(this, classfile.fields[i]); 57 cananian 1.1 this.declaredMethods = new HMethod[classfile.methods.length]; 58 cananian 1.1 for (int i=0; i<declaredMethods.length; i++) 59 cananian 1.1 declaredMethods[i] = // constructors are different. 60 cananian 1.1 (classfile.methods[i].name().equals("<init>")) 61 cananian 1.5.2.1 ?(HMethod)new MagicConstructor(this, classfile.methods[i]) 62 cananian 1.5.2.1 :(classfile.methods[i].name().equals("<clinit>")) 63 cananian 1.5.2.1 ?(HMethod)new MagicInitializer(this, classfile.methods[i]) 64 cananian 1.1 :(HMethod)new MagicMethod(this, classfile.methods[i]); 65 cananian 1.1 this.sourcefile = ""; 66 cananian 1.1 for (int i=0; i<classfile.attributes.length; i++) 67 cananian 1.1 if (classfile.attributes[i] instanceof AttributeSourceFile) { 68 cananian 1.1 this.sourcefile = 69 cananian 1.1 ((AttributeSourceFile)classfile.attributes[i]) 70 cananian 1.1 .sourcefile(); 71 cananian 1.1 break; 72 cananian 1.1 } 73 cananian 1.5.2.6 // for some odd reason, interfaces have 'java.lang.Object' 74 cananian 1.5.2.6 // as their superclass in the class file format. In the 75 cananian 1.5.2.6 // rarified "real world", interfaces have *no* superclass. 76 cananian 1.5.2.6 // So fix fantasy to match reality. See the Java Virtual 77 cananian 1.5.2.6 // Machine Specification, section 4.1, which offers zero 78 cananian 1.5.2.6 // explanation for this strange behaviour. 79 cananian 1.5.2.6 if (isInterface()) this.superclass = null; 80 cananian 1.1 } 81 cananian 1.5.2.3 // optimize hashcode. 82 cananian 1.5.2.11 private transient int hashcode=0; 83 cananian 1.5.2.11 public int hashCode() { // 1 in 2^32 chance of recomputing frequently. 84 cananian 1.5.2.11 if (hashcode==0) hashcode = super.hashCode(); 85 cananian 1.5.2.11 return hashcode; 86 cananian 1.5.2.11 } 87 cananian 1.1 } // END MagicClass 88 cananian 1.1 89 cananian 1.5.2.1 // utility function to initialize HMethod/HConstructor/HInitializer. 90 cananian 1.5.2.9 static private final void initMethod(HMethodImpl _this, HClass parent, 91 cananian 1.5.2.5 harpoon.IR.RawClass.MethodInfo methodinfo) { 92 cananian 1.1 _this.parent = parent; 93 cananian 1.1 _this.name = methodinfo.name(); 94 cananian 1.1 _this.modifiers = methodinfo.access_flags.access_flags; 95 cananian 1.1 { // returnTypes 96 cananian 1.1 String desc = methodinfo.descriptor(); 97 cananian 1.1 // snip off everything but the return value descriptor. 98 cananian 1.1 desc = desc.substring(desc.lastIndexOf(')')+1); 99 cananian 1.5.2.9 _this.returnType = new ClassPointer(parent.getLinker(), desc); 100 cananian 1.1 } 101 cananian 1.1 { // parameterTypes 102 cananian 1.1 String desc = methodinfo.descriptor(); 103 cananian 1.1 // snip off everything but the parameter list descriptors. 104 cananian 1.1 desc = desc.substring(1, desc.lastIndexOf(')')); 105 cananian 1.5.2.10 List v = new ArrayList(); 106 cananian 1.1 for (int i=0; i<desc.length(); i++) { 107 cananian 1.1 // make HClass for first param in list. 108 cananian 1.5.2.10 v.add(new ClassPointer(parent.getLinker(), 109 cananian 1.5.2.10 desc.substring(i))); 110 cananian 1.1 // skip over the one we just added. 111 cananian 1.1 while (desc.charAt(i)=='[') i++; 112 cananian 1.1 if (desc.charAt(i)=='L') i=desc.indexOf(';', i); 113 cananian 1.1 } 114 cananian 1.5.2.10 _this.parameterTypes = (HPointer[]) 115 cananian 1.5.2.10 v.toArray(new HPointer[v.size()]); 116 cananian 1.1 } 117 cananian 1.1 // Make sure our parsing/construction is correct. 118 cananian 1.5.2.2 // COMMENTED OUT because it was causing us to load unnecessary classes 119 cananian 1.7.2.1 //assert _this.getDescriptor().equals(methodinfo.descriptor()); 120 cananian 1.1 121 cananian 1.1 AttributeCode code = null; 122 cananian 1.1 AttributeExceptions exceptions = null; 123 cananian 1.1 AttributeSynthetic synthetic = null; 124 cananian 1.1 // Crunch the attribute information. 125 cananian 1.1 for (int i=0; i<methodinfo.attributes.length; i++) { 126 cananian 1.1 if (methodinfo.attributes[i] instanceof AttributeCode) 127 cananian 1.1 code = (AttributeCode) methodinfo.attributes[i]; 128 cananian 1.1 else if (methodinfo.attributes[i] instanceof AttributeExceptions) 129 cananian 1.1 exceptions=(AttributeExceptions) methodinfo.attributes[i]; 130 cananian 1.1 else if (methodinfo.attributes[i] instanceof AttributeSynthetic) 131 cananian 1.1 synthetic =(AttributeSynthetic) methodinfo.attributes[i]; 132 cananian 1.1 } 133 cananian 1.1 134 cananian 1.1 { // parameterNames 135 cananian 1.1 _this.parameterNames = new String[_this.parameterTypes.length]; 136 cananian 1.1 // for non-static methods, 0th local variable is 'this'. 137 cananian 1.1 int offset = _this.isStatic()?0:1; 138 cananian 1.1 // assign names. 139 cananian 1.1 for (int i=0; i<_this.parameterNames.length; i++) { 140 cananian 1.1 _this.parameterNames[i]= 141 cananian 1.1 ((code==null)?null: 142 cananian 1.1 code.localName(0/*pc*/, offset)); 143 cananian 1.1 // longs and doubles take up two local variable slots. 144 cananian 1.1 offset += (_this.parameterTypes[i]==HClass.Double || 145 cananian 1.1 _this.parameterTypes[i]==HClass.Long) ? 2 : 1; 146 cananian 1.1 } 147 cananian 1.1 } 148 cananian 1.1 { // exceptionTypes: 149 cananian 1.1 if (exceptions == null) 150 cananian 1.1 _this.exceptionTypes = new HClass[0]; 151 cananian 1.1 else { 152 cananian 1.5.2.10 List v = new ArrayList(); 153 cananian 1.1 for (int i=0; i<exceptions.number_of_exceptions(); i++) { 154 cananian 1.1 ConstantClass cc = exceptions.exception_index_table(i); 155 cananian 1.1 if (cc != null) 156 cananian 1.5.2.10 v.add(new ClassPointer(parent.getLinker(), 157 cananian 1.5.2.10 "L"+cc.name()+";")); 158 cananian 1.1 } 159 cananian 1.5.2.10 _this.exceptionTypes = (HPointer[]) 160 cananian 1.5.2.10 v.toArray(new HPointer[v.size()]); 161 cananian 1.1 } 162 cananian 1.1 } 163 cananian 1.1 _this.isSynthetic = (synthetic!=null); 164 cananian 1.3 165 cananian 1.1 // Add the default code representation, if method is not native. 166 cananian 1.1 if (!Modifier.isNative(_this.getModifiers()) && 167 cananian 1.1 !Modifier.isAbstract(_this.getModifiers())) 168 cananian 1.5.2.12 repository.put(meth2str(_this), methodinfo); 169 cananian 1.5.2.12 } 170 cananian 1.5.2.12 171 cananian 1.5.2.12 // keys in repository are strings, to avoid conflict-of-linker problems. 172 cananian 1.5.2.12 private static String meth2str(HMethod m) { 173 cananian 1.5.2.12 return m.getDeclaringClass().getName()+"."+m.getName()+ 174 cananian 1.5.2.12 m.getDescriptor(); 175 cananian 1.1 } 176 cananian 1.1 177 cananian 1.5.2.10 static final Map repository = new HashMap(); 178 cananian 1.5.2.8 public static final HCodeFactory codeFactory = new SerializableCodeFactory() { 179 cananian 1.5.2.7 public String getCodeName() 180 cananian 1.5.2.7 { return harpoon.IR.Bytecode.Code.codename; } 181 cananian 1.5.2.7 public HCode convert(HMethod m) 182 cananian 1.5.2.7 { 183 cananian 1.5.2.7 harpoon.IR.RawClass.MethodInfo methodinfo = 184 cananian 1.5.2.12 (harpoon.IR.RawClass.MethodInfo) repository.get(meth2str(m)); 185 cananian 1.5.2.7 if (methodinfo==null) return null; 186 cananian 1.5.2.7 else return new harpoon.IR.Bytecode.Code(m, methodinfo); 187 cananian 1.5.2.7 } 188 cananian 1.5.2.7 public void clear(HMethod m) { 189 cananian 1.5.2.7 repository.remove(m); // make methodinfo garbage. 190 cananian 1.5.2.7 } 191 cananian 1.5.2.7 }; 192 cananian 1.5.2.7 193 cananian 1.5.2.9 static class MagicMethod extends HMethodImpl { 194 cananian 1.1 /** Creates a <code>MagicMethod</code> from a 195 cananian 1.5.2.5 * <code>harpoon.IR.RawClass.MethodInfo</code>. */ 196 cananian 1.1 MagicMethod(HClass parent, 197 cananian 1.5.2.5 harpoon.IR.RawClass.MethodInfo methodinfo) { 198 cananian 1.1 initMethod(this, parent, methodinfo); 199 cananian 1.1 } 200 cananian 1.5.2.3 // optimize hashcode. 201 cananian 1.5.2.9 private transient int hashcode=0; 202 cananian 1.5.2.4 public int hashCode() { // 1 in 2^32 chance of recomputing frequently. 203 cananian 1.5.2.3 if (hashcode==0) hashcode = super.hashCode(); 204 cananian 1.5.2.3 return hashcode; 205 cananian 1.5.2.3 } 206 cananian 1.1 } // END MagicMethod 207 cananian 1.1 208 cananian 1.5.2.9 static class MagicConstructor extends HConstructorImpl { 209 cananian 1.1 /** Creates a <code>MagicConstructor</code> from a 210 cananian 1.5.2.5 * <code>harpoon.IR.RawClass.MethodInfo</code>. */ 211 cananian 1.1 MagicConstructor(HClass parent, 212 cananian 1.5.2.5 harpoon.IR.RawClass.MethodInfo methodinfo) { 213 cananian 1.1 initMethod(this, parent, methodinfo); 214 cananian 1.1 } 215 cananian 1.5.2.3 // optimize hashcode. 216 cananian 1.5.2.9 private transient int hashcode=0; 217 cananian 1.5.2.4 public int hashCode() { // 1 in 2^32 chance of recomputing frequently. 218 cananian 1.5.2.3 if (hashcode==0) hashcode = super.hashCode(); 219 cananian 1.5.2.3 return hashcode; 220 cananian 1.5.2.3 } 221 cananian 1.1 } // END MagicConstructor 222 cananian 1.1 223 cananian 1.5.2.9 static class MagicInitializer extends HInitializerImpl { 224 cananian 1.5.2.1 /** Creates a <code>MagicInitializer</code> from a 225 cananian 1.5.2.5 * <code>harpoon.IR.RawClass.MethodInfo</code>. */ 226 cananian 1.5.2.1 MagicInitializer(HClass parent, 227 cananian 1.5.2.5 harpoon.IR.RawClass.MethodInfo methodinfo) { 228 cananian 1.5.2.1 initMethod(this, parent, methodinfo); 229 cananian 1.5.2.1 } 230 cananian 1.5.2.3 // optimize hashcode. 231 cananian 1.5.2.9 private transient int hashcode=0; 232 cananian 1.5.2.4 public int hashCode() { // 1 in 2^32 chance of recomputing frequently. 233 cananian 1.5.2.3 if (hashcode==0) hashcode = super.hashCode(); 234 cananian 1.5.2.3 return hashcode; 235 cananian 1.5.2.3 } 236 cananian 1.5.2.1 } // END MagicInitializer 237 cananian 1.1 238 cananian 1.5.2.9 static class MagicField extends HFieldImpl { 239 cananian 1.1 /** Creates a <code>MagicField</code> from a 240 cananian 1.5.2.5 * <code>harpoon.IR.RawClass.FieldInfo</code>. */ 241 cananian 1.1 MagicField(HClass parent, 242 cananian 1.5.2.5 harpoon.IR.RawClass.FieldInfo fieldinfo) { 243 cananian 1.1 this.parent = parent; 244 cananian 1.5.2.9 this.type = new ClassPointer(parent.getLinker(), 245 cananian 1.5.2.9 fieldinfo.descriptor()); 246 cananian 1.1 this.name = fieldinfo.name(); 247 cananian 1.1 this.modifiers = fieldinfo.access_flags.access_flags; 248 cananian 1.1 { 249 cananian 1.1 AttributeConstantValue attrconst = null; 250 cananian 1.1 for (int i=0; i<fieldinfo.attributes.length; i++) 251 cananian 1.1 if (fieldinfo.attributes[i] 252 cananian 1.1 instanceof AttributeConstantValue) { 253 cananian 1.1 attrconst = 254 cananian 1.1 (AttributeConstantValue) fieldinfo.attributes[i]; 255 cananian 1.1 break; 256 cananian 1.1 } 257 cananian 1.1 this.constValue = (attrconst==null) ? null : 258 cananian 1.1 ((ConstantValue)attrconst.constantvalue_index()).value(); 259 cananian 1.1 } 260 cananian 1.1 this.isSynthetic = false; 261 cananian 1.1 for (int i=0; i<fieldinfo.attributes.length; i++) 262 cananian 1.1 if (fieldinfo.attributes[i] instanceof AttributeSynthetic) 263 cananian 1.1 this.isSynthetic=true; 264 cananian 1.1 } 265 cananian 1.5.2.3 // optimize hashcode. 266 cananian 1.5.2.11 private transient int hashcode=0; 267 cananian 1.5.2.11 public int hashCode() { // 1 in 2^32 chance of recomputing frequently. 268 cananian 1.5.2.11 if (hashcode==0) hashcode = super.hashCode(); 269 cananian 1.5.2.11 return hashcode; 270 cananian 1.1 } 271 cananian 1.1 } // END MagicField 272 cananian 1.1 }