View Javadoc

1   // jq_Member.java, created Mon Feb  5 23:23:20 2001 by joewhaley
2   // Copyright (C) 2001-3 John Whaley <jwhaley@alum.mit.edu>
3   // Licensed under the terms of the GNU LGPL; see COPYING for details.
4   package joeq.Class;
5   
6   import java.util.HashMap;
7   import java.util.Iterator;
8   import java.util.Map;
9   import java.util.StringTokenizer;
10  import java.io.DataInput;
11  import java.io.DataOutput;
12  import java.io.IOException;
13  import java.lang.reflect.Member;
14  import joeq.ClassLib.ClassLibInterface;
15  import joeq.Main.jq;
16  import joeq.Runtime.Reflection;
17  import joeq.UTF.Utf8;
18  import jwutil.collections.Filter;
19  import jwutil.io.Textualizable;
20  import jwutil.io.Textualizer;
21  import jwutil.strings.CharSequenceWrapper;
22  import jwutil.util.Assert;
23  
24  /*
25   * @author  John Whaley <jwhaley@alum.mit.edu>
26   * @version $Id: jq_Member.java 2234 2005-03-20 09:53:57Z joewhaley $
27   */
28  public abstract class jq_Member implements jq_ClassFileConstants, Textualizable {
29  
30      protected final void chkState(int s) {
31          if (getState() >= s) return;
32          Assert.UNREACHABLE(this + " actual state: " + getState() + " expected state: " + s);
33      }
34  
35      public final int getState() {
36          return state;
37      }
38  
39      public final boolean isLoaded() {
40          return state >= STATE_LOADED;
41      }
42  
43      public final boolean isPrepared() {
44          return state >= STATE_PREPARED;
45      }
46      
47      public final boolean isInitialized() {
48          return state >= STATE_SFINITIALIZED;
49      }
50      
51      //  Always available
52      protected byte state;
53      // pointer to the jq_Class object it's a member of
54      protected /*final*/ jq_Class clazz; // made not final for class replacement
55      protected /*final*/ jq_NameAndDesc nd;
56  
57      // Available after loading
58      protected char access_flags;
59      protected Map attributes;
60  
61      private /*final*/ Member member_object;  // pointer to our associated java.lang.reflect.Member object
62  
63      public static final boolean USE_MEMBER_OBJECT_FIELD = true;
64  
65      protected jq_Member(jq_Class clazz, jq_NameAndDesc nd) {
66          Assert._assert(clazz != null);
67          Assert._assert(nd != null);
68          this.clazz = clazz;
69          this.nd = nd;
70          initializeMemberObject();
71      }
72  
73      private final void initializeMemberObject() {
74          if (jq.RunningNative) {
75              if (this instanceof jq_Field) {
76                  this.member_object = ClassLibInterface.DEFAULT.createNewField((jq_Field) this);
77              } else if (this instanceof jq_Initializer) {
78                  this.member_object = ClassLibInterface.DEFAULT.createNewConstructor((jq_Initializer) this);
79              } else {
80                  this.member_object = ClassLibInterface.DEFAULT.createNewMethod((jq_Method) this);
81              }
82          } else if (USE_MEMBER_OBJECT_FIELD) {
83              Class jdktype = Reflection.getJDKType(clazz);
84              if (jdktype != null) {
85                  if (this instanceof jq_Field) {
86                      this.member_object = Reflection.getJDKField(jdktype, nd.getName().toString());
87                  } else {
88                      Class[] args = Reflection.getArgTypesFromDesc(nd.getDesc());
89                      if (this instanceof jq_Initializer) {
90                          this.member_object = Reflection.getJDKConstructor(jdktype, args);
91                      } else {
92                          this.member_object = Reflection.getJDKMethod(jdktype, nd.getName().toString(), args);
93                      }
94                  }
95              }
96          }
97      }
98  
99      public final Member getJavaLangReflectMemberObject() {
100         if (jq.RunningNative && member_object == null)
101             initializeMemberObject();
102         return member_object;
103     }
104     
105     public static final boolean DETERMINISTIC = true;
106     
107     public int hashCode() {
108         if (DETERMINISTIC)
109             return clazz.hashCode() ^ nd.hashCode();
110         else
111             return System.identityHashCode(this);
112     }
113 
114     /* attribute_info {
115            u2 attribute_name_index;
116            u4 attribute_length;
117            u1 info[attribute_length];
118        }
119        VM Spec 4.7 */
120 
121     public void load(char access_flags, DataInput in)
122             throws IOException, ClassFormatError {
123         state = STATE_LOADING1;
124         this.access_flags = access_flags;
125         attributes = new HashMap();
126         char n_attributes = (char) in.readUnsignedShort();
127         for (int i = 0; i < n_attributes; ++i) {
128             char attribute_name_index = (char) in.readUnsignedShort();
129             if (clazz.getCPtag(attribute_name_index) != CONSTANT_Utf8)
130                 throw new ClassFormatError("constant pool entry " + attribute_name_index + ", referred to by attribute " + i +
131                         ", is wrong type tag (expected=" + CONSTANT_Utf8 + ", actual=" + clazz.getCPtag(attribute_name_index));
132             Utf8 attribute_desc = clazz.getCPasUtf8(attribute_name_index);
133             int attribute_length = in.readInt();
134             // todo: maybe we only want to read in attributes we care about...
135             byte[] attribute_data = new byte[attribute_length];
136             in.readFully(attribute_data);
137             attributes.put(attribute_desc, attribute_data);
138         }
139         state = STATE_LOADING2;
140     }
141 
142     public void load(char access_flags, Map attributes) {
143         this.access_flags = access_flags;
144         this.attributes = attributes;
145         state = STATE_LOADING2;
146     }
147 
148     public void unload() {
149         state = STATE_UNLOADED;
150     }
151 
152     public final void dump(DataOutput out, jq_ConstantPool.ConstantPoolRebuilder cpr) throws IOException {
153         out.writeChar(access_flags);
154         out.writeChar(cpr.get(getName()));
155         out.writeChar(cpr.get(getDesc()));
156         dumpAttributes(out, cpr);
157     }
158 
159     public void dumpAttributes(DataOutput out, jq_ConstantPool.ConstantPoolRebuilder cpr) throws IOException {
160         int nattributes = attributes.size();
161         Assert._assert(nattributes <= Character.MAX_VALUE);
162         out.writeChar(nattributes);
163         for (Iterator i = attributes.entrySet().iterator(); i.hasNext();) {
164             Map.Entry e = (Map.Entry) i.next();
165             Utf8 name = (Utf8) e.getKey();
166             out.writeChar(cpr.get(name));
167             byte[] value = (byte[]) e.getValue();
168             out.writeInt(value.length);
169             out.write(value);
170         }
171     }
172 
173     // Always available
174     public final jq_Class getDeclaringClass() {
175         return clazz;
176     }
177 
178     public final jq_NameAndDesc getNameAndDesc() {
179         return nd;
180     }
181 
182     public final Utf8 getName() {
183         return nd.getName();
184     }
185 
186     public final Utf8 getDesc() {
187         return nd.getDesc();
188     }
189 
190     public abstract boolean needsDynamicLink(jq_Method method);
191 
192     public final void setDeclaringClass(jq_Class k) {
193         this.clazz = k;
194     }
195 
196     public final void setNameAndDesc(jq_NameAndDesc nd) {
197         this.nd = nd;
198     }
199 
200     public abstract jq_Member resolve();
201 
202     // Available after loading
203     public final byte[] getAttribute(Utf8 name) {
204         chkState(STATE_LOADING2);
205         return (byte[]) attributes.get(name);
206     }
207 
208     public final byte[] getAttribute(String name) {
209         return getAttribute(Utf8.get(name));
210     }
211 
212     public final Map getAttributes() {
213         chkState(STATE_LOADING2);
214         return attributes;
215     }
216 
217     public final void removeAttribute(String name) {
218         removeAttribute(Utf8.get(name));
219     }
220     public final void removeAttribute(Utf8 name) {
221         attributes.remove(name);
222     }
223     
224     public final boolean checkAccessFlag(char f) {
225         chkState(STATE_LOADING2);
226         return (access_flags & f) != 0;
227     }
228 
229     public final char getAccessFlags() {
230         chkState(STATE_LOADING2);
231         return access_flags;
232     }
233 
234     public final boolean isPublic() {
235         return checkAccessFlag(ACC_PUBLIC);
236     }
237 
238     public final boolean isPrivate() {
239         return checkAccessFlag(ACC_PRIVATE);
240     }
241 
242     public final boolean isProtected() {
243         return checkAccessFlag(ACC_PROTECTED);
244     }
245 
246     public final boolean isFinal() {
247         return checkAccessFlag(ACC_FINAL);
248     }
249 
250     public final boolean isSynthetic() {
251         return getAttribute("Synthetic") != null;
252     }
253 
254     public final boolean isDeprecated() {
255         return getAttribute("Deprecated") != null;
256     }
257 
258     // Available after resolving
259     public abstract boolean isStatic();
260     
261     public void write(Textualizer t) throws IOException {
262         getDeclaringClass().write(t);
263         t.writeString(" "+getName()+" "+getDesc());
264     }
265     public void writeEdges(Textualizer t) throws IOException { }
266     public void addEdge(String edgeName, Textualizable t) { }
267     
268     public static jq_Member read(StringTokenizer st) {
269         jq_Class c = (jq_Class) jq_Type.read(st);
270         if (c == null) return null;
271         c.load();
272         String name = st.nextToken();
273         String desc = st.nextToken();
274         if (name.startsWith("fake$")) return jq_FakeInstanceMethod.fakeMethod(c, name, desc);
275         return c.getDeclaredMember(name, desc);
276     }
277     
278     public static jq_Member parseMember(String s) {
279         int i = s.indexOf(' ');
280         if (i < 0) return null;
281         String desc = s.substring(i+1);
282         int j = s.lastIndexOf('.');
283         if (j < 0 || j > i) return null;
284         String memberName = s.substring(j+1, i);
285         String className = s.substring(0, j);
286         jq_Class c = (jq_Class) jq_Type.parseType(className);
287         try {
288             c.load();
289         } catch (NoClassDefFoundError x) {
290             PrimordialClassLoader.loader.unloadBSType(c);
291             return null;
292         }
293         jq_Member m = c.getDeclaredMember(memberName, desc);
294         return m;
295     }
296     
297     public static class FilterByName extends Filter {
298         private java.util.regex.Pattern p;
299         public FilterByName(java.util.regex.Pattern p) { this.p = p; }
300         public FilterByName(String s) { this(java.util.regex.Pattern.compile(s)); }
301         public boolean isElement(Object o2) {
302             jq_Member m = (jq_Member) o2;
303             Object o = m.getName().toString();
304             CharSequence cs;
305             if (o instanceof CharSequence) cs = (CharSequence) o;
306             else cs = new CharSequenceWrapper((String) o);
307             return p.matcher(cs).matches();
308         }
309     }
310     public static class FilterByShortClassName extends Filter {
311         private java.util.regex.Pattern p;
312         public FilterByShortClassName(java.util.regex.Pattern p) { this.p = p; }
313         public FilterByShortClassName(String s) { this(java.util.regex.Pattern.compile(s)); }
314         public boolean isElement(Object o2) {
315             jq_Member m = (jq_Member) o2;
316             Object o = m.getDeclaringClass().shortName();
317             CharSequence cs;
318             if (o instanceof CharSequence) cs = (CharSequence) o;
319             else cs = new CharSequenceWrapper((String) o);
320             return p.matcher(cs).matches();
321         }
322     }
323     
324     public static final jq_Class _class = (jq_Class) PrimordialClassLoader.loader.getOrCreateBSType("Ljoeq/Class/jq_Member;");
325     public static final jq_InstanceField _state = (jq_InstanceField) _class.getOrCreateInstanceField("state", "B");
326 }