1 cananian 1.1.2.1  // DataReflection2.java, created Sat Oct 16 15:48:14 1999 by cananian
  2 cananian 1.1.2.1  // Copyright (C) 1999 C. Scott Ananian <cananian@alumni.princeton.edu>
  3 cananian 1.1.2.1  // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 cananian 1.1.2.1  package harpoon.Backend.Runtime1;
  5 cananian 1.1.2.1  
  6 cananian 1.1.2.1  import harpoon.Analysis.ClassHierarchy;
  7 cananian 1.1.2.1  import harpoon.Backend.Generic.Frame;
  8 cananian 1.1.2.1  import harpoon.Backend.Maps.NameMap;
  9 cananian 1.1.2.1  import harpoon.ClassFile.HClass;
 10 cananian 1.1.2.2  import harpoon.ClassFile.HConstructor;
 11 cananian 1.1.2.1  import harpoon.ClassFile.HDataElement;
 12 cananian 1.1.2.2  import harpoon.ClassFile.HField;
 13 cananian 1.1.2.2  import harpoon.ClassFile.HMember;
 14 cananian 1.1.2.1  import harpoon.ClassFile.HMethod;
 15 cananian 1.1.2.1  import harpoon.IR.Tree.Stm;
 16 cananian 1.1.2.1  import harpoon.IR.Tree.TreeFactory;
 17 cananian 1.1.2.3  import harpoon.IR.Tree.ALIGN;
 18 cananian 1.1.2.2  import harpoon.IR.Tree.CONST;
 19 cananian 1.1.2.1  import harpoon.IR.Tree.LABEL;
 20 cananian 1.1.2.1  import harpoon.IR.Tree.SEGMENT;
 21 cananian 1.1.2.1  import harpoon.Temp.Label;
 22 cananian 1.1.2.1  
 23 cananian 1.1.2.2  import java.lang.reflect.Modifier;
 24 cananian 1.1.2.1  import java.util.ArrayList;
 25 cananian 1.1.2.2  import java.util.Arrays;
 26 cananian 1.1.2.2  import java.util.Collections;
 27 cananian 1.1.2.2  import java.util.Comparator;
 28 cananian 1.1.2.2  import java.util.Iterator;
 29 cananian 1.1.2.1  import java.util.List;
 30 cananian 1.1.2.1  /**
 31 cananian 1.1.2.1   * <code>DataReflection2</code> generates class information tables
 32 cananian 1.1.2.1   * for each class, with lots of juicy information needed by JNI and
 33 cananian 1.1.2.1   * java language reflection.  The class information table includes:
 34 cananian 1.1.2.1   * <UL>
 35 cananian 1.1.2.1   *  <LI>A pointer to a UTF-8 encoded string naming the class.
 36 cananian 1.1.2.1   *  <LI>A pointer to the claz structure containing the dispatch
 37 cananian 1.1.2.1   *      tables & etc. (See <code>DataClaz</code>.)
 38 cananian 1.1.2.12  *  <LI>The java access modifiers of the class.
 39 cananian 1.1.2.1   *  <LI>A sorted map of member signatures to method and field offsets.
 40 cananian 1.1.2.1   * </UL>
 41 cananian 1.1.2.1   * 
 42 cananian 1.1.2.1   * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 43 cananian 1.6       * @version $Id: DataReflection2.java,v 1.6 2004/02/08 03:20:58 cananian Exp $
 44 cananian 1.1.2.1   */
 45 cananian 1.1.2.1  public class DataReflection2 extends Data {
 46 cananian 1.1.2.1      final TreeBuilder m_tb;
 47 cananian 1.1.2.1      final NameMap m_nm;
 48 cananian 1.4          final boolean pointersAreLong;
 49 cananian 1.1.2.1      
 50 cananian 1.1.2.1      /** Creates a <code>DataReflection2</code>. */
 51 cananian 1.4          public DataReflection2(Frame f, HClass hc, ClassHierarchy ch) {
 52 cananian 1.1.2.1          super("reflection-data-2", hc, f);
 53 cananian 1.1.2.13         this.m_nm = f.getRuntime().getNameMap();
 54 cananian 1.1.2.13         this.m_tb = (TreeBuilder) f.getRuntime().getTreeBuilder();
 55 cananian 1.4              this.pointersAreLong = f.pointersAreLong();
 56 cananian 1.1.2.1          this.root = build(hc, ch);
 57 cananian 1.1.2.1      }
 58 cananian 1.1.2.1      private HDataElement build(HClass hc, ClassHierarchy ch) {
 59 cananian 1.1.2.2          List members = sortedMembers(hc);
 60 cananian 1.5              int ptrsz = pointersAreLong ? 8 : 4;
 61 cananian 1.1.2.2  
 62 cananian 1.1.2.2          List stmlist = new ArrayList(6+7*members.size()/* at least*/);
 63 cananian 1.1.2.1          stmlist.add(new SEGMENT(tf, null, SEGMENT.REFLECTION_DATA));
 64 cananian 1.5              stmlist.add(new ALIGN(tf, null, ptrsz));// align table to word boundary
 65 cananian 1.1.2.1          stmlist.add(new LABEL(tf, null, m_nm.label(hc, "classinfo"), true));
 66 cananian 1.1.2.1          // first field: a claz structure pointer.
 67 cananian 1.1.2.7          stmlist.add(_DATUM(m_nm.label(hc)));
 68 cananian 1.1.2.1          // next, a name string pointer.
 69 cananian 1.1.2.7          stmlist.add(_DATUM(m_nm.label(hc, "namestr")));
 70 cananian 1.1.2.12         // the java access modifiers for this class
 71 cananian 1.1.2.12         stmlist.add(_DATUM(new CONST(tf, null, hc.getModifiers())));
 72 cananian 1.4              // padding for 64-bit platforms.
 73 cananian 1.4              if (pointersAreLong)
 74 cananian 1.4                  stmlist.add(_DATUM(new CONST(tf, null, 0)));
 75 cananian 1.1.2.2          // pointer to the end of the lookup table.
 76 cananian 1.1.2.7          stmlist.add(_DATUM(m_nm.label(hc, "classinfo_end")));
 77 cananian 1.1.2.2          // okay, now the sorted name, desc, offset table.
 78 cananian 1.6              for (Object hmO : members) {
 79 cananian 1.6                  HMember hm = (HMember) hmO;
 80 cananian 1.1.2.2              if (hm instanceof HMethod && !ch.callableMethods().contains(hm))
 81 cananian 1.1.2.2                  continue; // skip uncallable methods.
 82 cananian 1.1.2.10             if (hm.getDeclaringClass().equals(hc))//member info for decl'd only
 83 cananian 1.1.2.10                 stmlist.add(new LABEL(tf, null, memberLabel(hm,"info"), true));
 84 cananian 1.1.2.7              stmlist.add(_DATUM(memberLabel(hm, "namestr")));
 85 cananian 1.1.2.7              stmlist.add(_DATUM(memberLabel(hm, "descstr")));
 86 cananian 1.1.2.11             stmlist.add(_DATUM(memberLabel(hm, "reflectinfo")));
 87 cananian 1.1.2.2              if (!memberVirtual(hm))
 88 cananian 1.1.2.7                  stmlist.add(_DATUM(memberLabel(hm, null)));
 89 cananian 1.1.2.2              else if (pointersAreLong)
 90 cananian 1.1.2.7                  stmlist.add(_DATUM(new CONST(tf, null,(long)memberOffset(hm))));
 91 cananian 1.1.2.2              else
 92 cananian 1.1.2.7                  stmlist.add(_DATUM(new CONST(tf, null,(int) memberOffset(hm))));
 93 cananian 1.1.2.4              // count number of argument words for methods
 94 cananian 1.1.2.4              emitNargs(stmlist, hm);
 95 cananian 1.1.2.2          }
 96 cananian 1.1.2.2          // ok, mark the end of the table.
 97 cananian 1.1.2.2          stmlist.add(new LABEL(tf, null,
 98 cananian 1.1.2.2                                m_nm.label(hc, "classinfo_end"), false));
 99 cananian 1.3              // We need to put something after the label to keep gcc from
100 cananian 1.3              // moving classinfo_end into the .bss section when compiling with
101 cananian 1.3              // the PreciseC backend.
102 cananian 1.3              stmlist.add(_DATUM(m_nm.label(hc, "classinfo_end")));
103 cananian 1.1.2.2          // now make the actual string data bits.
104 cananian 1.1.2.2          // (only for members we actually declare)
105 cananian 1.6              for (Object hmO : members) {
106 cananian 1.6                  HMember hm = (HMember) hmO;
107 cananian 1.1.2.2              if (hm instanceof HMethod && !ch.callableMethods().contains(hm))
108 cananian 1.1.2.2                  continue; // skip uncallable methods.
109 cananian 1.1.2.2              // only make string data for the members we declare
110 cananian 1.1.2.2              if (hm.getDeclaringClass() != hc) continue;
111 cananian 1.1.2.2              // first name string.
112 cananian 1.1.2.8              stmlist.add(new LABEL(tf, null, memberLabel(hm,"namestr"), true));
113 cananian 1.1.2.6              stmlist.add(emitUtf8String(hm.getName()));
114 cananian 1.1.2.2              // then descriptor string.
115 cananian 1.1.2.8              stmlist.add(new LABEL(tf, null, memberLabel(hm,"descstr"), true));
116 cananian 1.1.2.6              stmlist.add(emitUtf8String(hm.getDescriptor()));
117 cananian 1.1.2.2          }
118 cananian 1.1.2.3          // pad out to full word after last string bit.
119 cananian 1.5              stmlist.add(new ALIGN(tf, null, ptrsz));
120 cananian 1.1.2.2          // done, yay, whee.
121 cananian 1.1.2.1          return (HDataElement) Stm.toStm(stmlist);
122 cananian 1.1.2.2      }
123 cananian 1.1.2.2      private boolean memberVirtual(HMember hmf) {
124 cananian 1.1.2.2          if (hmf instanceof HField) return !((HField)hmf).isStatic();
125 cananian 1.1.2.2          HMethod hm = (HMethod) hmf;
126 cananian 1.1.2.2          if (hm instanceof HConstructor) return false;
127 cananian 1.1.2.2          if (hm.isStatic()) return false;
128 cananian 1.1.2.2          if (Modifier.isPrivate(hm.getModifiers())) return false;
129 cananian 1.1.2.2          return true;
130 cananian 1.1.2.2      }
131 cananian 1.1.2.2      private Label memberLabel(HMember hm, String suffix) {
132 cananian 1.1.2.2          if (hm instanceof HField)
133 cananian 1.1.2.2              return m_nm.label((HField)hm, suffix);
134 cananian 1.1.2.2          else return m_nm.label((HMethod)hm, suffix);
135 cananian 1.1.2.2      }
136 cananian 1.1.2.14     /* some methods are both defined in interfaces *and* inherited from
137 cananian 1.1.2.14      * java.lang.Object.  Use the java.lang.Object version. */
138 cananian 1.1.2.14     private HMethod remap(HMethod hm) {
139 cananian 1.1.2.14         try {
140 cananian 1.1.2.14             return linker.forName("java.lang.Object")
141 cananian 1.1.2.14                 .getMethod(hm.getName(), hm.getDescriptor());
142 cananian 1.1.2.14         } catch (NoSuchMethodError nsme) {
143 cananian 1.1.2.14             return hm;
144 cananian 1.1.2.14         }
145 cananian 1.1.2.14     }
146 cananian 1.1.2.2      private int memberOffset(HMember hmf) {
147 cananian 1.1.2.2          if (hmf instanceof HField)
148 cananian 1.1.2.5              return  m_tb.OBJ_FZERO_OFF + m_tb.cfm.fieldOffset((HField)hmf);
149 cananian 1.1.2.14         HMethod hm = remap((HMethod) hmf);
150 cananian 1.1.2.5          if (hm.isInterfaceMethod())
151 cananian 1.1.2.5              return m_tb.CLAZ_INTERFACES_OFF -
152 cananian 1.1.2.5                  m_tb.POINTER_SIZE * m_tb.imm.methodOrder(hm);
153 cananian 1.1.2.5          // virtual method
154 cananian 1.1.2.5          return m_tb.CLAZ_METHODS_OFF +
155 cananian 1.1.2.5              m_tb.POINTER_SIZE * m_tb.cmm.methodOrder(hm);
156 cananian 1.1.2.4      }
157 cananian 1.1.2.4      private void emitNargs(List stmlist, HMember hmf) {
158 cananian 1.1.2.4          final int REGS_PER_WORD = 1;
159 cananian 1.1.2.4          final int REGS_PER_DOUBLEWORD = (pointersAreLong) ? 1 : 2;
160 cananian 1.1.2.4          final int REGS_PER_POINTER = 1;
161 cananian 1.1.2.4  
162 cananian 1.1.2.4          int nargs=0;
163 cananian 1.1.2.4          if (hmf instanceof HMethod) {
164 cananian 1.1.2.4              if (!((HMethod)hmf).isStatic()) nargs+=REGS_PER_POINTER;
165 cananian 1.1.2.4              String desc=hmf.getDescriptor();
166 cananian 1.1.2.4              for (int i=1; desc.charAt(i)!=')'; i++) { // skip leading '('
167 cananian 1.1.2.4                  switch (desc.charAt(i)) {
168 cananian 1.1.2.4                  case 'B': case 'C': case 'F': case 'I': case 'S': case 'Z':
169 cananian 1.1.2.4                      nargs+=REGS_PER_WORD; break;
170 cananian 1.1.2.4                  case 'J': case 'D':
171 cananian 1.1.2.4                      nargs+=REGS_PER_DOUBLEWORD; break;
172 cananian 1.1.2.4                  case 'L':
173 cananian 1.1.2.4                      nargs+=REGS_PER_POINTER;
174 cananian 1.1.2.4                      i=desc.indexOf(';', i); break;
175 cananian 1.1.2.4                  case '[':
176 cananian 1.1.2.4                      nargs+=REGS_PER_POINTER;
177 cananian 1.1.2.4                      do { i++; } while (desc.charAt(i)=='[');
178 cananian 1.1.2.4                      if (desc.charAt(i)=='L') i=desc.indexOf(';',i);
179 cananian 1.1.2.4                      break;
180 cananian 1.1.2.4                  default:
181 cananian 1.1.2.4                      throw new Error("Illegal signature: "+desc);
182 cananian 1.1.2.4                  }
183 cananian 1.1.2.4              }
184 cananian 1.1.2.4          }
185 cananian 1.1.2.4          // output nargs value.
186 cananian 1.1.2.4          if (pointersAreLong)
187 cananian 1.1.2.7              stmlist.add(_DATUM(new CONST(tf, null, (long) nargs)));
188 cananian 1.1.2.4          else
189 cananian 1.1.2.7              stmlist.add(_DATUM(new CONST(tf, null, (int) nargs)));
190 cananian 1.1.2.2      }
191 cananian 1.1.2.2      private List sortedMembers(HClass hc) {
192 cananian 1.1.2.2          List members = new ArrayList(Arrays.asList(hc.getFields()));
193 cananian 1.1.2.2          members.addAll(Arrays.asList(hc.getMethods()));
194 cananian 1.1.2.9          // add back private members of superclasses, which
195 cananian 1.1.2.9          // getFields()/getMethods() omit. [CSA FIX: 3-28-00]
196 cananian 1.1.2.9          for (HClass hcp=hc.getSuperclass();hcp!=null;hcp=hcp.getSuperclass()) {
197 cananian 1.1.2.9              List l = new ArrayList(Arrays.asList(hcp.getDeclaredFields()));
198 cananian 1.1.2.9              l.addAll(Arrays.asList(hcp.getDeclaredMethods()));
199 cananian 1.6                  for (Object hmO : l) {
200 cananian 1.6                      HMember hm = (HMember) hmO;
201 cananian 1.1.2.9                  if (Modifier.isPrivate(hm.getModifiers()))
202 cananian 1.1.2.9                      members.add(hm);
203 cananian 1.1.2.9              }
204 cananian 1.1.2.9          }
205 cananian 1.1.2.10         // add back 'length' field of arrays, which getFields() omits.
206 cananian 1.1.2.10         // [CSA FIX: 11-14-00]
207 cananian 1.1.2.10         if (hc.isArray()) members.add(hc.getDeclaredField("length"));
208 cananian 1.1.2.9          // okay, now sort members.
209 cananian 1.1.2.2          Collections.sort(members, new Comparator() {
210 cananian 1.1.2.2              public int compare(Object o1, Object o2) {
211 cananian 1.1.2.2                  HMember hm1 = (HMember) o1, hm2 = (HMember) o2;
212 cananian 1.1.2.2                  int r = compareUTF8(hm1.getName(), hm2.getName());
213 cananian 1.1.2.2                  return (r!=0) ? r :
214 cananian 1.1.2.2                      compareUTF8(hm1.getDescriptor(), hm2.getDescriptor());
215 cananian 1.1.2.2              }
216 cananian 1.1.2.2              private int compareUTF8(String s1, String s2) {
217 cananian 1.1.2.2                  byte[] b1 = toUTF8(s1), b2 = toUTF8(s2);
218 cananian 1.1.2.2                  for (int i=0; i<b1.length && i<b2.length; i++)
219 cananian 1.1.2.2                      if (b1[i] != b2[i])
220 cananian 1.1.2.2                          // ack.  we want an unsigned comparison
221 cananian 1.1.2.2                          return (((int)b1[i])&0xFF) - (((int)b2[i])&0xFF);
222 cananian 1.1.2.2                  // okay, they're equal, up to minlen.
223 cananian 1.1.2.2                  return b1.length - b2.length;
224 cananian 1.1.2.2              }           
225 cananian 1.1.2.2          });
226 cananian 1.1.2.2          return Collections.unmodifiableList(members);
227 cananian 1.1.2.1      }
228 cananian 1.2      }