1
2
3
4 package joeq.Class;
5
6 import java.util.Arrays;
7 import java.util.Collection;
8 import java.util.Comparator;
9 import java.util.HashMap;
10 import java.util.Iterator;
11 import java.util.LinkedHashMap;
12 import java.util.LinkedList;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Set;
16 import java.util.StringTokenizer;
17 import java.io.DataInput;
18 import java.io.DataInputStream;
19 import java.io.DataOutput;
20 import java.io.IOException;
21 import joeq.Allocator.ObjectLayout;
22 import joeq.ClassLib.ClassLibInterface;
23 import joeq.Compiler.CompilationConstants;
24 import joeq.Compiler.BytecodeAnalysis.Bytecodes;
25 import joeq.Main.jq;
26 import joeq.Memory.Address;
27 import joeq.Memory.CodeAddress;
28 import joeq.Memory.HeapAddress;
29 import joeq.Memory.StackAddress;
30 import joeq.Runtime.Debug;
31 import joeq.Runtime.Reflection;
32 import joeq.Runtime.TypeCheck;
33 import joeq.UTF.UTFDataFormatError;
34 import joeq.UTF.Utf8;
35 import jwutil.io.Textualizer;
36 import jwutil.strings.Strings;
37 import jwutil.util.Assert;
38 import jwutil.util.Convert;
39
40 /***
41 * jq_Class
42 *
43 * @author John Whaley <jwhaley@alum.mit.edu>
44 * @version $Id: jq_Class.java 2465 2006-06-07 23:03:17Z joewhaley $
45 */
46 public final class jq_Class extends jq_Reference implements jq_ClassFileConstants, CompilationConstants {
47
48 public static
49 public static
50
51
52 public static boolean REPLACE_CLASS = false;
53 public static boolean TRACE_REPLACE_CLASS = false;
54 public static List classToReplace = new java.util.LinkedList();
55
56 /***** INTERFACE ****/
57
58
59 public final boolean isClassType() { return true; }
60 public final boolean isArrayType() { return false; }
61 public final boolean isAddressType() {
62 return this == Address._class || this == HeapAddress._class ||
63 this == CodeAddress._class || this == StackAddress._class;
64
65 }
66 public final String getName() {
67 return className(desc);
68 }
69 public final String shortName() {
70 String s = desc.toString();
71 int index = s.lastIndexOf('/')+1;
72 if (index == 0) index = 1;
73 return s.substring(index, s.length()-1);
74 }
75 public final boolean isInSamePackage(jq_Class that) {
76 if (this.getClassLoader() != that.getClassLoader()) return false;
77 String s1 = this.getName();
78 String s2 = that.getName();
79 int ind1 = s1.lastIndexOf('.');
80 int ind2 = s2.lastIndexOf('.');
81 if (ind1 != ind2) return false;
82 if (ind1 != -1) {
83 if (!s1.substring(0, ind1).equals(s2.substring(0, ind1)))
84 return false;
85 }
86 return true;
87 }
88 public final String getJDKName() {
89 return getName();
90 }
91 public final String getJDKDesc() {
92 return desc.toString().replace('/','.');
93 }
94 public jq_Member getDeclaredMember(jq_NameAndDesc nd) {
95 return (jq_Member)members.get(nd);
96 }
97 public jq_Member getDeclaredMember(String name, String desc) {
98 return (jq_Member)members.get(new jq_NameAndDesc(Utf8.get(name), Utf8.get(desc)));
99 }
100 public Collection getMembers() {
101 return members.values();
102 }
103 private void addDeclaredMember(jq_NameAndDesc nd, jq_Member m) {
104 Object b = members.put(nd, m);
105 if (TRACE) {
106 Debug.writeln("Added member to "+this+": "+m+" (old value "+b+")");
107
108 }
109 }
110 public void accept(jq_TypeVisitor tv) {
111 tv.visitClass(this);
112 super.accept(tv);
113 }
114
115 public static final boolean DETERMINISTIC = true;
116
117 public int hashCode() {
118 if (DETERMINISTIC)
119 return desc.hashCode();
120 else
121 return System.identityHashCode(this);
122 }
123
124
125 public final int getMinorVersion() { return minor_version; }
126 public final int getMajorVersion() { return major_version; }
127 public final char getAccessFlags() { return access_flags; }
128 public final boolean isPublic() {
129 chkState(STATE_LOADING2);
130 return (access_flags & ACC_PUBLIC) != 0;
131 }
132 public final boolean isFinal() {
133 chkState(STATE_LOADING2);
134 return (access_flags & ACC_FINAL) != 0;
135 }
136 public final boolean isSpecial() {
137 chkState(STATE_LOADING2);
138 return (access_flags & ACC_SUPER) != 0;
139 }
140 public final boolean isInterface() {
141 chkState(STATE_LOADING2);
142 return (access_flags & ACC_INTERFACE) != 0;
143 }
144 public final boolean isAbstract() {
145 chkState(STATE_LOADING2);
146 return (access_flags & ACC_ABSTRACT) != 0;
147 }
148 public final jq_Class getSuperclass() {
149 chkState(STATE_LOADING3);
150 return super_class;
151 }
152 public final int getDepth() {
153 chkState(STATE_LOADED);
154 if (super_class == null) return 0;
155 jq_Reference t = getDirectPrimarySupertype();
156 t.load();
157 return 1+getDirectPrimarySupertype().getDepth();
158 }
159 public final jq_Reference getDirectPrimarySupertype() {
160 chkState(STATE_LOADING3);
161 if (this.isInterface()) return PrimordialClassLoader.getJavaLangObject();
162 return super_class;
163 }
164 public final jq_Class[] getDeclaredInterfaces() {
165 chkState(STATE_LOADING3);
166 return declared_interfaces;
167 }
168 public final jq_Class getDeclaredInterface(Utf8 desc) {
169 chkState(STATE_LOADING3);
170 for (int i=0; i<declared_interfaces.length; ++i) {
171 jq_Class in = declared_interfaces[i];
172 if (in.getDesc() == desc)
173 return in;
174 }
175 return null;
176 }
177 public final jq_InstanceField[] getDeclaredInstanceFields() {
178 chkState(STATE_LOADING3);
179 return declared_instance_fields;
180 }
181 public final jq_InstanceField getDeclaredInstanceField(jq_NameAndDesc nd) {
182 chkState(STATE_LOADING3);
183 return (jq_InstanceField)findByNameAndDesc(declared_instance_fields, nd);
184 }
185 public final void setDeclaredInstanceFields(jq_InstanceField[] dif) {
186 chkState(STATE_LOADED);
187 declared_instance_fields = dif;
188 }
189 public final jq_StaticField[] getDeclaredStaticFields() {
190 chkState(STATE_LOADING3);
191 return static_fields;
192 }
193 public final jq_StaticField getDeclaredStaticField(jq_NameAndDesc nd) {
194 chkState(STATE_LOADING3);
195 return (jq_StaticField)findByNameAndDesc(static_fields, nd);
196 }
197 public final void setDeclaredStaticFields(jq_StaticField[] dsf) {
198 chkState(STATE_LOADED);
199 static_fields = dsf;
200 }
201
202 public final jq_StaticField getStaticField(jq_NameAndDesc nd) {
203 chkState(STATE_LOADING3);
204 jq_StaticField f = (jq_StaticField)findByNameAndDesc(static_fields, nd);
205 if (f != null) return f;
206
207
208 if (super_class != null) {
209 super_class.load();
210 f = super_class.getStaticField(nd);
211 if (f != null) return f;
212 }
213
214
215 for (int i=0; i<declared_interfaces.length; ++i) {
216 jq_Class in = declared_interfaces[i];
217 in.load();
218 f = in.getStaticField(nd);
219 if (f != null) return f;
220 }
221
222 return null;
223 }
224
225 public final int getNumberOfStaticFields() {
226 chkState(STATE_LOADED);
227 int length = static_fields.length;
228 if (this.isInterface()) {
229 for (int i=0; i<declared_interfaces.length; ++i) {
230 jq_Class in = declared_interfaces[i];
231 in.load();
232 length += in.getNumberOfStaticFields();
233 }
234 }
235 if (super_class != null) {
236 super_class.load();
237 length += super_class.getNumberOfStaticFields();
238 }
239 return length;
240 }
241
242 private int getStaticFields_helper(jq_StaticField[] sfs, int current) {
243 System.arraycopy(static_fields, 0, sfs, current, static_fields.length);
244 current += static_fields.length;
245 if (this.isInterface()) {
246 for (int i=0; i<declared_interfaces.length; ++i) {
247 jq_Class in = declared_interfaces[i];
248 current = in.getStaticFields_helper(sfs, current);
249 }
250 }
251 if (super_class != null) {
252 current = super_class.getStaticFields_helper(sfs, current);
253 }
254 return current;
255 }
256
257
258 public final jq_StaticField[] getStaticFields() {
259 chkState(STATE_LOADING3);
260 int length = this.getNumberOfStaticFields();
261 jq_StaticField[] sfs = new jq_StaticField[length];
262 int current = this.getStaticFields_helper(sfs, 0);
263 Assert._assert(current == sfs.length);
264 return sfs;
265 }
266
267 public final jq_InstanceMethod[] getDeclaredInstanceMethods() {
268 chkState(STATE_LOADING3);
269 return declared_instance_methods;
270 }
271 public final jq_InstanceMethod getDeclaredInstanceMethod(jq_NameAndDesc nd) {
272 chkState(STATE_LOADING3);
273 return (jq_InstanceMethod)findByNameAndDesc(declared_instance_methods, nd);
274 }
275 public final void setDeclaredInstanceMethods(jq_InstanceMethod[] dim) {
276 chkState(STATE_LOADED);
277 declared_instance_methods = dim;
278 }
279 public final jq_StaticMethod[] getDeclaredStaticMethods() {
280 chkState(STATE_LOADING3);
281 return static_methods;
282 }
283 public final jq_StaticMethod getDeclaredStaticMethod(jq_NameAndDesc nd) {
284 chkState(STATE_LOADING3);
285 return (jq_StaticMethod)findByNameAndDesc(static_methods, nd);
286 }
287 public final void setDeclaredStaticMethods(jq_StaticMethod[] dsm) {
288 chkState(STATE_LOADED);
289 static_methods = dsm;
290 }
291 public final jq_StaticMethod getStaticMethod(jq_NameAndDesc nd) {
292 chkState(STATE_LOADING3);
293 jq_StaticMethod m = (jq_StaticMethod)findByNameAndDesc(static_methods, nd);
294 if (m != null) return m;
295
296 if (super_class != null) {
297 super_class.load();
298 m = super_class.getStaticMethod(nd);
299 if (m != null) return m;
300 }
301
302 for (int i=0; i<declared_interfaces.length; ++i) {
303 jq_Class in = declared_interfaces[i];
304 in.load();
305 m = in.getStaticMethod(nd);
306 if (m != null) return m;
307 }
308 return null;
309 }
310
311 public final int getNumberOfStaticMethods() {
312 chkState(STATE_LOADED);
313 int length = static_methods.length;
314 for (int i=0; i<declared_interfaces.length; ++i) {
315 jq_Class in = declared_interfaces[i];
316 in.load();
317 length += in.getNumberOfStaticMethods();
318 }
319 if (super_class != null) {
320 super_class.load();
321 length += super_class.getNumberOfStaticMethods();
322 }
323 return length;
324 }
325
326 private int getStaticMethods_helper(jq_StaticMethod[] sfs, int current) {
327 System.arraycopy(static_methods, 0, sfs, current, static_methods.length);
328 current += static_methods.length;
329 for (int i=0; i<declared_interfaces.length; ++i) {
330 jq_Class in = declared_interfaces[i];
331 current = in.getStaticMethods_helper(sfs, current);
332 }
333 if (super_class != null) {
334 current = super_class.getStaticMethods_helper(sfs, current);
335 }
336 return current;
337 }
338
339
340 public final jq_StaticMethod[] getStaticMethods() {
341 chkState(STATE_LOADED);
342 int length = this.getNumberOfStaticMethods();
343 jq_StaticMethod[] sfs = new jq_StaticMethod[length];
344 int current = this.getStaticMethods_helper(sfs, 0);
345 Assert._assert(current == sfs.length);
346 return sfs;
347 }
348
349 public final jq_InstanceMethod getInstanceMethod(jq_NameAndDesc nd) {
350 chkState(STATE_LOADING3);
351 jq_InstanceMethod m = (jq_InstanceMethod)findByNameAndDesc(declared_instance_methods, nd);
352 if (m != null) return m;
353
354 if (super_class != null) {
355 super_class.load();
356 m = super_class.getInstanceMethod(nd);
357 if (m != null) return m;
358 }
359
360 for (int i=0; i<declared_interfaces.length; ++i) {
361 jq_Class in = declared_interfaces[i];
362 in.load();
363 m = in.getInstanceMethod(nd);
364 if (m != null) return m;
365 }
366 return null;
367 }
368 public final jq_Initializer getInitializer(Utf8 desc) {
369 return getInitializer(new jq_NameAndDesc(Utf8.get("<init>"), desc));
370 }
371 public final jq_Initializer getInitializer(jq_NameAndDesc nd) {
372 chkState(STATE_LOADING3);
373 return (jq_Initializer)getDeclaredInstanceMethod(nd);
374 }
375 public final jq_ClassInitializer getClassInitializer() {
376 chkState(STATE_LOADING3);
377 return (jq_ClassInitializer)getDeclaredStaticMethod(new jq_NameAndDesc(Utf8.get("<clinit>"), Utf8.get("()V")));
378 }
379
380 public jq_Field getDeclaredField(String name) {
381 return getDeclaredField(Utf8.get(name));
382 }
383
384 public jq_Field getDeclaredField(Utf8 name) {
385 chkState(STATE_LOADED);
386 for (int i=0; i<declared_instance_fields.length; ++i) {
387 jq_Field m = declared_instance_fields[i];
388 if (m.getName() == name) return m;
389 }
390 for (int i=0; i<static_fields.length; ++i) {
391 jq_Field m = static_fields[i];
392 if (m.getName() == name) return m;
393 }
394 return null;
395 }
396
397 public jq_Method getDeclaredMethod(String name) {
398 return getDeclaredMethod(Utf8.get(name));
399 }
400
401 public jq_Method getDeclaredMethod(Utf8 name) {
402 chkState(STATE_LOADED);
403 for (int i=0; i<declared_instance_methods.length; ++i) {
404 jq_Method m = declared_instance_methods[i];
405 if (m.getName() == name) return m;
406 }
407 for (int i=0; i<static_methods.length; ++i) {
408 jq_Method m = static_methods[i];
409 if (m.getName() == name) return m;
410 }
411 return null;
412 }
413
414 public jq_Method getMethodContainingLine(char lineNum) {
415 chkState(STATE_LOADED);
416 for (int i=0; i<declared_instance_methods.length; ++i) {
417 jq_Method m = declared_instance_methods[i];
418 jq_LineNumberBC a = m.getLineNumber(lineNum);
419 if (a != null) return m;
420 }
421 for (int i=0; i<static_methods.length; ++i) {
422 jq_Method m = static_methods[i];
423 jq_LineNumberBC a = m.getLineNumber(lineNum);
424 if (a != null) return m;
425 }
426 return null;
427 }
428
429
430 public final jq_ConstantPool getCP() {
431 chkState(STATE_LOADING2);
432 return const_pool;
433 }
434 public final void setCP(jq_ConstantPool cp) {
435 this.const_pool = cp;
436 }
437 public final Object getCP(char index) {
438 chkState(STATE_LOADING2);
439 return const_pool.get(index);
440 }
441 public final int getCPCount() {
442 chkState(STATE_LOADING2);
443 return const_pool.getCount();
444 }
445 public final byte getCPtag(char index) {
446 chkState(STATE_LOADING2);
447 return const_pool.getTag(index);
448 }
449 public final Integer getCPasInt(char index) {
450 chkState(STATE_LOADING2);
451 return const_pool.getAsInt(index);
452 }
453 public final Float getCPasFloat(char index) {
454 chkState(STATE_LOADING2);
455 return const_pool.getAsFloat(index);
456 }
457 public final Long getCPasLong(char index) {
458 chkState(STATE_LOADING2);
459 return const_pool.getAsLong(index);
460 }
461 public final Double getCPasDouble(char index) {
462 chkState(STATE_LOADING2);
463 return const_pool.getAsDouble(index);
464 }
465 public final String getCPasString(char index) {
466 chkState(STATE_LOADING2);
467 return const_pool.getAsString(index);
468 }
469 public final Object getCPasObjectConstant(char index) {
470 chkState(STATE_LOADING2);
471 return const_pool.getAsObjectConstant(index);
472 }
473 public final Utf8 getCPasUtf8(char index) {
474 chkState(STATE_LOADING2);
475 return const_pool.getAsUtf8(index);
476 }
477 public final jq_Type getCPasType(char index) {
478 chkState(STATE_LOADING2);
479 return const_pool.getAsType(index);
480 }
481 public final jq_Member getCPasMember(char index) {
482 chkState(STATE_LOADING2);
483 return const_pool.getAsMember(index);
484 }
485 public jq_StaticField getOrCreateStaticField(String name, String desc) {
486 return getOrCreateStaticField(new jq_NameAndDesc(Utf8.get(name), Utf8.get(desc)));
487 }
488 public jq_StaticField getOrCreateStaticField(jq_NameAndDesc nd) {
489 jq_StaticField sf = (jq_StaticField)getDeclaredMember(nd);
490 if (sf != null) return sf;
491 return createStaticField(nd);
492 }
493 jq_StaticField createStaticField(jq_NameAndDesc nd) {
494 Assert._assert(getDeclaredMember(nd) == null);
495 jq_StaticField f = jq_StaticField.newStaticField(this, nd);
496 addDeclaredMember(nd, f);
497 return f;
498 }
499 public final jq_StaticField getCPasStaticField(char index) {
500 chkState(STATE_LOADING2);
501 return const_pool.getAsStaticField(index);
502 }
503 public jq_InstanceField getOrCreateInstanceField(String name, String desc) {
504 return getOrCreateInstanceField(new jq_NameAndDesc(Utf8.get(name), Utf8.get(desc)));
505 }
506 public jq_InstanceField getOrCreateInstanceField(jq_NameAndDesc nd) {
507 jq_InstanceField sf = (jq_InstanceField)getDeclaredMember(nd);
508 if (sf != null) return sf;
509 return createInstanceField(nd);
510 }
511 jq_InstanceField createInstanceField(jq_NameAndDesc nd) {
512 Assert._assert(getDeclaredMember(nd) == null);
513 jq_InstanceField f = jq_InstanceField.newInstanceField(this, nd);
514 addDeclaredMember(nd, f);
515 return f;
516 }
517 public final jq_InstanceField getCPasInstanceField(char index) {
518 chkState(STATE_LOADING2);
519 return const_pool.getAsInstanceField(index);
520 }
521 public jq_StaticMethod getOrCreateStaticMethod(String name, String desc) {
522 return getOrCreateStaticMethod(new jq_NameAndDesc(Utf8.get(name), Utf8.get(desc)));
523 }
524 public jq_StaticMethod getOrCreateStaticMethod(jq_NameAndDesc nd) {
525 jq_StaticMethod sf = (jq_StaticMethod)getDeclaredMember(nd);
526 if (sf != null) return sf;
527 return createStaticMethod(nd);
528 }
529 jq_StaticMethod createStaticMethod(jq_NameAndDesc nd) {
530 Assert._assert(getDeclaredMember(nd) == null);
531 jq_StaticMethod f;
532 if (nd.getName() == Utf8.get("<clinit>") &&
533 nd.getDesc() == Utf8.get("()V")) {
534 f = jq_ClassInitializer.newClassInitializer(this, nd);
535 } else {
536 f = jq_StaticMethod.newStaticMethod(this, nd);
537 }
538 addDeclaredMember(nd, f);
539 return f;
540 }
541 public final jq_StaticMethod getCPasStaticMethod(char index) {
542 chkState(STATE_LOADING2);
543 return const_pool.getAsStaticMethod(index);
544 }
545 public jq_InstanceMethod getOrCreateInstanceMethod(String name, String desc) {
546 return getOrCreateInstanceMethod(new jq_NameAndDesc(Utf8.get(name), Utf8.get(desc)));
547 }
548 public jq_InstanceMethod getOrCreateInstanceMethod(jq_NameAndDesc nd) {
549 jq_InstanceMethod sf = (jq_InstanceMethod)getDeclaredMember(nd);
550 if (sf != null) return sf;
551 return createInstanceMethod(nd);
552 }
553 jq_InstanceMethod createInstanceMethod(jq_NameAndDesc nd) {
554 Assert._assert(getDeclaredMember(nd) == null);
555 jq_InstanceMethod f;
556 if (nd.getName() == Utf8.get("<init>")) {
557 f = jq_Initializer.newInitializer(this, nd);
558 } else {
559 f = jq_InstanceMethod.newInstanceMethod(this, nd);
560 }
561 addDeclaredMember(nd, f);
562 return f;
563 }
564 public final jq_InstanceMethod getCPasInstanceMethod(char index) {
565 chkState(STATE_LOADING2);
566 return const_pool.getAsInstanceMethod(index);
567 }
568 public final byte[] getAttribute(Utf8 name) {
569 chkState(STATE_LOADING3);
570 return (byte[])attributes.get(name);
571 }
572 public final byte[] getAttribute(String name) {
573 chkState(STATE_LOADING3);
574 return getAttribute(Utf8.get(name));
575 }
576 public final Iterator getAttributes() {
577 return attributes.keySet().iterator();
578 }
579 public final Utf8 getSourceFile() {
580 chkState(STATE_LOADING3);
581 byte[] attrib = getAttribute("SourceFile");
582 if (attrib == null) return null;
583 if (attrib.length != 2)
584 throw new ClassFormatError();
585 char cpi = Convert.twoBytesToChar(attrib, 0);
586 if (getCPtag(cpi) != CONSTANT_Utf8)
587 throw new ClassFormatError("cp tag "+(int)cpi+" is "+(int)getCPtag(cpi));
588 return getCPasUtf8(cpi);
589 }
590 public final boolean isSynthetic() {
591 chkState(STATE_LOADING3);
592 return getAttribute("Synthetic") != null;
593 }
594 public final boolean isDeprecated() {
595 chkState(STATE_LOADING3);
596 return getAttribute("Deprecated") != null;
597 }
598 public final void removeAttribute(String s) {
599 removeAttribute(Utf8.get(s));
600 }
601 public final void removeAttribute(Utf8 u) {
602 attributes.remove(u);
603 }
604 public final jq_Class[] getInnerClasses() {
605 chkState(STATE_LOADING3);
606 Assert.TODO();
607 return null;
608 }
609 public final jq_Class[] getSubClasses() {
610 chkState(STATE_LOADING3);
611 return subclasses;
612 }
613 public final jq_Class[] getSubInterfaces() {
614 chkState(STATE_LOADING3);
615 return subinterfaces;
616 }
617
618 public final jq_Class[] getInterfaces() {
619 chkState(STATE_PREPARED);
620 return interfaces;
621 }
622 public final jq_Class getInterface(Utf8 desc) {
623 chkState(STATE_PREPARED);
624 for (int i=0; i<interfaces.length; ++i) {
625 jq_Class in = interfaces[i];
626 if (in.getDesc() == desc)
627 return in;
628 }
629 return null;
630 }
631 public final boolean implementsInterface(jq_Class k) {
632 chkState(STATE_PREPARED);
633 for (int i=0; i<interfaces.length; ++i) {
634 if (interfaces[i] == k)
635 return true;
636 }
637 if (false) {
638 for (int i=0; i<interfaces.length; ++i) {
639 jq_Class k2 = interfaces[i];
640 k2.prepare();
641 if (k2.implementsInterface(k))
642 return true;
643 }
644 }
645 return false;
646 }
647 public final jq_InstanceField[] getInstanceFields() {
648 chkState(STATE_PREPARED);
649 return instance_fields;
650 }
651 public final int[] getReferenceOffsets() {
652 chkState(STATE_PREPARED);
653 return reference_offsets;
654 }
655 public final jq_InstanceField getInstanceField(jq_NameAndDesc nd) {
656 chkState(STATE_LOADING3);
657 jq_InstanceField m = (jq_InstanceField)findByNameAndDesc(declared_instance_fields, nd);
658 if (m != null) return m;
659
660 if (super_class != null) {
661 super_class.load();
662 m = super_class.getInstanceField(nd);
663 if (m != null) return m;
664 }
665 return null;
666 }
667 public final jq_InstanceMethod[] getVirtualMethods() {
668 chkState(STATE_PREPARED);
669 return virtual_methods;
670 }
671 public final jq_InstanceMethod getVirtualMethod(jq_NameAndDesc nd) {
672 chkState(STATE_PREPARED);
673 return (jq_InstanceMethod)findByNameAndDesc(virtual_methods, nd);
674 }
675 public final int getInstanceSize() {
676 chkState(STATE_PREPARED);
677 return instance_size;
678 }
679
680 public final int[] getStaticData() {
681 chkState(STATE_SFINITIALIZED);
682 return static_data;
683 }
684 public final void setStaticData(jq_StaticField sf, int data) {
685 chkState(STATE_SFINITIALIZED);
686 Assert._assert(sf.getDeclaringClass() == this);
687 Assert._assert(sf.getType().getReferenceSize() != 8);
688 int index = sf.getAddress().difference(HeapAddress.addressOf(static_data)) >> 2;
689 if (index < 0 || index >= static_data.length) {
690 Assert.UNREACHABLE("sf: "+sf+" index: "+index);
691 }
692 static_data[index] = data;
693 }
694 public final void setStaticData(jq_StaticField sf, long data) {
695 chkState(STATE_SFINITIALIZED);
696 Assert._assert(sf.getDeclaringClass() == this);
697 Assert._assert(sf.getType().getReferenceSize() == 8);
698 int index = sf.getAddress().difference(HeapAddress.addressOf(static_data)) >> 2;
699 static_data[index ] = (int)(data);
700 static_data[index+1] = (int)(data >> 32);
701 }
702 public final void setStaticData(jq_StaticField sf, float data) {
703 setStaticData(sf, Float.floatToRawIntBits(data));
704 }
705 public final void setStaticData(jq_StaticField sf, double data) {
706 setStaticData(sf, Double.doubleToRawLongBits(data));
707 }
708 public final void setStaticData(jq_StaticField sf, Object data) {
709 chkState(STATE_SFINITIALIZED);
710 Assert._assert(sf.getDeclaringClass() == this);
711 Assert._assert(sf.getType().getReferenceSize() != 8);
712 int index = sf.getAddress().difference(HeapAddress.addressOf(static_data)) >> 2;
713 static_data[index] = HeapAddress.addressOf(data).to32BitValue();
714 }
715 public final void setStaticData(jq_StaticField sf, Address data) {
716 chkState(STATE_SFINITIALIZED);
717 Assert._assert(sf.getDeclaringClass() == this);
718 Assert._assert(sf.getType().getReferenceSize() != 8);
719 int index = sf.getAddress().difference(HeapAddress.addressOf(static_data)) >> 2;
720 static_data[index] = data.to32BitValue();
721 }
722
723 public final Object newInstance() {
724 this.prepare();
725 return _delegate.newInstance(this, instance_size, vtable);
726 }
727
728
729 private Map
730 private char minor_version;
731 private char major_version;
732 private char access_flags;
733 private jq_Class super_class;
734 private jq_Class[] subclasses, subinterfaces;
735 private jq_Class[] declared_interfaces, interfaces;
736 private jq_StaticField[] static_fields;
737 private jq_StaticMethod[] static_methods;
738 private jq_InstanceField[] declared_instance_fields;
739 private jq_InstanceMethod[] declared_instance_methods;
740 private Map attributes;
741 private jq_ConstantPool const_pool;
742 private int static_data_size;
743 private int instance_size;
744 private jq_InstanceField[] instance_fields;
745 private int[] reference_offsets;
746 private jq_InstanceMethod[] virtual_methods;
747 private int[] static_data;
748 private boolean dont_align;
749
750 private static jq_Member findByNameAndDesc(jq_Member[] array, jq_NameAndDesc nd) {
751
752 for (int i=0; i<array.length; ++i) {
753 jq_Member m = array[i];
754 if (m.getNameAndDesc().equals(nd)) return m;
755 }
756 return null;
757 }
758
759 /***
760 * Private constructor.
761 * Use a ClassLoader to create a jq_Class instance.
762 */
763 private jq_Class(ClassLoader class_loader, Utf8 desc) {
764 super(desc, class_loader);
765 this.subclasses = new jq_Class[0];
766 this.subinterfaces = new jq_Class[0];
767 this.members = new HashMap();
768 }
769
770 public static jq_Class newClass(ClassLoader classLoader, Utf8 desc) {
771 Assert._assert(desc.isDescriptor(TC_CLASS));
772 return new jq_Class(classLoader, desc);
773 }
774
775 /***
776 * Loads the binary data for this class. See Jvm spec 2.17.2.
777 *
778 * Throws: ClassFormatError if the binary data is malformed in some way
779 * UnsupportedClassVersionError if the binary data is of an unsupported version
780 * ClassCircularityError if it would be its own superclass or superinterface
781 * NoClassDefFoundError if the class definition cannot be found
782 */
783 public void load()
784 throws ClassFormatError, UnsupportedClassVersionError, ClassCircularityError, NoClassDefFoundError {
785 if (isLoaded()) return;
786 Assert._assert(class_loader == PrimordialClassLoader.loader);
787 DataInputStream in = null;
788 try {
789 in = ((PrimordialClassLoader)class_loader).getClassFileStream(desc);
790 if (in == null) throw new NoClassDefFoundError(className(desc));
791 try {
792 load(in);
793 } catch (NoClassDefFoundError x) {
794 x.printStackTrace();
795 Assert.UNREACHABLE("Class not found error while attempting to load class!");
796 }
797 in.close();
798 } catch (IOException x) {
799 x.printStackTrace();
800 throw new ClassFormatError(x.toString());
801 } finally {
802 try { if (in != null) in.close(); } catch (IOException _) { }
803 }
804 }
805 public void load(DataInput in)
806 throws ClassFormatError, UnsupportedClassVersionError, ClassCircularityError {
807 if (isLoaded()) return;
808 if (state == STATE_LOADERROR) throw new ClassFormatError();
809 synchronized (this) {
810 if (isLoaded()) return;
811 if ((state == STATE_LOADING1) || (state == STATE_LOADING2) || (state == STATE_LOADING3))
812 throw new ClassCircularityError(this.toString());
813 state = STATE_LOADING1;
814 if (TRACE) Debug.writeln("Beginning loading "+this+"...");
815 try {
816 int magicNum = in.readInt();
817 if (magicNum != 0xCAFEBABE)
818 throw new ClassFormatError("bad magic number: "+Integer.toHexString(magicNum));
819 minor_version = (char)in.readUnsignedShort();
820 major_version = (char)in.readUnsignedShort();
821 if (((major_version != 45) || (minor_version != 0)) &&
822 ((major_version != 45) || (minor_version != 3)) &&
823 ((major_version != 46) || (minor_version != 0)) &&
824 ((major_version != 47) || (minor_version != 0)) &&
825 ((major_version != 48) || (minor_version != 0)) &&
826 ((major_version != 49) || (minor_version != 0))) {
827 throw new UnsupportedClassVersionError("unsupported version "+(int)major_version+"."+(int)minor_version);
828 }
829
830 char constant_pool_count = (char)in.readUnsignedShort();
831 const_pool = new jq_ConstantPool(constant_pool_count);
832
833 const_pool.load(in);
834
835 try {
836 const_pool.resolve(class_loader);
837 } catch (NoSuchMethodError x) {
838 throw new NoSuchMethodError("In class "+this+": "+x.getMessage());
839 } catch (NoSuchFieldError x) {
840 throw new NoSuchFieldError("In class "+this+": "+x.getMessage());
841 }
842
843 access_flags = (char)in.readUnsignedShort();
844 state = STATE_LOADING2;
845 char selfindex = (char)in.readUnsignedShort();
846 if (getCPtag(selfindex) != CONSTANT_ResolvedClass) {
847 throw new ClassFormatError("constant pool entry "+(int)selfindex+", referred to by field this_class" +
848 ", is wrong type tag (expected="+CONSTANT_Class+", actual="+getCPtag(selfindex)+")");
849 }
850 if (getCP(selfindex) != this && !this.getDesc().toString().startsWith("LREPLACE")) {
851 throw new ClassFormatError("expected class "+this+" but found class "+getCP(selfindex));
852 }
853 char superindex = (char)in.readUnsignedShort();
854 if (superindex != 0) {
855 if (getCPtag(superindex) != CONSTANT_ResolvedClass) {
856 throw new ClassFormatError("constant pool entry "+(int)superindex+", referred to by field super_class" +
857 ", is wrong type tag (expected="+CONSTANT_Class+", actual="+getCPtag(superindex)+")");
858 }
859 jq_Type super_type = getCPasType(superindex);
860 if (!super_type.isClassType()) {
861 throw new ClassFormatError("superclass ("+super_class.getName()+") is not a class type");
862 }
863 if (super_type == this) {
864 throw new ClassCircularityError(this.getName()+" has itself as a superclass!");
865 }
866 super_class = (jq_Class)super_type;
867 super_class.addSubclass(this);
868 } else {
869
870 if (PrimordialClassLoader.getJavaLangObject() != this) {
871 throw new ClassFormatError("no superclass listed for class "+this);
872 }
873 }
874 char n_interfaces = (char)in.readUnsignedShort();
875 declared_interfaces = new jq_Class[n_interfaces];
876 for (int i=0; i<n_interfaces; ++i) {
877 char interface_index = (char)in.readUnsignedShort();
878 if (getCPtag(interface_index) != CONSTANT_ResolvedClass) {
879 throw new ClassFormatError("constant pool entry "+(int)interface_index+", referred to by interfaces["+i+"]"+
880 ", is wrong type tag (expected="+CONSTANT_Class+", actual="+getCPtag(interface_index)+")");
881 }
882 declared_interfaces[i] = (jq_Class)getCPasType(interface_index);
883 if (!declared_interfaces[i].isClassType()) {
884 throw new ClassFormatError("implemented interface ("+super_class.getName()+") is not a class type");
885 }
886 if (declared_interfaces[i].isLoaded() && !declared_interfaces[i].isInterface()) {
887 throw new ClassFormatError("implemented interface ("+super_class.getName()+") is not an interface type");
888 }
889 if (declared_interfaces[i] == jq_DontAlign._class) dont_align = true;
890 declared_interfaces[i].addSubinterface(this);
891 }
892
893 char n_declared_fields = (char)in.readUnsignedShort();
894 char[] temp_declared_field_flags = new char[n_declared_fields];
895 jq_Field[] temp_declared_fields = new jq_Field[n_declared_fields];
896 int numStaticFields = 0, numInstanceFields = 0;
897 for (int i=0; i<n_declared_fields; ++i) {
898 temp_declared_field_flags[i] = (char)in.readUnsignedShort();
899
900 char field_name_index = (char)in.readUnsignedShort();
901 if (getCPtag(field_name_index) != CONSTANT_Utf8)
902 throw new ClassFormatError("constant pool entry "+(int)field_name_index+", referred to by field "+i+
903 ", is wrong type tag (expected="+CONSTANT_Utf8+", actual="+getCPtag(field_name_index)+")");
904 Utf8 field_name = getCPasUtf8(field_name_index);
905 char field_desc_index = (char)in.readUnsignedShort();
906 if (getCPtag(field_desc_index) != CONSTANT_Utf8)
907 throw new ClassFormatError("constant pool entry "+(int)field_desc_index+", referred to by field "+i+
908 ", is wrong type tag (expected="+CONSTANT_Utf8+", actual="+getCPtag(field_desc_index)+")");
909 Utf8 field_desc = getCPasUtf8(field_desc_index);
910 if (!field_desc.isValidTypeDescriptor())
911 throw new ClassFormatError(field_desc+" is not a valid type descriptor");
912 jq_NameAndDesc nd = new jq_NameAndDesc(field_name, field_desc);
913 jq_Field field = (jq_Field)getDeclaredMember(nd);
914 if ((temp_declared_field_flags[i] & ACC_STATIC) != 0) {
915 if (field == null) {
916 field = createStaticField(nd);
917 } else if (!field.isStatic())
918 throw new VerifyError("static field "+field+" was referred to as an instance field");
919 ++numStaticFields;
920 } else {
921 if (field == null) {
922 field = createInstanceField(nd);
923 } else if (field.isStatic())
924 throw new VerifyError("instance field "+field+" was referred to as a static field");
925 ++numInstanceFields;
926 }
927 field.load(temp_declared_field_flags[i], in);
928 temp_declared_fields[i] = field;
929 }
930 static_data_size = 0;
931 declared_instance_fields = new jq_InstanceField[numInstanceFields];
932 static_fields = new jq_StaticField[numStaticFields];
933 for (int i=0, di=-1, si=-1; i<n_declared_fields; ++i) {
934 if ((temp_declared_field_flags[i] & ACC_STATIC) != 0) {
935 static_fields[++si] = (jq_StaticField)temp_declared_fields[i];
936 static_data_size += static_fields[si].getWidth();
937 } else {
938 declared_instance_fields[++di] = (jq_InstanceField)temp_declared_fields[i];
939 }
940 }
941 if (!dont_align) {
942
943 Arrays.sort(declared_instance_fields, new Comparator() {
944 public int compare(jq_InstanceField o1, jq_InstanceField o2) {
945 int s1 = o1.getSize(), s2 = o2.getSize();
946 if (s1 > s2) return -1;
947 else if (s1 < s2) return 1;
948 else return 0;
949 }
950 public int compare(Object o1, Object o2) {
951 return compare((jq_InstanceField)o1, (jq_InstanceField)o2);
952 }
953 });
954 }
955
956 char n_declared_methods = (char)in.readUnsignedShort();
957 char[] temp_declared_method_flags = new char[n_declared_methods];
958 jq_Method[] temp_declared_methods = new jq_Method[n_declared_methods];
959 int numStaticMethods = 0, numInstanceMethods = 0;
960 for (int i=0; i<n_declared_methods; ++i) {
961 temp_declared_method_flags[i] = (char)in.readUnsignedShort();
962
963 char method_name_index = (char)in.readUnsignedShort();
964 if (getCPtag(method_name_index) != CONSTANT_Utf8)
965 throw new ClassFormatError("constant pool entry "+(int)method_name_index+", referred to by method "+i+
966 ", is wrong type tag (expected="+CONSTANT_Utf8+", actual="+getCPtag(method_name_index)+")");
967 Utf8 method_name = getCPasUtf8(method_name_index);
968 char method_desc_index = (char)in.readUnsignedShort();
969 if (getCPtag(method_desc_index) != CONSTANT_Utf8)
970 throw new ClassFormatError("constant pool entry "+(int)method_desc_index+", referred to by method "+i+
971 ", is wrong type tag (expected="+CONSTANT_Utf8+", actual="+getCPtag(method_desc_index)+")");
972 Utf8 method_desc = getCPasUtf8(method_desc_index);
973 if (!method_desc.isValidMethodDescriptor())
974 throw new ClassFormatError(method_desc+" is not a valid method descriptor");
975 jq_NameAndDesc nd = new jq_NameAndDesc(method_name, method_desc);
976 jq_Method method = (jq_Method)getDeclaredMember(nd);
977 if ((temp_declared_method_flags[i] & ACC_STATIC) != 0) {
978 if (method == null) {
979 method = createStaticMethod(nd);
980 } else if (!method.isStatic())
981 throw new VerifyError();
982 ++numStaticMethods;
983 } else {
984 if (method == null) {
985 method = createInstanceMethod(nd);
986 } else if (method.isStatic())
987 throw new VerifyError();
988 ++numInstanceMethods;
989 }
990 method.load(temp_declared_method_flags[i], in);
991 temp_declared_methods[i] = method;
992 }
993 declared_instance_methods = new jq_InstanceMethod[numInstanceMethods];
994 static_methods = new jq_StaticMethod[numStaticMethods];
995 for (int i=0, di=-1, si=-1; i<n_declared_methods; ++i) {
996 if ((temp_declared_method_flags[i] & ACC_STATIC) != 0) {
997 static_methods[++si] = (jq_StaticMethod)temp_declared_methods[i];
998 } else {
999 declared_instance_methods[++di] = (jq_InstanceMethod)temp_declared_methods[i];
1000 }
1001 }
1002
1003 attributes = new HashMap();
1004 readAttributes(in, attributes);
1005
1006 state = STATE_LOADING3;
1007
1008
1009
1010 Iterator impls = ClassLibInterface.DEFAULT.getImplementationClassDescs(getDesc());
1011 while (impls.hasNext()) {
1012 Utf8 impl_utf = (Utf8)impls.next();
1013 jq_Class mirrorclass = (jq_Class)PrimordialClassLoader.getOrCreateType(class_loader, impl_utf);
1014 try {
1015 if (TRACE) Debug.writeln("Attempting to load mirror class "+mirrorclass);
1016 mirrorclass.load();
1017 } catch (NoClassDefFoundError x) {
1018
1019 PrimordialClassLoader.unloadType(class_loader, mirrorclass);
1020 mirrorclass = null;
1021 }
1022 if (mirrorclass != null) {
1023 this.merge(mirrorclass);
1024 }
1025 }
1026
1027
1028 if (this.isInClassLib()) {
1029 if (TRACE) Debug.writeln(this+" is in the class library, rewriting method bodies.");
1030 final jq_ConstantPool.ConstantPoolRebuilder cpr = this.rebuildConstantPool(false);
1031
1032 for (int i=0; i<this.declared_instance_fields.length; ++i) {
1033 jq_InstanceField this_m = this.declared_instance_fields[i];
1034 jq_NameAndDesc nd = ClassLibInterface.convertClassLibNameAndDesc(this, this_m.getNameAndDesc());
1035 if (this_m.getNameAndDesc() != nd) {
1036 if (TRACE) Debug.writeln("Rewriting field signature from "+this_m.getNameAndDesc()+" to "+nd);
1037 jq_InstanceField this_m2 = getOrCreateInstanceField(nd);
1038 this_m2.load(this_m);
1039 this_m.unload(); Object b = this.members.remove(this_m.getNameAndDesc()); cpr.remove(this_m);
1040 if (TRACE) Debug.writeln("Removed member "+this_m.getNameAndDesc()+" from member set of "+this+": "+b);
1041 this.addDeclaredMember(nd, this_m2);
1042 this_m = declared_instance_fields[i] = this_m2;
1043 }
1044 }
1045
1046 for (int i=0; i<this.static_fields.length; ++i) {
1047 jq_StaticField this_m = this.static_fields[i];
1048 jq_NameAndDesc nd = ClassLibInterface.convertClassLibNameAndDesc(this, this_m.getNameAndDesc());
1049 if (this_m.getNameAndDesc() != nd) {
1050 if (TRACE) Debug.writeln("Rewriting field signature from "+this_m.getNameAndDesc()+" to "+nd);
1051 jq_StaticField this_m2 = getOrCreateStaticField(nd);
1052 this_m2.load(this_m);
1053 this_m.unload(); Object b = this.members.remove(this_m.getNameAndDesc()); cpr.remove(this_m);
1054 if (TRACE) Debug.writeln("Removed member "+this_m.getNameAndDesc()+" from member set of "+this+": "+b);
1055 this.addDeclaredMember(nd, this_m2);
1056 this_m = static_fields[i] = this_m2;
1057 }
1058 }
1059
1060 LinkedHashMap newInstanceMethods = new LinkedHashMap();
1061 for (int i=0; i<this.declared_instance_methods.length; ++i) {
1062 jq_InstanceMethod this_m = this.declared_instance_methods[i];
1063 jq_NameAndDesc nd = ClassLibInterface.convertClassLibNameAndDesc(this, this_m.getNameAndDesc());
1064 if (this_m.getNameAndDesc() != nd) {
1065 if (TRACE) Debug.writeln("Rewriting method signature from "+this_m.getNameAndDesc()+" to "+nd);
1066 jq_InstanceMethod this_m2 = getOrCreateInstanceMethod(nd);
1067 this_m2.load(this_m);
1068 this_m.unload(); Object b = this.members.remove(this_m.getNameAndDesc()); cpr.remove(this_m);
1069 if (TRACE) Debug.writeln("Removed member "+this_m.getNameAndDesc()+" from member set of "+this+": "+b);
1070 this.addDeclaredMember(nd, this_m2);
1071 this_m = this_m2;
1072 }
1073 byte[] bc = this_m.getBytecode();
1074 Bytecodes.InstructionList il;
1075 if (bc == null) {
1076 il = null;
1077 } else {
1078
1079 if (TRACE) Debug.writeln("Extracting instructions of "+this_m);
1080 il = new Bytecodes.InstructionList(this_m);
1081
1082
1083 rewriteMethod(cpr, il);
1084 }
1085
1086
1087 newInstanceMethods.put(this_m, il);
1088 }
1089
1090 LinkedHashMap newStaticMethods = new LinkedHashMap();
1091 for (int i=0; i<this.static_methods.length; ++i) {
1092 jq_StaticMethod this_m = this.static_methods[i];
1093 jq_NameAndDesc nd = ClassLibInterface.convertClassLibNameAndDesc(this, this_m.getNameAndDesc());
1094 if (this_m.getNameAndDesc() != nd) {
1095 if (TRACE) Debug.writeln("Rewriting method signature from "+this_m.getNameAndDesc()+" to "+nd);
1096 jq_StaticMethod this_m2 = getOrCreateStaticMethod(nd);
1097 this_m2.load(this_m);
1098 this_m.unload(); Object b = this.members.remove(this_m.getNameAndDesc()); cpr.remove(this_m);
1099 if (TRACE) Debug.writeln("Removed member "+this_m.getNameAndDesc()+" from member set of "+this+": "+b);
1100 this.addDeclaredMember(nd, this_m2);
1101 this_m = this_m2;
1102 }
1103 byte[] bc = this_m.getBytecode();
1104 Bytecodes.InstructionList il;
1105 if (bc == null) {
1106 il = null;
1107 } else {
1108
1109 if (TRACE) Debug.writeln("Extracting instructions of "+this_m);
1110 il = new Bytecodes.InstructionList(this_m);
1111
1112
1113 rewriteMethod(cpr, il);
1114 }
1115
1116
1117 newStaticMethods.put(this_m, il);
1118 }
1119 jq_ConstantPool new_cp = cpr.finish();
1120
1121 this.declared_instance_methods = new jq_InstanceMethod[newInstanceMethods.size()];
1122 int j = -1;
1123 for (Iterator i=newInstanceMethods.entrySet().iterator(); i.hasNext(); ) {
1124 Map.Entry e = (Map.Entry)i.next();
1125 jq_InstanceMethod i_m = (jq_InstanceMethod)e.getKey();
1126 Bytecodes.InstructionList i_l = (Bytecodes.InstructionList)e.getValue();
1127 if (i_l != null) {
1128 if (TRACE) Debug.writeln("Rebuilding bytecodes for instance method "+i_m+", entry "+(j+1));
1129 Bytecodes.CodeException[] ex_table = i_m.getExceptionTable(i_l);
1130 Bytecodes.LineNumber[] line_num = i_m.getLineNumberTable(i_l);
1131 i_m.setCode(i_l, ex_table, line_num, cpr);
1132 } else {
1133 if (TRACE) Debug.writeln("No bytecodes for instance method "+i_m+", entry "+(j+1));
1134 }
1135
1136 this.declared_instance_methods[++j] = i_m;
1137 }
1138 this.static_methods = new jq_StaticMethod[newStaticMethods.size()];
1139 j = -1;
1140 for (Iterator i=newStaticMethods.entrySet().iterator(); i.hasNext(); ) {
1141 Map.Entry e = (Map.Entry)i.next();
1142 jq_StaticMethod i_m = (jq_StaticMethod)e.getKey();
1143 Bytecodes.InstructionList i_l = (Bytecodes.InstructionList)e.getValue();
1144 if (i_l != null) {
1145 if (TRACE) Debug.writeln("Rebuilding bytecodes for static method "+i_m+", entry "+(j+1));
1146 Bytecodes.CodeException[] ex_table = i_m.getExceptionTable(i_l);
1147 Bytecodes.LineNumber[] line_num = i_m.getLineNumberTable(i_l);
1148 i_m.setCode(i_l, ex_table, line_num, cpr);
1149 } else {
1150 if (TRACE) Debug.writeln("No bytecodes for static method "+i_m+", entry "+(j+1));
1151 }
1152
1153 this.static_methods[++j] = i_m;
1154 }
1155 this.remakeAttributes(cpr);
1156 this.const_pool = new_cp;
1157 getSourceFile();
1158 if (TRACE) Debug.writeln("Finished rebuilding constant pool.");
1159 } else {
1160
1161
1162 Iterator it = members.entrySet().iterator();
1163 while (it.hasNext()) {
1164 Map.Entry e = (Map.Entry)it.next();
1165 jq_Member m = (jq_Member)e.getValue();
1166 if (m.getState() < STATE_LOADED) {
1167
1168
1169 it.remove();
1170 if (WARN_STALE_CLASS_FILES) {
1171 Set s = PrimordialClassLoader.loader.getClassesThatReference(m);
1172 System.err.println("Warning: classes "+s+" refer to member "+m+", which does not exist. This may indicate stale class files.");
1173 }
1174
1175 }
1176 }
1177
1178 }
1179
1180
1181 if (TRACE) Debug.writeln("Finished loading "+this);
1182 state = STATE_LOADED;
1183
1184
1185
1186
1187
1188 String thisDesc = this.getDesc().toString();
1189 if (thisDesc.startsWith("LREPLACE")) {
1190 Utf8 oldDesc = Utf8.get("L" + thisDesc.substring( 8 , thisDesc.length() ));
1191 jq_Type old = PrimordialClassLoader.getOrCreateType(class_loader , oldDesc) ;
1192 Assert._assert(old instanceof jq_Class);
1193 if (((jq_Class)old).getState() < STATE_LOADED) {
1194
1195 if (TRACE_REPLACE_CLASS) Debug.writeln("REPLACING Class: " + old.getDesc() + ". This class was not in the original image: doing nothing!");
1196 PrimordialClassLoader.unloadType(class_loader , old) ;
1197 } else {
1198 replaceMethodIn((jq_Class) old);
1199 }
1200 }
1201 }
1202 catch (UTFDataFormatError x) {
1203 state = STATE_LOADERROR;
1204
1205 throw new ClassFormatError(x.toString());
1206 }
1207 catch (IOException x) {
1208 state = STATE_LOADERROR;
1209
1210 throw new ClassFormatError(x.toString());
1211 }
1212 catch (ArrayIndexOutOfBoundsException x) {
1213 state = STATE_LOADERROR;
1214
1215 x.printStackTrace();
1216 throw new ClassFormatError("bad constant pool index");
1217 }
1218 catch (Error x) {
1219 state = STATE_LOADERROR;
1220
1221 throw x;
1222 }
1223 }
1224 }
1225
1226
1227
1228 private void replaceMethodIn(jq_Class old) {
1229
1230 jq_ConstantPool.ConstantPoolAdder cpa =
1231 new jq_ConstantPool.ConstantPoolAdder(old.const_pool);
1232
1233
1234
1235 for (int i = 0;
1236 (old.static_methods != null) && i < old.static_methods.length;
1237 ++i) {
1238 jq_StaticMethod old_m = old.static_methods[i];
1239 jq_NameAndDesc nd = old_m.getNameAndDesc();
1240 jq_StaticMethod new_m = this.getDeclaredStaticMethod(nd);
1241 if (new_m != null) {
1242
1243 byte[] new_bc = new_m.getBytecode();
1244 byte[] old_bc = old_m.getBytecode();
1245
1246
1247 if (new_bc.length == old_bc.length)
1248 continue;
1249
1250
1251 if (TRACE_REPLACE_CLASS)
1252 joeq.Runtime.Debug.writeln(
1253 Strings.lineSep+Strings.lineSep+"In REPLACE: STARTING REPLACEMENT of:\t" + old_m);
1254
1255 jq_NameAndDesc old_m_nd = old_m.getNameAndDesc();
1256
1257 Bytecodes.InstructionList il;
1258 if (TRACE) Debug.writeln("Extracting instructions of "+new_m);
1259 il = new Bytecodes.InstructionList(new_m);
1260
1261
1262 if (TRACE_REPLACE_CLASS)
1263 Debug.writeln(
1264 "\tIn Replace: Rebuilding CP for static method "
1265 + new_m);
1266 old.rewriteMethodForReplace(cpa, il);
1267 cpa.finish();
1268 Bytecodes.CodeException[] ex_table = new_m.getExceptionTable(il);
1269 Bytecodes.LineNumber[] line_num = new_m.getLineNumberTable(il);
1270
1271 new_m.setCode(il, ex_table, line_num, cpa);
1272
1273 old.remakeAttributes(cpa);
1274
1275 if (TRACE_REPLACE_CLASS)
1276 Debug.writeln(
1277 "\tIn Replace: Finished Rebuilding CP for static method "
1278 + new_m);
1279
1280
1281 new_m.setNameAndDesc(old_m_nd);
1282 old.addDeclaredMember(old_m_nd, new_m);
1283 new_m.setDeclaringClass(old);
1284
1285
1286 new_m.prepare();
1287
1288
1289 if (TRACE_REPLACE_CLASS)
1290 Debug.writeln(
1291 "\tIn REPLACE: Compiling stub for: " + new_m);
1292 new_m.compile();
1293
1294 old.static_methods[i] = new_m;
1295 old_m.default_compiled_version.redirect(new_m.default_compiled_version);
1296 old_m.default_compiled_version =
1297 new_m.default_compiled_version;
1298
1299 if (TRACE_REPLACE_CLASS)
1300 Debug.writeln(
1301 Strings.lineSep+Strings.lineSep+"In Replace: DONE REPLACEMENT for STATIC method "
1302 + old_m);
1303 } else {
1304
1305
1306
1307 }
1308 }
1309
1310
1311 for (int i = 0;
1312 (old.declared_instance_methods != null)
1313 && i < old.declared_instance_methods.length;
1314 ++i) {
1315 jq_InstanceMethod old_m = old.declared_instance_methods[i];
1316 jq_NameAndDesc nd = old_m.getNameAndDesc();
1317 jq_InstanceMethod new_m = this.getDeclaredInstanceMethod(nd);
1318 if (new_m != null) {
1319
1320 byte[] new_bc = new_m.getBytecode();
1321 byte[] old_bc = old_m.getBytecode();
1322
1323 if (new_bc == null || old_bc == null)
1324 continue;
1325
1326
1327
1328 if (new_bc.length == old_bc.length)
1329 continue;
1330
1331
1332 if (TRACE_REPLACE_CLASS)
1333 joeq.Runtime.Debug.writeln(
1334 Strings.lineSep+Strings.lineSep+"In REPLACE: STARTING REPLACEMENT of:\t" + old_m);
1335
1336
1337 jq_NameAndDesc old_m_nd = old_m.getNameAndDesc();
1338
1339 Bytecodes.InstructionList il;
1340
1341 if (TRACE) Debug.writeln("Extracting instructions of "+new_m);
1342 il = new Bytecodes.InstructionList(new_m);
1343
1344
1345 if (TRACE_REPLACE_CLASS)
1346 Debug.writeln(
1347 "\tIn Replace: Rebuilding CP for instance method "
1348 + new_m);
1349 old.rewriteMethodForReplace(cpa, il);
1350
1351 cpa.finish();
1352 Bytecodes.CodeException[] ex_table = new_m.getExceptionTable(il);
1353 Bytecodes.LineNumber[] line_num = new_m.getLineNumberTable(il);
1354 new_m.setCode(il, ex_table, line_num, cpa);
1355
1356 old.remakeAttributes(cpa);
1357
1358
1359 if (TRACE_REPLACE_CLASS)
1360 Debug.writeln(
1361 "\tIn Replace: Finished Rebuilding CP for instance method "
1362 + new_m);
1363
1364
1365 new_m.setNameAndDesc(old_m_nd);
1366 old.addDeclaredMember(old_m_nd, new_m);
1367 new_m.setDeclaringClass(old);
1368
1369 if (new_m.isInitializer() || new_m.isPrivate()) {
1370 new_m.prepare();
1371
1372 if (TRACE_REPLACE_CLASS)
1373 Debug.writeln(
1374 "\tIn REPLACE: Compiling stub for: " + new_m);
1375 new_m.compile();
1376 } else
1377 {
1378
1379
1380 int old_m_offset = old_m.getOffset();
1381 new_m.prepare(old_m_offset);
1382
1383
1384 if (TRACE_REPLACE_CLASS)
1385 Debug.writeln(
1386 "\tIn REPLACE: Compiling stub for: " + new_m);
1387 new_m.compile();
1388
1389 int index = (old_m_offset >> 2) - 1;
1390
1391 Assert._assert(old.virtual_methods[index] == old_m);
1392 old.virtual_methods[index] = new_m;
1393 CodeAddress entryPoint =
1394 new_m.getDefaultCompiledVersion().getEntrypoint();
1395 ((Address[]) old.vtable)[index + 1] = entryPoint;
1396
1397 }
1398
1399 old.declared_instance_methods[i] = new_m;
1400
1401 old_m.default_compiled_version.redirect(new_m.default_compiled_version);
1402 old_m.default_compiled_version =
1403 new_m.default_compiled_version;
1404
1405 if (TRACE_REPLACE_CLASS)
1406 Debug.writeln(
1407 Strings.lineSep+Strings.lineSep+"In Replace: DONE REPLACING instance method "
1408 + old_m);
1409 } else {
1410
1411
1412
1413 }
1414 }
1415
1416 {
1417
1418
1419
1420 }
1421 }
1422
1423 public boolean isInClassLib() {
1424 return (this.getDesc().toString().startsWith("Ljoeq/ClassLib/") &&
1425 this.getDesc().toString().indexOf('/', 11) != -1);
1426 }
1427
1428 public boolean doesConstantPoolContain(Object o) {
1429 if (const_pool == null) return false;
1430 return const_pool.contains(o);
1431 }
1432
1433 public jq_StaticMethod generateStaticMethodStub(jq_NameAndDesc nd, jq_StaticMethod m, char access_flags, char classfield_idx, char method_idx) {
1434 jq_Type[] params = m.getParamTypes();
1435 Assert._assert(params.length >= 1);
1436 int size = 3+((params.length-1)*2)+3+1;
1437 byte[] bc = new byte[size];
1438 bc[0] = (byte)0xb2;
1439 bc[1] = (byte)(classfield_idx >> 8);
1440 bc[2] = (byte)classfield_idx;
1441 int k=2;
1442 for (int j=1, n=0; j<params.length; ++j, ++n) {
1443 if (params[j].isReferenceType()) {
1444 bc[++k] = (byte)0x19;
1445 } else if (params[j] == jq_Primitive.LONG) {
1446 bc[++k] = (byte)0x16;
1447 } else if (params[j] == jq_Primitive.FLOAT) {
1448 bc[++k] = (byte)0x17;
1449 } else if (params[j] == jq_Primitive.DOUBLE) {
1450 bc[++k] = (byte)0x18;
1451 } else {
1452 bc[++k] = (byte)0x15;
1453 }
1454 bc[++k] = (byte)n;
1455 if ((params[j] == jq_Primitive.LONG) || (params[j] == jq_Primitive.DOUBLE))
1456 ++n;
1457 }
1458 bc[++k] = (byte)0xb8;
1459 bc[++k] = (byte)(method_idx>>8);
1460 bc[++k] = (byte)method_idx;
1461 jq_Type t = m.getReturnType();
1462 if (t.isReferenceType()) {
1463 bc[++k] = (byte)0xb0;
1464 } else if (t == jq_Primitive.LONG) {
1465 bc[++k] = (byte)0xad;
1466 } else if (t == jq_Primitive.FLOAT) {
1467 bc[++k] = (byte)0xae;
1468 } else if (t == jq_Primitive.DOUBLE) {
1469 bc[++k] = (byte)0xaf;
1470 } else if (t == jq_Primitive.VOID) {
1471 bc[++k] = (byte)0xb1;
1472 } else {
1473 bc[++k] = (byte)0xac;
1474 }
1475 jq_Method stubm = (jq_Method)getDeclaredMember(nd);
1476 jq_StaticMethod stub;
1477 if (stubm == null) stub = jq_StaticMethod.newStaticMethod(this, nd);
1478 else {
1479
1480 Assert._assert(stubm.isStatic(), stubm.toString());
1481 stub = (jq_StaticMethod)stubm;
1482 }
1483
1484 char max_stack = (char)Math.max(m.getParamWords(), m.getReturnType().getReferenceSize()>>2);
1485 char max_locals = (char)(m.getParamWords()-1);
1486 stub.load(access_flags, max_stack, max_locals, bc, new jq_TryCatchBC[0], new jq_LineNumberBC[0], new HashMap());
1487 return stub;
1488 }
1489
1490 public jq_InstanceMethod generateInstanceMethodStub(jq_NameAndDesc nd, jq_StaticMethod m, char access_flags, char method_idx) {
1491 jq_Type[] params = m.getParamTypes();
1492 Assert._assert(params.length >= 1);
1493 int size = 1+((params.length-1)*2)+3+1;
1494 byte[] bc = new byte[size];
1495 bc[0] = (byte)0x2a;
1496 int k=0;
1497 for (int j=1, n=1; j<params.length; ++j, ++n) {
1498 if (params[j].isReferenceType()) {
1499 bc[++k] = (byte)0x19;
1500 } else if (params[j] == jq_Primitive.LONG) {
1501 bc[++k] = (byte)0x16;
1502 } else if (params[j] == jq_Primitive.FLOAT) {
1503 bc[++k] = (byte)0x17;
1504 } else if (params[j] == jq_Primitive.DOUBLE) {
1505 bc[++k] = (byte)0x18;
1506 } else {
1507 bc[++k] = (byte)0x15;
1508 }
1509 bc[++k] = (byte)n;
1510 if ((params[j] == jq_Primitive.LONG) || (params[j] == jq_Primitive.DOUBLE))
1511 ++n;
1512 }
1513 bc[++k] = (byte)0xb8;
1514 bc[++k] = (byte)(method_idx>>8);
1515 bc[++k] = (byte)method_idx;
1516 jq_Type t = m.getReturnType();
1517 if (t.isReferenceType()) {
1518 bc[++k] = (byte)0xb0;
1519 } else if (t == jq_Primitive.LONG) {
1520 bc[++k] = (byte)0xad;
1521 } else if (t == jq_Primitive.FLOAT) {
1522 bc[++k] = (byte)0xae;
1523 } else if (t == jq_Primitive.DOUBLE) {
1524 bc[++k] = (byte)0xaf;
1525 } else if (t == jq_Primitive.VOID) {
1526 bc[++k] = (byte)0xb1;
1527 } else {
1528 bc[++k] = (byte)0xac;
1529 }
1530 jq_Method stubm = (jq_Method)getDeclaredMember(nd);
1531 jq_InstanceMethod stub;
1532 if (stubm == null) stub = jq_InstanceMethod.newInstanceMethod(this, nd);
1533 else {
1534
1535 Assert._assert(!stubm.isStatic(), stubm.toString());
1536 stub = (jq_InstanceMethod)stubm;
1537 }
1538
1539 char max_stack = (char)Math.max(m.getParamWords(), m.getReturnType().getReferenceSize()>>2);
1540 char max_locals = (char)m.getParamWords();
1541 stub.load(access_flags, max_stack, max_locals, bc, new jq_TryCatchBC[0], new jq_LineNumberBC[0], new HashMap());
1542 return stub;
1543 }
1544
1545
1546 public void merge(jq_Class that) {
1547
1548 final jq_ConstantPool.ConstantPoolRebuilder cpr = rebuildConstantPool(true);
1549
1550
1551 LinkedList newInstanceFields = new LinkedList();
1552 for (int i=0; i<that.declared_instance_fields.length; ++i) {
1553 jq_InstanceField that_f = that.declared_instance_fields[i];
1554 jq_NameAndDesc nd = ClassLibInterface.convertClassLibNameAndDesc(that, that_f.getNameAndDesc());
1555 jq_InstanceField this_f = this.getDeclaredInstanceField(nd);
1556 if (this_f != null) {
1557 if (TRACE) Debug.writeln("Instance field "+this_f+" already exists, skipping.");
1558 if (this_f.getAccessFlags() != that_f.getAccessFlags()) {
1559 if (TRACE)
1560 Debug.writeln("Access flags of instance field "+this_f+" from merged class do not match. ("+
1561 (int)this_f.getAccessFlags()+"!="+(int)that_f.getAccessFlags()+")");
1562 }
1563 continue;
1564 }
1565 this_f = getOrCreateInstanceField(nd);
1566 Assert._assert(this_f.getState() == STATE_UNLOADED);
1567 this_f.load(that_f);
1568 that_f.unload(); Object b = that.members.remove(that_f.getNameAndDesc());
1569 if (TRACE) Debug.writeln("Removed member "+that_f.getNameAndDesc()+" from member set of "+that+": "+b);
1570 if (TRACE) Debug.writeln("Adding instance field: "+this_f);
1571 this.addDeclaredMember(nd, this_f);
1572 newInstanceFields.add(this_f);
1573 cpr.addUtf8(this_f.getName());
1574 cpr.addUtf8(this_f.getDesc());
1575 cpr.addAttributeNames(this_f);
1576 }
1577 if (newInstanceFields.size() > 0) {
1578 jq_InstanceField[] ifs = new jq_InstanceField[this.declared_instance_fields.length+newInstanceFields.size()];
1579 System.arraycopy(this.declared_instance_fields, 0, ifs, 0, this.declared_instance_fields.length);
1580 int j = this.declared_instance_fields.length-1;
1581 for (Iterator i=newInstanceFields.iterator(); i.hasNext(); )
1582 ifs[++j] = (jq_InstanceField)i.next();
1583 this.declared_instance_fields = ifs;
1584 }
1585
1586
1587 LinkedList newStaticFields = new LinkedList();
1588 for (int i=0; i<that.static_fields.length; ++i) {
1589 jq_StaticField that_f = that.static_fields[i];
1590 jq_NameAndDesc nd = ClassLibInterface.convertClassLibNameAndDesc(that, that_f.getNameAndDesc());
1591 jq_StaticField this_f = this.getDeclaredStaticField(nd);
1592 if (this_f != null) {
1593 if (TRACE) Debug.writeln("Static field "+this_f+" already exists, skipping.");
1594 if (this_f.getAccessFlags() != that_f.getAccessFlags()) {
1595 if (TRACE)
1596 Debug.writeln("Access flags of static field "+this_f+" from merged class do not match. ("+
1597 (int)this_f.getAccessFlags()+"!="+(int)that_f.getAccessFlags()+")");
1598 }
1599 continue;
1600 }
1601 this_f = getOrCreateStaticField(nd);
1602 Assert._assert(this_f.getState() == STATE_UNLOADED);
1603 this_f.load(that_f);
1604 that_f.unload(); Object b = that.members.remove(that_f.getNameAndDesc());
1605 if (TRACE) Debug.writeln("Removed member "+that_f.getNameAndDesc()+" from member set of "+that+": "+b);
1606 if (TRACE) Debug.writeln("Adding static field: "+this_f);
1607 this.addDeclaredMember(nd, this_f);
1608 newStaticFields.add(this_f);
1609 cpr.addUtf8(this_f.getName());
1610 cpr.addUtf8(this_f.getDesc());
1611 cpr.addAttributeNames(this_f);
1612 }
1613 if (newStaticFields.size() > 0) {
1614 jq_StaticField[] ifs = new jq_StaticField[this.static_fields.length+newStaticFields.size()];
1615 System.arraycopy(this.static_fields, 0, ifs, 0, this.static_fields.length);
1616 int j = this.static_fields.length-1;
1617 for (Iterator i=newStaticFields.iterator(); i.hasNext(); ) {
1618 ifs[++j] = (jq_StaticField)i.next();
1619 this.static_data_size += ifs[j].getWidth();
1620 }
1621 this.static_fields = ifs;
1622 }
1623
1624
1625
1626
1627
1628 LinkedHashMap newInstanceMethods = new LinkedHashMap();
1629 for (int i=0; i<that.declared_instance_methods.length; ++i) {
1630 jq_InstanceMethod that_m = that.declared_instance_methods[i];
1631 jq_NameAndDesc nd = that_m.getNameAndDesc();
1632
1633 Assert._assert(ClassLibInterface.convertClassLibNameAndDesc(that, nd) == nd);
1634 jq_InstanceMethod this_m = this.getDeclaredInstanceMethod(nd);
1635 byte[] bc = that_m.getBytecode();
1636 if (bc == null) {
1637 if (this_m != null) {
1638 if (TRACE) Debug.writeln("Using existing body for instance method "+this_m+".");
1639 } else {
1640 if (TRACE)
1641 System.err.println("Body of method "+that_m+" doesn't already exist!");
1642 }
1643 continue;
1644 }
1645 if (bc.length == 5 && that_m instanceof jq_Initializer && that_m.getDesc() == Utf8.get("()V") &&
1646 this.getInitializer(Utf8.get("()V")) != null) {
1647 if (TRACE) Debug.writeln("Skipping default initializer "+that_m+".");
1648 continue;
1649 }
1650
1651
1652 if (TRACE) Debug.writeln("Extracting instructions of "+that_m);
1653 Bytecodes.InstructionList il = new Bytecodes.InstructionList(that_m);
1654
1655
1656 rewriteMethod(cpr, il);
1657
1658 if (false) {
1659
1660 if (TRACE) Debug.writeln("Using existing instance method object "+this_m+".");
1661 } else {
1662 if (TRACE) Debug.writeln("Creating new instance method object "+nd+".");
1663 this_m = this.getOrCreateInstanceMethod(nd);
1664 this.addDeclaredMember(nd, this_m);
1665 that_m.unload(); Object b = that.members.remove(that_m.getNameAndDesc());
1666 if (TRACE) Debug.writeln("Removed member "+that_m.getNameAndDesc()+" from member set of "+that+": "+b);
1667 }
1668
1669
1670 this_m.load(that_m);
1671
1672
1673 newInstanceMethods.put(this_m, il);
1674 }
1675
1676 for (int i=0; i<this.declared_instance_methods.length; ++i) {
1677 jq_InstanceMethod this_m = this.declared_instance_methods[i];
1678 jq_Member this_m2 = this.getDeclaredMember(this_m.getNameAndDesc());
1679 if (newInstanceMethods.containsKey(this_m2)) {
1680 if (TRACE) Debug.writeln("Skipping replaced instance method object "+this_m+".");
1681 continue;
1682 }
1683 Assert._assert(this_m == this_m2);
1684 byte[] bc = this_m.getBytecode();
1685 if (bc == null) {
1686 if (TRACE) Debug.writeln("Skipping native/abstract instance method object "+this_m+".");
1687 newInstanceMethods.put(this_m, null);
1688 continue;
1689 }
1690
1691
1692 if (TRACE) Debug.writeln("Extracting instructions of "+this_m);
1693 Bytecodes.InstructionList il = new Bytecodes.InstructionList(this_m);
1694
1695
1696 cpr.addCode(il);
1697
1698
1699 newInstanceMethods.put(this_m, il);
1700 }
1701
1702 Bytecodes.InstructionList rebuilt_clinit = null;
1703
1704
1705 LinkedHashMap newStaticMethods = new LinkedHashMap();
1706 for (int i=0; i<that.static_methods.length; ++i) {
1707 jq_StaticMethod that_m = that.static_methods[i];
1708 Bytecodes.InstructionList il;
1709 jq_StaticMethod this_m;
1710 if (that_m instanceof jq_ClassInitializer) {
1711 if (TRACE) Debug.writeln("Creating special static method for "+that_m+" class initializer.");
1712 Assert._assert(that_m.getBytecode() != null);
1713 Utf8 newname = Utf8.get("clinit_"+that.getJDKName());
1714 jq_NameAndDesc nd = new jq_NameAndDesc(newname, that_m.getDesc());
1715 this_m = getOrCreateStaticMethod(nd);
1716 this.addDeclaredMember(nd, this_m);
1717 this_m.load(that_m);
1718
1719
1720 jq_ClassInitializer clinit = getClassInitializer();
1721 if (clinit == null) {
1722 jq_NameAndDesc nd2 = new jq_NameAndDesc(Utf8.get("<clinit>"), Utf8.get("()V"));
1723 clinit = (jq_ClassInitializer)getOrCreateStaticMethod(nd2);
1724 this.addDeclaredMember(nd2, clinit);
1725 clinit.load((char)(ACC_PUBLIC | ACC_STATIC), (char)0, (char)0, new byte[0],
1726 new jq_TryCatchBC[0], new jq_LineNumberBC[0], new HashMap());
1727 if (TRACE) Debug.writeln("Created class initializer "+clinit);
1728 rebuilt_clinit = new Bytecodes.InstructionList();
1729 Bytecodes.RETURN re = new Bytecodes.RETURN();
1730 rebuilt_clinit.append(re);
1731 rebuilt_clinit.setPositions();
1732 } else {
1733 if (TRACE) Debug.writeln("Using existing class initializer "+clinit);
1734 rebuilt_clinit = new Bytecodes.InstructionList(clinit);
1735 }
1736 Bytecodes.INVOKESTATIC is = new Bytecodes.INVOKESTATIC(this_m);
1737 rebuilt_clinit.insert(is);
1738 cpr.addCode(rebuilt_clinit);
1739
1740
1741 if (TRACE) Debug.writeln("Extracting instructions of "+that_m);
1742 il = new Bytecodes.InstructionList(that_m);
1743
1744 newStaticMethods.put(clinit, rebuilt_clinit);
1745
1746 that_m.unload(); Object b = that.members.remove(that_m.getNameAndDesc());
1747 if (TRACE) Debug.writeln("Removed member "+that_m.getNameAndDesc()+" from member set of "+that+": "+b);
1748 } else {
1749 jq_NameAndDesc nd = that_m.getNameAndDesc();
1750
1751 Assert._assert(ClassLibInterface.convertClassLibNameAndDesc(that, nd) == nd);
1752 this_m = this.getDeclaredStaticMethod(nd);
1753 byte[] bc = that_m.getBytecode();
1754 if (bc == null) {
1755 if (this_m != null) {
1756 if (TRACE) Debug.writeln("Using existing body for static method "+this_m+".");
1757 } else {
1758 if (TRACE)
1759 System.err.println("Body of method "+that_m+" doesn't already exist!");
1760 }
1761 continue;
1762 }
1763
1764 if (TRACE) Debug.writeln("Extracting instructions of "+that_m);
1765 il = new Bytecodes.InstructionList(that_m);
1766
1767 if (false) {
1768
1769 if (TRACE) Debug.writeln("Using existing static method object "+this_m+".");
1770 } else {
1771 this_m = getOrCreateStaticMethod(nd);
1772 this.addDeclaredMember(nd, this_m);
1773 that_m.unload(); Object b = that.members.remove(that_m.getNameAndDesc());
1774 if (TRACE) Debug.writeln("Removed member "+that_m.getNameAndDesc()+" from member set of "+that+": "+b);
1775 if (TRACE) Debug.writeln("Created new static method object "+this_m+".");
1776 }
1777 this_m.load(that_m);
1778 }
1779
1780
1781 rewriteMethod(cpr, il);
1782
1783
1784 newStaticMethods.put(this_m, il);
1785 }
1786 for (int i=0; i<this.static_methods.length; ++i) {
1787 jq_StaticMethod this_m = this.static_methods[i];
1788 jq_Member this_m2 = this.getDeclaredMember(this_m.getNameAndDesc());
1789 if (newStaticMethods.containsKey(this_m2)) {
1790
1791 continue;
1792 }
1793 Assert._assert(this_m == this_m2);
1794 byte[] bc = this_m.getBytecode();
1795 if (bc == null) {
1796
1797 newStaticMethods.put(this_m, null);
1798 continue;
1799 }
1800
1801
1802 if (TRACE) Debug.writeln("Extracting instructions of "+this_m);
1803 Bytecodes.InstructionList il = new Bytecodes.InstructionList(this_m);
1804
1805
1806 cpr.addCode(il);
1807
1808
1809 newStaticMethods.put(this_m, il);
1810 }
1811
1812
1813 jq_ConstantPool new_cp = cpr.finish();
1814
1815
1816 this.declared_instance_methods = new jq_InstanceMethod[newInstanceMethods.size()];
1817 int j = -1;
1818 for (Iterator i=newInstanceMethods.entrySet().iterator(); i.hasNext(); ) {
1819 Map.Entry e = (Map.Entry)i.next();
1820 jq_InstanceMethod i_m = (jq_InstanceMethod)e.getKey();
1821 Bytecodes.InstructionList i_l = (Bytecodes.InstructionList)e.getValue();
1822 if (i_l != null) {
1823 if (TRACE) Debug.writeln("Rebuilding bytecodes for instance method "+i_m+".");
1824 Bytecodes.CodeException[] ex_table = i_m.getExceptionTable(i_l);
1825 Bytecodes.LineNumber[] line_num = i_m.getLineNumberTable(i_l);
1826 i_m.setCode(i_l, ex_table, line_num, cpr);
1827 } else {
1828 if (TRACE) Debug.writeln("No bytecodes for instance method "+i_m+".");
1829 }
1830
1831 this.declared_instance_methods[++j] = i_m;
1832 }
1833 this.static_methods = new jq_StaticMethod[newStaticMethods.size()];
1834 j = -1;
1835 for (Iterator i=newStaticMethods.entrySet().iterator(); i.hasNext(); ) {
1836 Map.Entry e = (Map.Entry)i.next();
1837 jq_StaticMethod i_m = (jq_StaticMethod)e.getKey();
1838 Bytecodes.InstructionList i_l = (Bytecodes.InstructionList)e.getValue();
1839 if (i_l != null) {
1840 if (TRACE) Debug.writeln("Rebuilding bytecodes for static method "+i_m+".");
1841 Bytecodes.CodeException[] ex_table = i_m.getExceptionTable(i_l);
1842 Bytecodes.LineNumber[] line_num = i_m.getLineNumberTable(i_l);
1843 i_m.setCode(i_l, ex_table, line_num, cpr);
1844 } else {
1845 if (TRACE) Debug.writeln("No bytecodes for static method "+i_m+".");
1846 }
1847
1848 this.static_methods[++j] = i_m;
1849 }
1850 this.remakeAttributes(cpr);
1851 this.const_pool = new_cp;
1852 getSourceFile();
1853 if (TRACE) Debug.writeln("Finished rebuilding constant pool.");
1854
1855 that.super_class.removeSubclass(that);
1856 for (int i=0; i<that.declared_interfaces.length; ++i) {
1857 jq_Class di = that.declared_interfaces[i];
1858 di.removeSubinterface(that);
1859 }
1860 PrimordialClassLoader.unloadType(class_loader, that);
1861 if (TRACE) Debug.writeln("Finished merging class "+this+".");
1862 }
1863
1864 public void remakeAttributes(jq_ConstantPool.ConstantPoolRebuilder cpr) {
1865 Utf8 sf = getSourceFile();
1866 if (sf != null) {
1867 byte[] b = new byte[2];
1868 Convert.charToTwoBytes(cpr.get(sf), b, 0);
1869 attributes.put(Utf8.get("SourceFile"), b);
1870 if (TRACE) Debug.writeln("Reset SourceFile attribute to cp idx "+(int)cpr.get(sf)+".");
1871 }
1872 }
1873
1874 private void rewriteMethod(jq_ConstantPool.ConstantPoolRebuilder cp, Bytecodes.InstructionList il) {
1875 final jq_ConstantPool.ConstantPoolRebuilder cpr = cp;
1876 il.accept(new Bytecodes.EmptyVisitor() {
1877 public void visitCPInstruction(Bytecodes.CPInstruction x) {
1878 Object o = x.getObject();
1879 if (o instanceof String) {
1880 cpr.addString((String)o);
1881 } else if (o instanceof Class) {
1882 jq_Type r = Reflection.getJQType((Class)o);
1883 if (r instanceof jq_Reference) {
1884 r = ClassLibInterface.convertClassLibCPEntry((jq_Reference)r);
1885 x.setObject(r.getJavaLangClassObject());
1886 }
1887 cpr.addType(r);
1888 } else if (o instanceof jq_Type) {
1889 if (o instanceof jq_Reference)
1890 x.setObject(o = ClassLibInterface.convertClassLibCPEntry((jq_Reference)o));
1891 cpr.addType((jq_Type)o);
1892 } else if (o instanceof jq_Member) {
1893 x.setObject(o = ClassLibInterface.convertClassLibCPEntry((jq_Member)o));
1894 cpr.addMember((jq_Member)o);
1895 } else {
1896 cpr.addOther(o);
1897 }
1898 }
1899 });
1900 }
1901
1902 private void rewriteMethodForReplace(jq_ConstantPool.ConstantPoolRebuilder cp,
1903 Bytecodes.InstructionList il) {
1904 final jq_ConstantPool.ConstantPoolRebuilder cpr = cp;
1905 il.accept(new Bytecodes.EmptyVisitor() {
1906 public void visitCPInstruction(Bytecodes.CPInstruction x) {
1907 Object o = x.getObject();
1908 if (o instanceof String) {
1909 cpr.addString((String) o);
1910 } else if (o instanceof Class) {
1911 cpr.addType(Reflection.getJQType((Class)o));
1912 } else if (o instanceof jq_Type) {
1913 if (o instanceof jq_Reference)
1914 cpr.addType((jq_Type) o);
1915 } else if (o instanceof jq_Member) {
1916 cpr.addMember((jq_Member) o);
1917 } else {
1918 cpr.addOther(o);
1919 }
1920 }
1921 });
1922 }
1923
1924 public void merge_old(jq_Class that) {
1925
1926 jq_ConstantPool.Adder cp_adder = const_pool.getAdder();
1927
1928
1929 Assert._assert(that.declared_instance_methods.length <= 1, that.toString());
1930 LinkedList toadd_instance = new LinkedList();
1931 LinkedList toadd_static = new LinkedList();
1932 char classfield_index = 0;
1933 for (int i=0; i<that.static_methods.length; ++i) {
1934 jq_StaticMethod sm = that.static_methods[i];
1935 if (sm.isClassInitializer()) continue;
1936 jq_Type[] that_param = sm.getParamTypes();
1937 Assert._assert(that_param.length >= 1, sm.toString());
1938 Utf8 name_utf = sm.getName();
1939 if (name_utf == Utf8.get("__init__")) name_utf = Utf8.get("<init>");
1940 char method_idx = cp_adder.add(sm, CONSTANT_ResolvedSMethodRef);
1941 if (that_param[0] == jq_Class._class) {
1942
1943 char access_flags = sm.getAccessFlags();
1944 if (classfield_index == 0) {
1945 jq_StaticField that_sf = that.getDeclaredStaticField(new jq_NameAndDesc(Utf8.get("_class"), Utf8.get("Ljoeq/Class/jq_Class;")));
1946 Assert._assert(that_sf != null);
1947 classfield_index = cp_adder.add(that_sf, CONSTANT_ResolvedSFieldRef);
1948 }
1949 uphere1:
1950 for (int j=0; ; ++j) {
1951 if (j>=static_methods.length) {
1952 StringBuffer desc = new StringBuffer("(");
1953 for (int k=1; k<that_param.length; ++k) {
1954 desc.append(that_param[k].getDesc().toString());
1955 }
1956 desc.append(")");
1957 desc.append(sm.getReturnType().getDesc().toString());
1958 Utf8 desc_utf = Utf8.get(desc.toString());
1959 jq_NameAndDesc nd = new jq_NameAndDesc(name_utf, desc_utf);
1960 jq_StaticMethod stub = generateStaticMethodStub(nd, sm, access_flags, (char)classfield_index, (char)method_idx);
1961 toadd_static.add(stub);
1962 break;
1963 }
1964 jq_StaticMethod f = this.static_methods[j];
1965 if (f.getName() == name_utf) {
1966
1967 jq_Type[] this_param = f.getParamTypes();
1968 if (this_param.length+1 != that_param.length) continue;
1969 for (int k=0; k<this_param.length; ++k) {
1970 if ((this_param[k] != that_param[k+1]) &&
1971 (that_param[k+1] != PrimordialClassLoader.getJavaLangObject())) continue uphere1;
1972 }
1973 jq_NameAndDesc nd = f.getNameAndDesc();
1974 access_flags = f.getAccessFlags();
1975 jq_StaticMethod stub = generateStaticMethodStub(nd, sm, access_flags, (char)classfield_index, (char)method_idx);
1976 if (TRACE) Debug.writeln("Replacing static method: "+stub);
1977 this.static_methods[j] = stub;
1978 break;
1979 }
1980 }
1981 } else {
1982
1983 char access_flags = (char)(sm.getAccessFlags() & ~ACC_STATIC);
1984 Assert._assert(that_param[0] == PrimordialClassLoader.getJavaLangObject() || that_param[0] == this, sm.toString());
1985 uphere2:
1986 for (int j=0; ; ++j) {
1987 if (j>=declared_instance_methods.length) {
1988 StringBuffer desc = new StringBuffer("(");
1989 for (int k=1; k<that_param.length; ++k) {
1990 desc.append(that_param[k].getDesc().toString());
1991 }
1992 desc.append(")");
1993 desc.append(sm.getReturnType().getDesc().toString());
1994 Utf8 desc_utf = Utf8.get(desc.toString());
1995 jq_NameAndDesc nd = new jq_NameAndDesc(name_utf, desc_utf);
1996 jq_InstanceMethod stub = generateInstanceMethodStub(nd, sm, access_flags, (char)method_idx);
1997 toadd_instance.add(stub);
1998 break;
1999 }
2000 jq_InstanceMethod f = this.declared_instance_methods[j];
2001 if (f.getName() == name_utf) {
2002
2003 jq_Type[] this_param = f.getParamTypes();
2004 if (this_param.length != that_param.length) continue;
2005 for (int k=0; k<this_param.length; ++k) {
2006 if ((this_param[k] != that_param[k]) &&
2007 (that_param[k] != PrimordialClassLoader.getJavaLangObject())) continue uphere2;
2008 }
2009 jq_NameAndDesc nd = f.getNameAndDesc();
2010 access_flags = f.getAccessFlags();
2011 jq_InstanceMethod stub = generateInstanceMethodStub(nd, sm, access_flags, (char)method_idx);
2012 if (TRACE) Debug.writeln("Replacing instance method: "+stub);
2013 this.declared_instance_methods[j] = stub;
2014 break;
2015 }
2016 }
2017 }
2018 }
2019 if (toadd_static.size() > 0) {
2020 jq_StaticMethod[] sms = new jq_StaticMethod[this.static_methods.length+toadd_static.size()];
2021 int i = this.static_methods.length-1;
2022 System.arraycopy(this.static_methods, 0, sms, 0, this.static_methods.length);
2023 Iterator it = toadd_static.iterator();
2024 while (it.hasNext()) {
2025 jq_StaticMethod stub = (jq_StaticMethod)it.next();
2026 if (TRACE) Debug.writeln("Adding static method stub: "+stub);
2027 sms[++i] = stub;
2028 }
2029 this.static_methods = sms;
2030 }
2031 if (toadd_instance.size() > 0) {
2032 jq_InstanceMethod[] ims = new jq_InstanceMethod[this.declared_instance_methods.length+toadd_instance.size()];
2033 int i = this.declared_instance_methods.length-1;
2034 System.arraycopy(this.declared_instance_methods, 0, ims, 0, this.declared_instance_methods.length);
2035 Iterator it = toadd_instance.iterator();
2036 while (it.hasNext()) {
2037 jq_InstanceMethod stub = (jq_InstanceMethod)it.next();
2038 if (TRACE) Debug.writeln("Adding instance method stub: "+stub);
2039 ims[++i] = stub;
2040 }
2041 this.declared_instance_methods = ims;
2042 }
2043
2044 if (that.declared_instance_fields.length > 0) {
2045 jq_InstanceField[] ifs = new jq_InstanceField[this.declared_instance_fields.length+that.declared_instance_fields.length];
2046 System.arraycopy(this.declared_instance_fields, 0, ifs, 0, this.declared_instance_fields.length);
2047 int i = this.declared_instance_fields.length-1;
2048 for (int j=0; j<that.declared_instance_fields.length; ++j) {
2049 jq_InstanceField that_f = that.declared_instance_fields[j];
2050 jq_InstanceField this_f = getOrCreateInstanceField(that_f.getNameAndDesc());
2051 Assert._assert(this_f.getState() == STATE_UNLOADED, "conflict in field names in merged class: "+this_f);
2052 this_f.load(that_f.getAccessFlags(), that_f.getAttributes());
2053 if (TRACE) Debug.writeln("Adding instance field: "+this_f);
2054 ifs[++i] = this_f;
2055 }
2056 this.declared_instance_fields = ifs;
2057 }
2058 cp_adder.finish();
2059 }
2060
2061 public void verify() {
2062 if (isVerified()) return;
2063 synchronized (this) {
2064 if (isVerified()) return;
2065 if (!isLoaded()) load();
2066 if (state == STATE_VERIFYING)
2067 throw new ClassCircularityError(this.toString());
2068 if (state == STATE_VERIFYERROR)
2069 throw new VerifyError();
2070 state = STATE_VERIFYING;
2071 try {
2072 if (TRACE) Debug.writeln("Beginning verifying "+this+"...");
2073 if (super_class != null) {
2074 super_class.verify();
2075 }
2076
2077 if (TRACE) Debug.writeln("Finished verifying "+this);
2078 state = STATE_VERIFIED;
2079 } catch (Error x) {
2080 state = STATE_VERIFYERROR;
2081 throw x;
2082 }
2083 }
2084 }
2085
2086 public void prepare() {
2087 if (isPrepared()) return;
2088 synchronized (this) {
2089 if (isPrepared()) return;
2090 if (!isVerified()) verify();
2091 if (state == STATE_PREPARING)
2092 throw new ClassCircularityError(this.toString());
2093 if (state == STATE_PREPAREERROR)
2094 throw new ClassFormatError();
2095 state = STATE_PREPARING;
2096 try {
2097 if (TRACE) Debug.writeln("Beginning preparing "+this+"...");
2098
2099
2100 if (super_class != null) {
2101 super_class.prepare();
2102 }
2103
2104 int superfields;
2105 if (super_class != null) superfields = super_class.instance_fields.length;
2106 else superfields = 0;
2107 int numOfInstanceFields = superfields + this.declared_instance_fields.length;
2108 this.instance_fields = new jq_InstanceField[numOfInstanceFields];
2109 if (superfields > 0)
2110 System.arraycopy(super_class.instance_fields, 0, this.instance_fields, 0, superfields);
2111
2112 int superreferencefields;
2113 if (super_class != null) superreferencefields = super_class.reference_offsets.length;
2114 else superreferencefields = 0;
2115 int numOfReferenceFields = superreferencefields;
2116
2117
2118 int currentInstanceField = superfields-1;
2119 int size;
2120 if (super_class != null) size = super_class.instance_size;
2121 else size = ObjectLayout.OBJ_HEADER_SIZE;
2122 if (declared_instance_fields.length > 0) {
2123 if (!dont_align) {
2124
2125 int largestDataType = declared_instance_fields[0].getSize();
2126 int align = size & largestDataType-1;
2127 if (align != 0) {
2128 if (TRACE) Debug.writeln("Gap of size "+align+" has been filled.");
2129
2130 for (int i=1; i<declared_instance_fields.length; ++i) {
2131 jq_InstanceField f = declared_instance_fields[i];
2132 int fsize = f.getSize();
2133 if (fsize <= largestDataType-align) {
2134 instance_fields[++currentInstanceField] = f;
2135 if (TRACE) Debug.writeln("Filling in field #"+currentInstanceField+" "+f+" at offset "+Strings.shex(size - ObjectLayout.OBJ_HEADER_SIZE));
2136 f.prepare(size - ObjectLayout.OBJ_HEADER_SIZE);
2137 if (f.getType().isReferenceType() && !f.getType().isAddressType())
2138 ++numOfReferenceFields;
2139 size += fsize;
2140 align += fsize;
2141 }
2142 if (align == largestDataType) {
2143 if (TRACE) Debug.writeln("Gap of size "+align+" has been filled.");
2144 break;
2145 }
2146 }
2147 }
2148 } else {
2149 if (TRACE) Debug.writeln("Skipping field alignment for class "+this);
2150 }
2151 for (int i=0; i<declared_instance_fields.length; ++i) {
2152 jq_InstanceField f = declared_instance_fields[i];
2153 if (f.getState() == STATE_LOADED) {
2154 instance_fields[++currentInstanceField] = f;
2155 if (TRACE) Debug.writeln("Laying out field #"+currentInstanceField+" "+f+" at offset "+Strings.shex(size - ObjectLayout.OBJ_HEADER_SIZE));
2156 f.prepare(size - ObjectLayout.OBJ_HEADER_SIZE);
2157 if (f.getType().isReferenceType() && !f.getType().isAddressType())
2158 ++numOfReferenceFields;
2159 size += f.getSize();
2160 }
2161 }
2162 }
2163 this.instance_size = (size+3) & ~3;
2164
2165 this.reference_offsets = new int[numOfReferenceFields];
2166 int k = -1;
2167 for (int i=0; i < instance_fields.length; ++i) {
2168 jq_InstanceField f = instance_fields[i];
2169 if (f.getType().isReferenceType() && !f.getType().isAddressType()) {
2170 reference_offsets[++k] = f.getOffset();
2171 }
2172 }
2173 Assert._assert(k+1 == this.reference_offsets.length);
2174
2175
2176 int numOfNewVirtualMethods = 0;
2177 for (int i=0; i<declared_instance_methods.length; ++i) {
2178 jq_InstanceMethod m = declared_instance_methods[i];
2179 Assert._assert(m.getState() == STATE_LOADED);
2180 if (m.isInitializer()) {
2181
2182 continue;
2183 }
2184 if (super_class != null) {
2185 jq_InstanceMethod m2 = super_class.getVirtualMethod(m.getNameAndDesc());
2186 if (m2 != null) {
2187 if (m.isPrivate() ||
2188 m2.isPrivate() || m2.isFinal()) {
2189 System.out.println("error: method "+m+" overrides method "+m2);
2190 }
2191 m2.overriddenBy(m);
2192 if (TRACE) Debug.writeln("Virtual method "+m+" overrides method "+m2+" offset "+Strings.shex(m2.getOffset()));
2193 m.prepare(m2.getOffset());
2194 continue;
2195 }
2196 }
2197 if (m.isPrivate()) {
2198
2199 continue;
2200 }
2201 ++numOfNewVirtualMethods;
2202 }
2203 int super_virtual_methods;
2204 if (super_class != null)
2205 super_virtual_methods = super_class.virtual_methods.length;
2206 else
2207 super_virtual_methods = 0;
2208 int num_virtual_methods = super_virtual_methods + numOfNewVirtualMethods;
2209 virtual_methods = new jq_InstanceMethod[num_virtual_methods];
2210 if (super_virtual_methods > 0)
2211 System.arraycopy(super_class.virtual_methods, 0, this.virtual_methods, 0, super_virtual_methods);
2212 for (int i=0, j=super_virtual_methods-1; i<declared_instance_methods.length; ++i) {
2213 jq_InstanceMethod m = declared_instance_methods[i];
2214 if (m.isInitializer() || m.isPrivate()) {
2215
2216 if (TRACE) Debug.writeln("Skipping "+m+" in virtual method table.");
2217 m.prepare();
2218 continue;
2219 }
2220 if (m.isOverriding()) {
2221 if (m.getState() != STATE_PREPARED) {
2222 Assert.UNREACHABLE("Method "+m+" overrides superclass, but is not prepared");
2223 }
2224 int entry = (m.getOffset() >> 2) - 1;
2225 virtual_methods[entry] = m;
2226 continue;
2227 }
2228 Assert._assert(m.getState() == STATE_LOADED);
2229 virtual_methods[++j] = m;
2230 if (TRACE) Debug.writeln("Virtual method "+m+" is new, offset "+Strings.shex((j+1)*CodeAddress.size()));
2231 m.prepare((j+1)*CodeAddress.size());
2232 }
2233
2234 vtable = new Address[num_virtual_methods+1];
2235
2236
2237 for (int i=0; i<declared_interfaces.length; ++i) {
2238 declared_interfaces[i].prepare();
2239 }
2240
2241
2242 int n_super_interfaces;
2243 if (super_class != null) {
2244 n_super_interfaces = super_class.interfaces.length;
2245 if (super_class.isInterface())
2246 ++n_super_interfaces;
2247 } else
2248 n_super_interfaces = 0;
2249 for (int i=0; i<declared_interfaces.length; ++i) {
2250 n_super_interfaces += declared_interfaces[i].interfaces.length;
2251 }
2252
2253 interfaces = new jq_Class[n_super_interfaces + declared_interfaces.length];
2254 int n = 0;
2255 if (n_super_interfaces > 0) {
2256 System.arraycopy(super_class.interfaces, 0, this.interfaces, 0, super_class.interfaces.length);
2257 n += super_class.interfaces.length;
2258 if (super_class.isInterface())
2259 this.interfaces[n++] = super_class;
2260 for (int i=0; i<declared_interfaces.length; ++i) {
2261 System.arraycopy(declared_interfaces[i].interfaces, 0, this.interfaces, n, declared_interfaces[i].interfaces.length);
2262 n += declared_interfaces[i].interfaces.length;
2263 }
2264 }
2265 Assert._assert (n == n_super_interfaces);
2266 System.arraycopy(declared_interfaces, 0, this.interfaces, n_super_interfaces, declared_interfaces.length);
2267
2268
2269 this.display = new jq_Type[DISPLAY_SIZE+2];
2270 if (!this.isInterface()) {
2271 jq_Reference dps = this.getDirectPrimarySupertype();
2272 if (dps != null) {
2273 Assert._assert(dps.isPrepared());
2274 int num = dps.offset;
2275 if (num < 2) num = DISPLAY_SIZE+1;
2276 System.arraycopy(dps.display, 2, this.display, 2, num-1);
2277 this.offset = num + 1;
2278 if (this.offset >= DISPLAY_SIZE+2)
2279 this.offset = 0;
2280 } else {
2281 this.offset = 2;
2282 }
2283 this.display[this.offset] = this;
2284 } else {
2285 this.display[2] = PrimordialClassLoader.getJavaLangObject();
2286 }
2287 this.s_s_array = interfaces;
2288 this.s_s_array_length = interfaces.length;
2289
2290 if (TRACE) {
2291 System.out.println(this+" offset="+this.offset);
2292 if (this.offset != 0) {
2293 for (int i=0; i<this.display.length; ++i) {
2294 System.out.println(this+" display["+i+"] = "+this.display[i]);
2295 }
2296 }
2297 for (int i=0; i<this.s_s_array_length; ++i) {
2298 System.out.println(this+" s_s_array["+i+"] = "+this.s_s_array[i]);
2299 }
2300 }
2301
2302
2303 for (int i=0; i<static_methods.length; ++i) {
2304 jq_StaticMethod m = static_methods[i];
2305 m.prepare();
2306 }
2307
2308 for (int i=0; i<static_fields.length; ++i) {
2309 jq_StaticField m = static_fields[i];
2310 m.prepare();
2311 }
2312
2313 if (TRACE) Debug.writeln("Finished preparing "+this);
2314 state = STATE_PREPARED;
2315 } catch (Error x) {
2316 state = STATE_PREPAREERROR;
2317 throw x;
2318 }
2319 }
2320 }
2321
2322 public void sf_initialize() {
2323 if (isSFInitialized()) return;
2324 synchronized (this) {
2325 if (isSFInitialized()) return;
2326 if (!isPrepared()) prepare();
2327 if (state == STATE_SFINITIALIZING)
2328 throw new ClassCircularityError(this.toString());
2329 if (state == STATE_SFINITERROR)
2330 throw new NoClassDefFoundError();
2331 state = STATE_SFINITIALIZING;
2332 try {
2333 if (TRACE) Debug.writeln("Beginning SF init "+this+"...");
2334 if (super_class != null) {
2335 super_class.sf_initialize();
2336 }
2337
2338 if (static_data_size > 0) {
2339 static_data = new int[static_data_size>>2];
2340 for (int i=0, j=0; i<static_fields.length; ++i) {
2341 jq_StaticField f = static_fields[i];
2342 f.sf_initialize(static_data, j << 2);
2343 if (f.isConstant()) {
2344 Object cv = f.getConstantValue();
2345 if (f.getType().isPrimitiveType()) {
2346 if (f.getType() == jq_Primitive.LONG) {
2347 long l = ((Long)cv).longValue();
2348 static_data[j ] = (int)l;
2349 static_data[j+1] = (int)(l >> 32);
2350 } else if (f.getType() == jq_Primitive.FLOAT) {
2351 static_data[j] = Float.floatToRawIntBits(((Float)cv).floatValue());
2352 } else if (f.getType() == jq_Primitive.DOUBLE) {
2353 long l = Double.doubleToRawLongBits(((Double)cv).doubleValue());
2354 static_data[j ] = (int)l;
2355 static_data[j+1] = (int)(l >> 32);
2356 } else {
2357 static_data[j] = ((Integer)cv).intValue();
2358 }
2359 } else {
2360
2361 HeapAddress a = HeapAddress.addressOf(cv);
2362 if (a != null) {
2363 static_data[j] = a.to32BitValue();
2364 }
2365 }
2366 }
2367 j += f.getWidth() >> 2;
2368 }
2369 }
2370 if (TRACE) Debug.writeln("Finished SF init "+this);
2371 state = STATE_SFINITIALIZED;
2372 } catch (Error x) {
2373 state = STATE_SFINITERROR;
2374 throw x;
2375 }
2376 }
2377 }
2378
2379 public void compile() {
2380 if (isCompiled()) return;
2381 synchronized (this) {
2382 if (isCompiled()) return;
2383 if (!isSFInitialized()) sf_initialize();
2384 state = STATE_COMPILING;
2385 if (TRACE) Debug.writeln("Beginning compilation "+this+"...");
2386 if (super_class != null) {
2387 super_class.compile();
2388 }
2389
2390 for (int i=0; i<static_methods.length; ++i) {
2391 jq_StaticMethod m = static_methods[i];
2392 if (m.getState() == STATE_PREPARED) {
2393 if (TRACE) Debug.writeln("Compiling stub for: "+m);
2394 jq_CompiledCode cc = m.compile_stub();
2395 if (jq.RunningNative) cc.patchDirectBindCalls();
2396 }
2397 }
2398 for (int i=0; i<declared_instance_methods.length; ++i) {
2399 jq_InstanceMethod m = declared_instance_methods[i];
2400 if (m.getState() == STATE_PREPARED) {
2401 if (TRACE) Debug.writeln("Compiling stub for: "+m);
2402 jq_CompiledCode cc = m.compile_stub();
2403 if (jq.RunningNative) cc.patchDirectBindCalls();
2404 }
2405 }
2406 Address[] vt = (Address[])vtable;
2407
2408 vt[0] = HeapAddress.addressOf(this);
2409 for (int i=0; i<virtual_methods.length; ++i) {
2410 vt[i+1] = virtual_methods[i].getDefaultCompiledVersion().getEntrypoint();
2411 }
2412 if (TRACE) Debug.writeln(this+": "+vt[0].stringRep()+" vtable "+HeapAddress.addressOf(vt).stringRep());
2413 if (TRACE) Debug.writeln("Finished compilation "+this);
2414 state = STATE_COMPILED;
2415 }
2416 }
2417
2418 public void cls_initialize() throws ExceptionInInitializerError, NoClassDefFoundError {
2419 if (isClsInitialized()) return;
2420 synchronized (this) {
2421 if (state == STATE_CLSINITERROR) throw new NoClassDefFoundError(this+": clinit failed");
2422 if (state >= STATE_CLSINITIALIZING) return;
2423 if (!isCompiled()) compile();
2424 state = STATE_CLSINITIALIZING;
2425 if (TRACE) Debug.writeln("Beginning class init "+this+"...");
2426 if (super_class != null) {
2427 super_class.cls_initialize();
2428 }
2429 state = STATE_CLSINITRUNNING;
2430 if (jq.RunningNative)
2431 invokeclinit();
2432 if (TRACE) Debug.writeln("Finished class init "+this);
2433 state = STATE_CLSINITIALIZED;
2434 }
2435 }
2436
2437 private void invokeclinit() throws ExceptionInInitializerError {
2438 try {
2439 state = STATE_CLSINITRUNNING;
2440 jq_ClassInitializer clinit = this.getClassInitializer();
2441 if (clinit != null)
2442 Reflection.invokestatic_V(clinit);
2443 } catch (Error x) {
2444 state = STATE_CLSINITERROR;
2445 throw x;
2446 } catch (Throwable x) {
2447 state = STATE_CLSINITERROR;
2448 throw new ExceptionInInitializerError(x);
2449 }
2450 }
2451
2452 public static int NumOfIFieldsKept = 0;
2453 public static int NumOfSFieldsKept = 0;
2454 public static int NumOfIMethodsKept = 0;
2455 public static int NumOfSMethodsKept = 0;
2456 public static int NumOfIFieldsEliminated = 0;
2457 public static int NumOfSFieldsEliminated = 0;
2458 public static int NumOfIMethodsEliminated = 0;
2459 public static int NumOfSMethodsEliminated = 0;
2460
2461 void readAttributes(DataInput in, Map attribMap)
2462 throws IOException {
2463 char n_attributes = (char)in.readUnsignedShort();
2464 for (int i=0; i<n_attributes; ++i) {
2465 char attribute_name_index = (char)in.readUnsignedShort();
2466 if (getCPtag(attribute_name_index) != CONSTANT_Utf8)
2467 throw new ClassFormatError("constant pool entry "+attribute_name_index+", referred to by attribute "+i+
2468 ", is wrong type tag (expected="+CONSTANT_Utf8+", actual="+getCPtag(attribute_name_index));
2469 Utf8 attribute_desc = getCPasUtf8(attribute_name_index);
2470 int attribute_length = in.readInt();
2471
2472 byte[] attribute_data = new byte[attribute_length];
2473 in.readFully(attribute_data);
2474 attribMap.put(attribute_desc, attribute_data);
2475 }
2476 }
2477
2478 public static String className(Utf8 desc) {
2479 String temp = desc.toString();
2480 Assert._assert(temp.startsWith("L"), temp);
2481 Assert._assert(temp.endsWith(";"), temp);
2482 return temp.substring(1, temp.length()-1).replace('/','.');
2483 }
2484
2485 private void addSubclass(jq_Class subclass) {
2486 jq_Class[] newsubclasses = new jq_Class[subclasses.length+1];
2487 System.arraycopy(subclasses, 0, newsubclasses, 0, subclasses.length);
2488 newsubclasses[subclasses.length] = subclass;
2489 subclasses = newsubclasses;
2490 }
2491
2492 private void addSubinterface(jq_Class subinterface) {
2493 jq_Class[] newsubinterfaces = new jq_Class[subinterfaces.length+1];
2494 System.arraycopy(subinterfaces, 0, newsubinterfaces, 0, subinterfaces.length);
2495 newsubinterfaces[subinterfaces.length] = subinterface;
2496 subinterfaces = newsubinterfaces;
2497 }
2498
2499 private void removeSubclass(jq_Class subclass) {
2500 jq_Class[] newsubclasses = new jq_Class[subclasses.length-1];
2501 for (int i=-1, j=0; i<newsubclasses.length-1; ++j) {
2502 if (subclass != subclasses[j]) {
2503 newsubclasses[++i] = subclasses[j];
2504 }
2505 }
2506 subclasses = newsubclasses;
2507 }
2508
2509 private void removeSubinterface(jq_Class subinterface) {
2510 jq_Class[] newsubinterfaces = new jq_Class[subinterfaces.length-1];
2511 for (int i=-1, j=0; i<newsubinterfaces.length-1; ++j) {
2512 if (subinterface != subinterfaces[j]) {
2513 newsubinterfaces[++i] = subinterfaces[j];
2514 }
2515 }
2516 subinterfaces = newsubinterfaces;
2517 }
2518
2519 public static jq_InstanceMethod getInvokespecialTarget(jq_Class clazz, jq_InstanceMethod method)
2520 throws AbstractMethodError {
2521 clazz.load();
2522 if (!clazz.isSpecial())
2523 return method;
2524 if (method.isInitializer())
2525 return method;
2526 if (TypeCheck.isSuperclassOf(method.getDeclaringClass(), clazz, true) != YES)
2527 return method;
2528 jq_NameAndDesc nd = method.getNameAndDesc();
2529 for (;;) {
2530 clazz = clazz.getSuperclass();
2531 if (clazz == null)
2532 throw new AbstractMethodError();
2533 clazz.load();
2534 method = clazz.getDeclaredInstanceMethod(nd);
2535 if (method != null)
2536 return method;
2537 }
2538 }
2539
2540 public jq_ConstantPool.ConstantPoolRebuilder rebuildConstantPool(boolean addCode) {
2541 jq_ConstantPool.ConstantPoolRebuilder cpr = new jq_ConstantPool.ConstantPoolRebuilder();
2542 cpr.addType(this);
2543 if (this.getSuperclass() != null)
2544 cpr.addType(this.getSuperclass());
2545 for (int i=0; i < declared_interfaces.length; ++i) {
2546 jq_Class f = declared_interfaces[i];
2547 cpr.addType(f);
2548 }
2549 for (int i=0; i < declared_instance_fields.length; ++i) {
2550 jq_InstanceField f = declared_instance_fields[i];
2551 cpr.addUtf8(f.getName());
2552 cpr.addUtf8(f.getDesc());
2553 cpr.addAttributeNames(f);
2554 }
2555 for (int i=0; i < static_fields.length; ++i) {
2556 jq_StaticField f = static_fields[i];
2557 cpr.addUtf8(f.getName());
2558 cpr.addUtf8(f.getDesc());
2559 cpr.addAttributeNames(f);
2560 if (f.isConstant()) {
2561 Object o = f.getConstantValue();
2562 if (o instanceof String)
2563 cpr.addString((String) f.getConstantValue());
2564 else if (o instanceof Class)
2565 cpr.addType(Reflection.getJQType((Class)o));
2566 else
2567 cpr.addOther(f.getConstantValue());
2568 }
2569 }
2570 for (int i=0; i < declared_instance_methods.length; ++i) {
2571 jq_InstanceMethod f = declared_instance_methods[i];
2572 cpr.addUtf8(f.getName());
2573 cpr.addUtf8(f.getDesc());
2574 cpr.addAttributeNames(f);
2575 if (addCode) cpr.addCode(f);
2576 cpr.addExceptions(f);
2577 }
2578 for (int i=0; i < static_methods.length; ++i) {
2579 jq_StaticMethod f = static_methods[i];
2580 cpr.addUtf8(f.getName());
2581 cpr.addUtf8(f.getDesc());
2582 cpr.addAttributeNames(f);
2583 if (addCode) cpr.addCode(f);
2584 cpr.addExceptions(f);
2585 }
2586 Utf8 sourcefile = getSourceFile();
2587 if (sourcefile != null) {
2588 cpr.addUtf8(sourcefile);
2589 }
2590
2591 for (Iterator i = attributes.entrySet().iterator(); i.hasNext(); ) {
2592 Map.Entry e = (Map.Entry)i.next();
2593 Utf8 name = (Utf8)e.getKey();
2594 cpr.addUtf8(name);
2595 }
2596
2597 return cpr;
2598 }
2599
2600 public void dump(DataOutput out) throws IOException {
2601 chkState(STATE_LOADED);
2602 out.writeInt(0xcafebabe);
2603 out.writeChar(minor_version);
2604 out.writeChar(major_version);
2605
2606 jq_ConstantPool.ConstantPoolRebuilder cpr = rebuildConstantPool(true);
2607 cpr.dump(out);
2608
2609 out.writeChar(access_flags);
2610 out.writeChar(cpr.get(this));
2611 char sc;
2612 if (super_class == null) sc = 0;
2613 else sc = cpr.get(super_class);
2614 out.writeChar(sc);
2615
2616 out.writeChar(declared_interfaces.length);
2617 for(int i=0; i < declared_interfaces.length; i++)
2618 out.writeChar(cpr.get(declared_interfaces[i]));
2619
2620 int nfields = static_fields.length + declared_instance_fields.length;
2621 Assert._assert(nfields <= Character.MAX_VALUE);
2622 out.writeChar(nfields);
2623 for(int i=0; i < static_fields.length; i++) {
2624 static_fields[i].dump(out, cpr);
2625 }
2626 for(int i=0; i < declared_instance_fields.length; i++) {
2627 declared_instance_fields[i].dump(out, cpr);
2628 }
2629
2630 int nmethods = static_methods.length + declared_instance_methods.length;
2631 out.writeChar(nmethods);
2632 for(int i=0; i < static_methods.length; i++) {
2633 static_methods[i].dump(out, cpr);
2634 }
2635 for(int i=0; i < declared_instance_methods.length; i++) {
2636 declared_instance_methods[i].dump(out, cpr);
2637 }
2638
2639 int nattributes = attributes.size();
2640 Assert._assert(nattributes <= Character.MAX_VALUE);
2641 out.writeChar(nattributes);
2642 for (Iterator i = attributes.entrySet().iterator(); i.hasNext(); ) {
2643 Map.Entry e = (Map.Entry)i.next();
2644 Utf8 name = (Utf8)e.getKey();
2645 out.writeChar(cpr.get(name));
2646 byte[] value = (byte[])e.getValue();
2647 if (name == Utf8.get("SourceFile")) {
2648 char oldIndex = Convert.twoBytesToChar(value, 0);
2649 Utf8 oldValue = (Utf8)const_pool.get(oldIndex);
2650 Convert.charToTwoBytes(cpr.get(oldValue), value, 0);
2651 } else if (name == Utf8.get("InnerClasses")) {
2652
2653 }
2654 out.writeInt(value.length);
2655 out.write(value);
2656 }
2657 }
2658
2659 public static final jq_Class _class = (jq_Class)PrimordialClassLoader.loader.getOrCreateBSType("Ljoeq/Class/jq_Class;");
2660
2661 static interface Delegate {
2662 Object newInstance(jq_Class c, int instance_size, Object vtable);
2663 }
2664
2665 private static Delegate _delegate;
2666
2667 static {
2668
2669 _delegate = null;
2670 boolean nullVM = jq.nullVM;
2671 if (!nullVM) {
2672 _delegate = attemptDelegate("joeq.Class.Delegates$Klass");
2673 }
2674 if (_delegate == null) {
2675 _delegate = new NullDelegates.Klass();
2676 }
2677 }
2678
2679 private static Delegate attemptDelegate(String s) {
2680
2681 try {
2682 Class c = Class.forName(s);
2683 return (Delegate)c.newInstance();
2684 } catch (java.lang.ClassNotFoundException x) {
2685
2686 } catch (java.lang.InstantiationException x) {
2687
2688 } catch (java.lang.IllegalAccessException x) {
2689
2690 }
2691 return null;
2692 }
2693
2694 static final HashMap
2695 public StringConstant findStringConstant(String s) {
2696 StringConstant sc = (StringConstant)stringConstants.get(s);
2697 if (sc == null) {
2698 char idx = getCP().findEqual(s, CONSTANT_String);
2699 if (idx != 0)
2700 stringConstants.put(s, sc = new StringConstant(idx));
2701 }
2702 return sc;
2703 }
2704 public static StringConstant readStringConstant(StringTokenizer st) {
2705 jq_Class clazz = (jq_Class)jq_Type.read(st);
2706 char cpindex = (char)Integer.parseInt(st.nextToken());
2707 clazz.load();
2708 return clazz.findStringConstant(clazz.getCPasString(cpindex));
2709 }
2710
2711 public class StringConstant {
2712 char cpindex;
2713 StringConstant(char cpindex) {
2714 this.cpindex = cpindex;
2715 }
2716 public void write(Textualizer t) throws IOException {
2717 jq_Class.this.write(t);
2718 t.writeString(" "+(int)cpindex);
2719 }
2720 public String getString() {
2721 load();
2722 return getCPasString(cpindex);
2723 }
2724 public String toString() {
2725 return "StringConstant[class="+jq_Class.this+",idx="+(int)cpindex+"]";
2726 }
2727 }
2728 }