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      }