1
2
3
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
26
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
52 protected byte state;
53
54 protected
55 protected
56
57
58 protected char access_flags;
59 protected Map attributes;
60
61 private
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
115
116
117
118
119
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
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
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
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
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 }