1 cananian 1.1.2.1 // HClassInfo.java, created Wed Jan 13 17:09:19 1999 by duncan
  2 cananian 1.1.2.2 // Copyright (C) 1998 Duncan Bryce <duncan@lcs.mit.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.Interpret.Tree;
  5 cananian 1.1.2.1 
  6 cananian 1.1.2.1 import harpoon.ClassFile.HClass;
  7 cananian 1.1.2.1 import harpoon.ClassFile.HField;
  8 cananian 1.1.2.1 import harpoon.ClassFile.HMember;
  9 cananian 1.1.2.1 import harpoon.ClassFile.HMethod;
 10 cananian 1.1.2.1 import harpoon.Util.HClassUtil;
 11 cananian 1.1.2.1 
 12 cananian 1.1.2.1 import java.util.HashMap;
 13 cananian 1.1.2.1 import java.util.Map;
 14 cananian 1.1.2.1 
 15 cananian 1.1.2.1 /**
 16 cananian 1.1.2.1  * The <code>HClassInfo</code> class provides various useful bits of 
 17 cananian 1.1.2.1  * information about an <code>HClass</code>. 
 18 cananian 1.1.2.1  *
 19 cananian 1.1.2.2  * @author  Duncan Bryce <duncan@lcs.mit.edu>
 20 cananian 1.2      * @version $Id: HClassInfo.java,v 1.2 2002/02/25 21:05:50 cananian Exp $
 21 cananian 1.1.2.1  * @see     harpoon.ClassFile.HClass
 22 cananian 1.1.2.1  */
 23 cananian 1.1.2.1 class HClassInfo
 24 cananian 1.1.2.1 {
 25 cananian 1.1.2.1     private HCIMap m_hcim = new HCIMap();
 26 cananian 1.1.2.1 
 27 cananian 1.1.2.1     /**
 28 cananian 1.1.2.1      * @return the depth of <code>hc</code> in the class hierarchy 
 29 cananian 1.1.2.1      */
 30 cananian 1.1.2.1     public int depth(HClass hc) {
 31 cananian 1.1.2.1         return m_hcim.get(hc).depth();
 32 cananian 1.1.2.1     }
 33 cananian 1.1.2.1 
 34 cananian 1.1.2.1     /**
 35 cananian 1.1.2.1      * @return the offset of of <code>hf</code> from the initial field.
 36 cananian 1.1.2.1      *         For instance, if <code>hf</code> is the 3rd field in its class, 
 37 cananian 1.1.2.1      *         <code>getFieldOffset</code> returns 2.
 38 cananian 1.1.2.1      */
 39 cananian 1.1.2.1     public int getFieldOffset(HField hf) {
 40 cananian 1.1.2.1         return m_hcim.get(hf.getDeclaringClass()).getOffset(hf);
 41 cananian 1.1.2.1     }
 42 cananian 1.1.2.1 
 43 cananian 1.1.2.1     /**
 44 cananian 1.1.2.1      * @return the offset of of <code>hm</code> from the initial method.
 45 cananian 1.1.2.1      *         For instance, if <code>hm</code> is the 3rd method in its class, 
 46 cananian 1.1.2.1      *         <code>getMethodOffset()</code> returns 2.
 47 cananian 1.1.2.1      */
 48 cananian 1.1.2.1     public int getMethodOffset(HMethod hm) {
 49 cananian 1.1.2.1         return m_hcim.get(hm.getDeclaringClass()).getOffset(hm);
 50 cananian 1.1.2.1     }
 51 cananian 1.1.2.1 
 52 cananian 1.1.2.1     /**
 53 cananian 1.1.2.1      * @return a String representation of this HClassInfo object
 54 cananian 1.1.2.1      */
 55 cananian 1.1.2.1     public String toString() { return m_hcim.toString(); }
 56 cananian 1.1.2.1 
 57 cananian 1.1.2.1     /**
 58 cananian 1.1.2.1      * @return a String representation of the information stored
 59 cananian 1.1.2.1      *         about <code>hc</code>
 60 cananian 1.1.2.1      */
 61 cananian 1.1.2.1     public String toString(HClass hc) { return m_hcim.get(hc).toString(); }
 62 cananian 1.1.2.1 
 63 cananian 1.1.2.1     final class HCIMap {
 64 cananian 1.1.2.1         private Map m_table = new HashMap();
 65 cananian 1.1.2.1 
 66 cananian 1.1.2.1         HCIUnit get(HClass hc) {
 67 cananian 1.1.2.1             HCIUnit     hciu;
 68 cananian 1.1.2.1             HClass      superclass;
 69 cananian 1.1.2.1             HCIUnit     superclassInfo;
 70 cananian 1.1.2.1         
 71 cananian 1.1.2.1             hciu = (HCIUnit)m_table.get(hc);
 72 cananian 1.1.2.1             if (hciu == null) {
 73 cananian 1.1.2.1                 if (hc.isArray())  { // Treat arrays differently
 74 cananian 1.1.2.1                     int    dims      = HClassUtil.dims(hc);
 75 cananian 1.1.2.1                     HClass baseclass = HClassUtil.baseClass(hc);
 76 cananian 1.1.2.1                     // hc is not primitive, so hc.getLinker() is safe.
 77 cananian 1.1.2.1                     superclass = 
 78 cananian 1.1.2.1                         baseclass.isPrimitive() ? 
 79 cananian 1.1.2.1                         hc.getLinker().forName("java.lang.Object")
 80 cananian 1.1.2.1                         : (baseclass.getDescriptor()
 81 cananian 1.1.2.1                            .equals("Ljava/lang/Object;") ?
 82 cananian 1.1.2.1                            (HClassUtil.arrayClass(hc.getLinker(),
 83 cananian 1.1.2.1                                                   baseclass, dims-1))
 84 cananian 1.1.2.1                            : HClassUtil.arrayClass(hc.getLinker(),
 85 cananian 1.1.2.1                                                    baseclass.getSuperclass(),
 86 cananian 1.1.2.1                                                    dims));
 87 cananian 1.1.2.1                 } 
 88 cananian 1.1.2.1                 else { superclass = hc.getSuperclass(); } 
 89 cananian 1.1.2.1                 if (superclass != null) {
 90 cananian 1.1.2.1                     superclassInfo = get(superclass);
 91 cananian 1.1.2.1                     hciu = new HCIUnit(hc, superclassInfo);
 92 cananian 1.1.2.1                 }
 93 cananian 1.1.2.1                 else {
 94 cananian 1.1.2.1                     hciu = new HCIUnit(hc);
 95 cananian 1.1.2.1                 }
 96 cananian 1.1.2.1                 m_table.put(hc, hciu);
 97 cananian 1.1.2.1             }
 98 cananian 1.1.2.1             return hciu;
 99 cananian 1.1.2.1         }
100 cananian 1.1.2.1     
101 cananian 1.1.2.1         public String toString() { return m_table.toString(); }
102 cananian 1.1.2.1     }
103 cananian 1.1.2.1 }
104 cananian 1.1.2.1 
105 cananian 1.1.2.1 
106 cananian 1.1.2.1 class HCIUnit {
107 cananian 1.1.2.1 
108 cananian 1.1.2.1     private HMemberMap m_memberMap;
109 cananian 1.1.2.1     private int        m_currentFieldOffset          = 0;
110 cananian 1.1.2.1     private int        m_currentMethodOffset         = 0;
111 cananian 1.1.2.1     private static int m_currentStaticFieldOffset    = 0;
112 cananian 1.1.2.1     private int        m_depth;
113 cananian 1.1.2.1 
114 cananian 1.1.2.1     // Constructor used for classes extending another class
115 cananian 1.1.2.1     // (i.e. anything other than class Object)
116 cananian 1.1.2.1     HCIUnit(HClass hc, HCIUnit scInfo) {
117 cananian 1.1.2.1         m_depth     = scInfo.depth() + 1;
118 cananian 1.1.2.1         m_currentMethodOffset = scInfo.m_currentMethodOffset;
119 cananian 1.1.2.1         m_currentFieldOffset  = scInfo.m_currentFieldOffset;
120 cananian 1.1.2.1         m_memberMap = new HMemberMap(scInfo.m_memberMap);
121 cananian 1.1.2.1         extend(hc);
122 cananian 1.1.2.1     }
123 cananian 1.1.2.1     
124 cananian 1.1.2.1     // Constructor used for classes which don't extend anything
125 cananian 1.1.2.1     // (Object)
126 cananian 1.1.2.1     HCIUnit(HClass hc) {
127 cananian 1.1.2.1         m_depth = 0;      
128 cananian 1.1.2.1         m_memberMap = new HMemberMap();
129 cananian 1.1.2.1         extend(hc);
130 cananian 1.1.2.1     }
131 cananian 1.1.2.1 
132 cananian 1.1.2.1     int depth() { return m_depth; }
133 cananian 1.1.2.1 
134 cananian 1.1.2.1     int getOffset(HMember hm) { return m_memberMap.get(hm); }
135 cananian 1.1.2.1 
136 cananian 1.1.2.1     private void extend(HClass hc) {
137 cananian 1.1.2.1         HField[] hFields = hc.getDeclaredFields();
138 cananian 1.1.2.1         for (int i = 0; i < hFields.length; i++) {
139 cananian 1.1.2.1             if (hFields[i].isStatic())
140 cananian 1.1.2.1                 m_currentStaticFieldOffset =
141 cananian 1.1.2.1                     m_memberMap.map(hFields[i], m_currentStaticFieldOffset);
142 cananian 1.1.2.1             else
143 cananian 1.1.2.1                 m_currentFieldOffset = 
144 cananian 1.1.2.1                     m_memberMap.map(hFields[i], m_currentFieldOffset);
145 cananian 1.1.2.1         }
146 cananian 1.1.2.1 
147 cananian 1.1.2.1         HMethod[] hMethods = hc.getDeclaredMethods();
148 cananian 1.1.2.1         for (int i = 0; i < hMethods.length; i++) {
149 cananian 1.1.2.1             m_currentMethodOffset = 
150 cananian 1.1.2.1                 m_memberMap.map(hMethods[i], m_currentMethodOffset);
151 cananian 1.1.2.1         }
152 cananian 1.1.2.1     }
153 cananian 1.1.2.1 
154 cananian 1.1.2.1     public String toString() { return m_memberMap.toString(); }
155 cananian 1.1.2.1 
156 cananian 1.1.2.1     // Used to map HMethods and HFields to offsets
157 cananian 1.1.2.1     final class HMemberMap {
158 cananian 1.1.2.1         private Map m_table;
159 cananian 1.1.2.1 
160 cananian 1.1.2.1         HMemberMap() { m_table = new HashMap(); }
161 cananian 1.1.2.1 
162 cananian 1.1.2.1         HMemberMap(HMemberMap map) { m_table = new HashMap(map.m_table); } 
163 cananian 1.1.2.1 
164 cananian 1.1.2.1         int map(HField hf, int next) {
165 cananian 1.1.2.1             m_table.put(hf, new Integer(next++));
166 cananian 1.1.2.1             return next;
167 cananian 1.1.2.1         }
168 cananian 1.1.2.1 
169 cananian 1.1.2.1         int map(HMethod hm, int next) {
170 cananian 1.1.2.1             int    offset;
171 cananian 1.1.2.1             String sig = getSignature(hm);
172 cananian 1.1.2.1         
173 cananian 1.1.2.1             if (m_table.get(sig) == null) { 
174 cananian 1.1.2.1                 // Method does not override anything
175 cananian 1.1.2.1                 offset = next++;
176 cananian 1.1.2.1             }
177 cananian 1.1.2.1             else {
178 cananian 1.1.2.1                 HMethod scMethod = (HMethod)(m_table.get(sig));
179 cananian 1.1.2.1                 offset           = ((Integer)m_table.get(scMethod)).intValue();
180 cananian 1.1.2.1             }
181 cananian 1.1.2.1 
182 cananian 1.1.2.1             m_table.put(sig, hm);
183 cananian 1.1.2.1             m_table.put(hm, new Integer(offset));
184 cananian 1.1.2.1 
185 cananian 1.1.2.1             return next;
186 cananian 1.1.2.1         }
187 cananian 1.1.2.1     
188 cananian 1.1.2.1         int get(HMember hm) {
189 cananian 1.1.2.1             return (m_table.containsKey(hm) ? 
190 cananian 1.1.2.1                     ((Integer)m_table.get(hm)).intValue() : 
191 cananian 1.1.2.1                     Integer.MIN_VALUE);
192 cananian 1.1.2.1         }
193 cananian 1.1.2.1 
194 cananian 1.1.2.1         private String getSignature(HMethod hm) {
195 cananian 1.1.2.1             HClass[] paramTypes;
196 cananian 1.1.2.1             StringBuffer sb;
197 cananian 1.1.2.1         
198 cananian 1.1.2.1             sb = new StringBuffer("");
199 cananian 1.1.2.1             sb.append(hm.getName());
200 cananian 1.1.2.1             paramTypes = hm.getParameterTypes();
201 cananian 1.1.2.1             for (int i = 0; i < paramTypes.length; i++)
202 cananian 1.1.2.1                 sb.append(paramTypes[i].toString());
203 cananian 1.1.2.1             return sb.toString();
204 cananian 1.1.2.1         }
205 cananian 1.1.2.1     
206 cananian 1.1.2.1         public String toString() { return m_table.toString(); }
207 cananian 1.1.2.1     }
208 cananian 1.2     }