View Javadoc

1   // BootstrapRootSet.java, created Wed Jun 26 12:27:23 2002 by joewhaley
2   // Copyright (C) 2001-3 John Whaley <jwhaley@alum.mit.edu>
3   // Licensed under the terms of the GNU LGPL; see COPYING for details.
4   package joeq.Bootstrap;
5   
6   import java.util.HashSet;
7   import java.util.Iterator;
8   import java.util.LinkedHashSet;
9   import java.util.LinkedList;
10  import java.util.List;
11  import java.util.Set;
12  import joeq.Class.PrimordialClassLoader;
13  import joeq.Class.jq_Array;
14  import joeq.Class.jq_Class;
15  import joeq.Class.jq_ClassInitializer;
16  import joeq.Class.jq_Field;
17  import joeq.Class.jq_FieldVisitor;
18  import joeq.Class.jq_Initializer;
19  import joeq.Class.jq_InstanceField;
20  import joeq.Class.jq_InstanceMethod;
21  import joeq.Class.jq_Member;
22  import joeq.Class.jq_Method;
23  import joeq.Class.jq_MethodVisitor;
24  import joeq.Class.jq_Primitive;
25  import joeq.Class.jq_Reference;
26  import joeq.Class.jq_StaticField;
27  import joeq.Class.jq_StaticMethod;
28  import joeq.Class.jq_Type;
29  import joeq.Class.jq_TypeVisitor;
30  import joeq.Memory.CodeAddress;
31  import joeq.Memory.HeapAddress;
32  import joeq.Memory.StackAddress;
33  import joeq.Runtime.ExceptionDeliverer;
34  import joeq.Runtime.Reflection;
35  import joeq.Runtime.SystemInterface;
36  import joeq.Runtime.Unsafe;
37  import jwutil.collections.IdentityHashCodeWrapper;
38  import jwutil.util.Assert;
39  
40  /***
41   * BootstrapRootSet
42   *
43   * @author  John Whaley <jwhaley@alum.mit.edu>
44   * @version $Id: BootstrapRootSet.java 1941 2004-09-30 03:37:06Z joewhaley $
45   */
46  public class BootstrapRootSet {
47  
48      public static /*final*/ boolean TRACE = false;
49      public static final java.io.PrintStream out = System.out;
50      
51      protected final Set/*jq_Type*/ instantiatedTypes;
52      protected final Set/*jq_Type*/ necessaryTypes;
53      protected final Set/*jq_Field*/ necessaryFields;
54      protected final Set/*jq_Method*/ necessaryMethods;
55      
56      protected final LinkedHashSet/*Object*/ visitedObjects;
57      
58      protected List/*jq_TypeVisitor*/ instantiatedTypesListeners;
59      protected List/*jq_TypeVisitor*/ necessaryTypesListeners;
60      protected List/*jq_FieldVisitor*/ necessaryFieldsListeners;
61      protected List/*jq_MethodVisitor*/ necessaryMethodsListeners;
62      
63      public boolean AddAllFields;
64      
65      /*** Creates new BootstrapRootSet */
66      public BootstrapRootSet(boolean addall) {
67          this.instantiatedTypes = new HashSet();
68          this.necessaryTypes = new HashSet();
69          this.necessaryFields = new HashSet();
70          this.necessaryMethods = new HashSet();
71          this.visitedObjects = new LinkedHashSet();
72          this.AddAllFields = addall;
73      }
74      
75      public Set/*jq_Type*/ getInstantiatedTypes() { return instantiatedTypes; }
76      public Set/*jq_Type*/ getNecessaryTypes() { return necessaryTypes; }
77      public Set/*jq_Field*/ getNecessaryFields() { return necessaryFields; }
78      public Set/*jq_Method*/ getNecessaryMethods() { return necessaryMethods; }
79      
80      public void registerInstantiatedTypeListener(jq_TypeVisitor tv) {
81          if (instantiatedTypesListeners == null)
82              instantiatedTypesListeners = new LinkedList();
83          instantiatedTypesListeners.add(tv);
84      }
85      public void unregisterInstantiatedTypeListener(jq_TypeVisitor tv) {
86          instantiatedTypesListeners.remove(tv);
87      }
88      public void registerNecessaryTypeListener(jq_TypeVisitor tv) {
89          if (necessaryTypesListeners == null)
90              necessaryTypesListeners = new LinkedList();
91          necessaryTypesListeners.add(tv);
92      }
93      public void unregisterNecessaryTypeListener(jq_TypeVisitor tv) {
94          necessaryTypesListeners.remove(tv);
95      }
96      public void registerNecessaryFieldListener(jq_FieldVisitor tv) {
97          if (necessaryFieldsListeners == null)
98              necessaryFieldsListeners = new LinkedList();
99          necessaryFieldsListeners.add(tv);
100     }
101     public void unregisterNecessaryFieldListener(jq_FieldVisitor tv) {
102         necessaryFieldsListeners.remove(tv);
103     }
104     public void registerNecessaryMethodListener(jq_MethodVisitor tv) {
105         if (necessaryMethodsListeners == null)
106             necessaryMethodsListeners = new LinkedList();
107         necessaryMethodsListeners.add(tv);
108     }
109     public void unregisterNecessaryMethodListener(jq_MethodVisitor tv) {
110         necessaryMethodsListeners.remove(tv);
111     }
112     
113     public boolean addInstantiatedType(jq_Type t) {
114         Assert._assert(t != null);
115         addNecessaryType(t);
116         boolean b = instantiatedTypes.add(t);
117         if (b) {
118             if (TRACE) out.println("New instantiated type: "+t);
119             if (instantiatedTypesListeners != null) {
120                 for (Iterator i=instantiatedTypesListeners.iterator(); i.hasNext(); ) {
121                     jq_TypeVisitor tv = (jq_TypeVisitor)i.next();
122                     t.accept(tv);
123                 }
124             }
125         }
126         return b;
127     }
128     
129     public jq_Type addNecessaryType(String desc) {
130         String className = desc.substring(1, desc.length()-1).replace('/', '.');
131         try {
132             // attempt to load class in host VM first.
133             Class.forName(className);
134             jq_Type t = null;
135             try {
136                 t = PrimordialClassLoader.loader.getOrCreateBSType(desc);
137                 t.load();
138                 addNecessaryType(t);
139                 return t;
140             } catch (NoClassDefFoundError x) {
141                 System.out.println("Note: Cannot load class "+t+" present in host Jvm");
142                 PrimordialClassLoader.unloadType(PrimordialClassLoader.loader, t);
143             }
144         } catch (ClassNotFoundException x) { }
145         return null;
146     }
147         
148     public boolean addNecessaryType(jq_Type t) {
149         if (t == null) return false;
150         t.prepare();
151         boolean b = necessaryTypes.add(t);
152         if (b) {
153             if (TRACE) out.println("New necessary type: "+t);
154             if (necessaryTypesListeners != null) {
155                 for (Iterator i=necessaryTypesListeners.iterator(); i.hasNext(); ) {
156                     jq_TypeVisitor tv = (jq_TypeVisitor)i.next();
157                     t.accept(tv);
158                 }
159             }
160             if (t instanceof jq_Class) {
161                 jq_Class klass = (jq_Class)t;
162                 if (AddAllFields) {
163                     jq_StaticField[] sfs = klass.getDeclaredStaticFields();
164                     for (int i=0; i<sfs.length; ++i) {
165                         addNecessaryField(sfs[i]);
166                     }
167                 }
168                 // add superclass as necessary, as well.
169                 addNecessaryType(klass.getSuperclass());
170             }
171         }
172         return b;
173     }
174     
175     public jq_StaticField addNecessaryStaticField(jq_Class c, String name, String desc) {
176         if (c == null) return null;
177         jq_StaticField f = c.getOrCreateStaticField(name, desc);
178         addNecessaryField(f);
179         return f;
180     }
181     
182     public jq_InstanceField addNecessaryInstanceField(jq_Class c, String name, String desc) {
183         if (c == null) return null;
184         jq_InstanceField f = c.getOrCreateInstanceField(name, desc);
185         addNecessaryField(f);
186         return f;
187     }
188         
189     public boolean addNecessaryField(jq_Field t) {
190         addNecessaryType(t.getDeclaringClass());
191         boolean b = necessaryFields.add(t);
192         if (b) {
193             if (TRACE) out.println("New necessary field: "+t);
194             if (necessaryFieldsListeners != null) {
195                 for (Iterator i=necessaryFieldsListeners.iterator(); i.hasNext(); ) {
196                     jq_FieldVisitor tv = (jq_FieldVisitor)i.next();
197                     t.accept(tv);
198                 }
199             }
200         }
201         return b;
202     }
203     
204     public jq_StaticMethod addNecessaryStaticMethod(jq_Class c, String name, String desc) {
205         if (c == null) return null;
206         jq_StaticMethod f = c.getOrCreateStaticMethod(name, desc);
207         addNecessaryMethod(f);
208         return f;
209     }
210     
211     public jq_InstanceMethod addNecessaryInstanceMethod(jq_Class c, String name, String desc) {
212         if (c == null) return null;
213         jq_InstanceMethod f = c.getOrCreateInstanceMethod(name, desc);
214         addNecessaryMethod(f);
215         return f;
216     }
217         
218     public boolean addNecessaryMethod(jq_Method t) {
219         addNecessaryType(t.getDeclaringClass());
220         boolean b = necessaryMethods.add(t);
221         if (b) {
222             if (TRACE) out.println("New necessary method: "+t);
223             if (necessaryMethodsListeners != null) {
224                 for (Iterator i=necessaryMethodsListeners.iterator(); i.hasNext(); ) {
225                     jq_MethodVisitor tv = (jq_MethodVisitor)i.next();
226                     t.accept(tv);
227                 }
228             }
229         }
230         return b;
231     }
232     
233     public void addDefaultRoots() {
234         jq_Class c;
235         jq_StaticMethod s_m; jq_InstanceMethod i_m;
236         
237         // some internal vm data structures are necessary for correct execution
238         // under just about any circumstances.
239         addNecessaryType(jq_Class._class);
240         addNecessaryType(jq_Primitive._class);
241         addNecessaryType(jq_Array._class);
242         addNecessaryType(jq_InstanceField._class);
243         addNecessaryType(jq_StaticField._class);
244         addNecessaryType(jq_InstanceMethod._class);
245         addNecessaryType(jq_StaticMethod._class);
246         addNecessaryType(jq_Initializer._class);
247         addNecessaryType(jq_ClassInitializer._class);
248         addNecessaryType(CodeAddress._class);
249         addNecessaryType(HeapAddress._class);
250         addNecessaryType(StackAddress._class);
251         addNecessaryField(jq_Reference._vtable);
252         
253         // the bootstrap loader uses the static fields in the SystemInterface class.
254         SystemInterface._class.load();
255         jq_StaticField[] sfs = SystemInterface._class.getDeclaredStaticFields();
256         for (int i=0; i<sfs.length; ++i) {
257             addNecessaryField(sfs[i]);
258         }
259         // even if there are no calls to these Unsafe methods, we need their definitions
260         // to stick around so that we can check against them.
261         Unsafe._class.load();
262         jq_StaticMethod[] sms = Unsafe._class.getDeclaredStaticMethods();
263         for (int i=0; i<sms.length; ++i) {
264             if (sms[i] instanceof jq_ClassInitializer) continue;
265             addNecessaryMethod(sms[i]);
266         }
267         //addNecessaryField(Unsafe._remapper_object);
268 
269         // We need to be able to allocate objects and code.
270         addNecessaryType(joeq.Allocator.SimpleAllocator._class);
271         addNecessaryType(PrimordialClassLoader.loader.getOrCreateBSType("Ljoeq/Allocator/RuntimeCodeAllocator;"));
272         
273         // setIn0, setOut0, and setErr0 use these fields, but the trimmer doesn't detect the uses.
274         c = PrimordialClassLoader.getJavaLangSystem();
275         addNecessaryStaticField(c, "in", "Ljava/io/InputStream;");
276         addNecessaryStaticField(c, "out", "Ljava/io/PrintStream;");
277         addNecessaryStaticField(c, "err", "Ljava/io/PrintStream;");
278         
279         // private method initializeSystemClass is called reflectively
280         addNecessaryStaticMethod(c, "initializeSystemClass", "()V");
281         
282         // an instance of this class is created via reflection during VM initialization.
283         c = (jq_Class)Reflection.getJQType(sun.io.CharToByteConverter.getDefault().getClass());
284         addNecessaryInstanceMethod(c, "<init>", "()V");
285         
286         // an instance of this class is created via reflection during VM initialization.
287         c = (jq_Class)Reflection.getJQType(sun.io.ByteToCharConverter.getDefault().getClass());
288         addNecessaryInstanceMethod(c, "<init>", "()V");
289         
290         // the trap handler can be implicitly called from any bytecode than can trigger a hardware exception.
291         s_m = ExceptionDeliverer._trap_handler;
292         addNecessaryMethod(s_m);
293         
294         // we want the compiler to be able to run at run time, too.
295         i_m = jq_Method._compile;
296         addNecessaryMethod(i_m);
297         
298         // debugger is large, so compile it on demand.
299         if (false) {
300             s_m = ExceptionDeliverer._debug_trap_handler;
301             addNecessaryMethod(s_m);
302         }
303         
304         // entrypoint for new threads
305         addNecessaryMethod(joeq.Scheduler.jq_NativeThread._nativeThreadEntry);
306         // thread switch interrupt
307         addNecessaryMethod(joeq.Scheduler.jq_NativeThread._threadSwitch);
308         // ctrl-break handler
309         addNecessaryMethod(joeq.Scheduler.jq_NativeThread._ctrl_break_handler);
310         // entrypoint for interrupter thread
311         addNecessaryMethod(joeq.Scheduler.jq_InterrupterThread._run);
312         
313         // dunno why this doesn't show up
314         addNecessaryType(joeq.Assembler.Heap2HeapReference._class);
315         
316         try {
317             // an instance of this class is created via reflection during VM initialization.
318             c = (jq_Class)Reflection.getJQType(sun.io.ByteToCharConverter.getConverter("ISO-8859-1").getClass());
319             addNecessaryInstanceMethod(c, "<init>", "()V");
320             // an instance of this class is created via reflection during VM initialization.
321             c = (jq_Class)Reflection.getJQType(sun.io.CharToByteConverter.getConverter("ISO-8859-1").getClass());
322             addNecessaryInstanceMethod(c, "<init>", "()V");
323         } catch (java.io.UnsupportedEncodingException x) { }
324 
325         // JDK1.4: an instance of this class is created via reflection during VM initialization.
326         c = (jq_Class) addNecessaryType("Lsun/nio/cs/ISO_8859_1;");
327         addNecessaryInstanceMethod(c, "<init>", "()V");
328         
329         addNecessaryType("Lsun/nio/cs/ISO_8859_1$Encoder;");
330         addNecessaryType("Lsun/nio/cs/ISO_8859_1$Decoder;");
331         addNecessaryType("Lsun/nio/cs/ISO_8859_1$1;");
332         
333         // for JDK1.4.2
334         addNecessaryType("Lsun/net/www/protocol/jar/Handler;");
335         addNecessaryType("Ljava/util/logging/LogManager$Cleaner;");
336         
337         // tracing in the compiler uses these
338         //c = jq._class; c.prepare();
339         //addToWorklist(jq._hex8);
340         //addToWorklist(jq._hex16);
341     }
342     
343     public boolean addObjectAndSubfields(Object o) {
344         return addObjectAndSubfields(o, visitedObjects);
345     }
346     private boolean addObjectAndSubfields(Object o, LinkedHashSet objs) {
347         if (o == null) return false;
348         IdentityHashCodeWrapper a = IdentityHashCodeWrapper.create(o);
349         if (visitedObjects.contains(a) || objs.contains(a))
350             return false;
351         objs.add(a);
352         Class objType = o.getClass();
353         jq_Reference jqType = (jq_Reference)Reflection.getJQType(objType);
354         if (TRACE) out.println("Adding object of type "+jqType+": "+o);
355         addInstantiatedType(jqType);
356         /*
357                 addClassInitializer((jq_Class)jqType);
358                 addSuperclassVirtualMethods((jq_Class)jqType);
359                 addClassInterfaceImplementations((jq_Class)jqType);
360          */
361         if (jqType.isArrayType()) {
362             jq_Type elemType = ((jq_Array)jqType).getElementType();
363             if (elemType.isAddressType()) {
364                 // no need to visit.
365             } else if (elemType.isReferenceType()) {
366                 int length = java.lang.reflect.Array.getLength(o);
367                 Object[] v = (Object[])o;
368                 if (TRACE) out.println("Visiting "+jqType+" of "+length+" elements");
369                 for (int k=0; k<length; ++k) {
370                     Object o2 = Reflection.arrayload_A(v, k);
371                     addObjectAndSubfields(o2, objs);
372                 }
373             }
374         } else {
375             Assert._assert(jqType.isClassType());
376             jq_Class clazz = (jq_Class)jqType;
377             jq_InstanceField[] fields = clazz.getInstanceFields();
378             for (int k=0; k<fields.length; ++k) {
379                 jq_InstanceField f = fields[k];
380                 if (!AddAllFields && !necessaryFields.contains(f))
381                     continue;
382                 jq_Type ftype = f.getType();
383                 if (ftype.isAddressType()) {
384                     // no need to visit.
385                 } else if (ftype.isReferenceType()) {
386                     if (TRACE) out.println("Visiting field "+f);
387                     Object o2 = Reflection.getfield_A(o, f);
388                     addObjectAndSubfields(o2, objs);
389                 }
390             }
391         }
392         return true;
393     }
394     
395     public void addNecessarySubfieldsOfVisitedObjects() {
396         if (AddAllFields) return;
397         LinkedHashSet objs = visitedObjects;
398         for (;;) {
399             LinkedHashSet objs2 = new LinkedHashSet();
400             boolean change = false;
401             for (Iterator i = objs.iterator(); i.hasNext(); ) {
402                 Object o = ((IdentityHashCodeWrapper)i.next()).getObject();
403                 Class objType = o.getClass();
404                 jq_Reference jqType = (jq_Reference)Reflection.getJQType(objType);
405                 if (jqType.isArrayType()) continue;
406                 Assert._assert(jqType.isClassType());
407                 jq_Class clazz = (jq_Class)jqType;
408                 jq_InstanceField[] fields = clazz.getInstanceFields();
409                 for (int k=0; k<fields.length; ++k) {
410                     jq_InstanceField f = fields[k];
411                     if (!necessaryFields.contains(f))
412                         continue;
413                     jq_Type ftype = f.getType();
414                     if (ftype.isAddressType()) {
415                         // no need to visit.
416                     } else if (ftype.isReferenceType()) {
417                         if (TRACE) out.println("Visiting field "+f+" of object of type "+clazz);
418                         Object o2 = Reflection.getfield_A(o, f);
419                         if (addObjectAndSubfields(o2, objs2))
420                             change = true;
421                     }
422                 }
423             }
424             if (!change) break;
425             if (TRACE) out.println("Objects added: "+objs2.size()+", iterating over those objects.");
426             visitedObjects.addAll(objs2);
427             objs = objs2;
428         }
429     }
430     
431     public void addAllInterfaceMethodImplementations(jq_InstanceMethod i_m) {
432         addNecessaryMethod(i_m);
433         jq_Class interf = i_m.getDeclaringClass();
434         Assert._assert(interf.isInterface());
435         Iterator i = necessaryTypes.iterator();
436         while (i.hasNext()) {
437             jq_Type t = (jq_Type)i.next();
438             if (!t.isReferenceType()) continue;
439             if (t.isAddressType()) continue;
440             jq_Reference r = (jq_Reference)t;
441             if (!r.implementsInterface(interf)) continue;
442             jq_InstanceMethod m2 = r.getVirtualMethod(i_m.getNameAndDesc());
443             if (m2 == null) {
444                 // error:
445                 if (TRACE) out.println("Error: class "+r+" does not implement interface method "+i_m);
446                 continue;
447             }
448             addNecessaryMethod(m2);
449         }
450     }
451     
452     public void addAllVirtualMethodImplementations(jq_InstanceMethod i_m) {
453         addNecessaryMethod(i_m);
454         addAllVirtualMethodImplementations(i_m.getDeclaringClass(), i_m);
455     }
456     
457     public void addAllVirtualMethodImplementations(jq_Class c, jq_InstanceMethod i_m) {
458         if (!i_m.isOverridden())
459             return;
460         jq_Class[] subclasses = c.getSubClasses();
461         for (int i=0; i<subclasses.length; ++i) {
462             jq_Class subclass = subclasses[i];
463             subclass.prepare();
464             jq_Method m2 = (jq_Method)subclass.getDeclaredMember(i_m.getNameAndDesc());
465             if (m2 != null && !m2.isStatic()) {
466                 addNecessaryMethod(m2);
467             }
468             addAllVirtualMethodImplementations(subclass, i_m);
469         }
470     }
471 
472     // not thread safe.
473     public void trimClass(jq_Class clazz) {
474         Assert._assert(clazz.isPrepared());
475 
476         jq_Class super_class = clazz.getSuperclass();
477         if (super_class != null)
478             trimClass(super_class);
479 
480         //Set instantiatedTypes = getInstantiatedTypes();
481         Set necessaryFields = getNecessaryFields();
482         Set necessaryMethods = getNecessaryMethods();
483         
484         Iterator it = clazz.getMembers().iterator();
485         while (it.hasNext()) {
486             jq_Member m = (jq_Member)it.next();
487             if (m instanceof jq_Field) {
488                 if (!necessaryFields.contains(m)) {
489                     if (TRACE) out.println("Eliminating field: "+m);
490                     it.remove();
491                 }
492             } else {
493                 Assert._assert(m instanceof jq_Method);
494                 if (!necessaryMethods.contains(m)) {
495                     if (TRACE) out.println("Eliminating method: "+m);
496                     it.remove();
497                 }
498             }
499         }
500 
501         int n;
502         n=0;
503         jq_InstanceField[] declared_instance_fields = clazz.getDeclaredInstanceFields();
504         for (int i=0; i<declared_instance_fields.length; ++i) {
505             jq_InstanceField f = declared_instance_fields[i];
506             f.unprepare();
507             if (necessaryMethods.contains(f)) ++n;
508         }
509         jq_InstanceField[] ifs = new jq_InstanceField[n];
510         for (int i=0, j=-1; j<n-1; ++i) {
511             jq_InstanceField f = declared_instance_fields[i];
512             if (necessaryFields.contains(f)) {
513                 ifs[++j] = f;
514                 ++jq_Class.NumOfIFieldsKept;
515             } else {
516                 if (TRACE) out.println("Eliminating instance field: "+f);
517                 ++jq_Class.NumOfIFieldsEliminated;
518             }
519         }
520         clazz.setDeclaredInstanceFields(ifs);
521         
522         jq_StaticField[] static_fields = clazz.getDeclaredStaticFields();
523         int static_data_size=0;
524         n=0; 
525         for (int i=0; i<static_fields.length; ++i) {
526             jq_StaticField f = static_fields[i];
527             f.unprepare();
528             if (necessaryFields.contains(f)) ++n;
529         }
530         jq_StaticField[] sfs = new jq_StaticField[n];
531         for (int i=0, j=-1; j<n-1; ++i) {
532             jq_StaticField f = static_fields[i];
533             if (necessaryFields.contains(f)) {
534                 sfs[++j] = f;
535                 static_data_size += f.getWidth();
536                 ++jq_Class.NumOfSFieldsKept;
537             }
538             else {
539                 if (TRACE) out.println("Eliminating static field: "+f);
540                 ++jq_Class.NumOfSFieldsEliminated;
541             }
542         }
543         clazz.setDeclaredStaticFields(sfs);
544 
545         n=0;
546         jq_InstanceMethod[] declared_instance_methods = clazz.getDeclaredInstanceMethods();
547         for (int i=0; i<declared_instance_methods.length; ++i) {
548             jq_InstanceMethod f = declared_instance_methods[i];
549             f.unprepare();
550             f.clearOverrideFlags();
551             if (necessaryMethods.contains(f)) ++n;
552         }
553         jq_InstanceMethod[] ims = new jq_InstanceMethod[n];
554         for (int i=0, j=-1; j<n-1; ++i) {
555             jq_InstanceMethod f = declared_instance_methods[i];
556             if (necessaryMethods.contains(f)) {
557                 ims[++j] = f;
558                 ++jq_Class.NumOfIMethodsKept;
559             } else {
560                 if (BootstrapRootSet.TRACE) BootstrapRootSet.out.println("Eliminating instance method: "+f);
561                 ++jq_Class.NumOfIMethodsEliminated;
562             }
563         }
564         clazz.setDeclaredInstanceMethods(ims);
565         
566         n=0;
567         jq_StaticMethod[] static_methods = clazz.getDeclaredStaticMethods();
568         for (int i=0; i<static_methods.length; ++i) {
569             jq_StaticMethod f = static_methods[i];
570             f.unprepare();
571             if (necessaryMethods.contains(f)) ++n;
572         }
573         jq_StaticMethod[] sms = new jq_StaticMethod[n];
574         for (int i=0, j=-1; j<n-1; ++i) {
575             jq_StaticMethod f = static_methods[i];
576             if (necessaryMethods.contains(f)) {
577                 sms[++j] = f;
578                 ++jq_Class.NumOfSMethodsKept;
579             } else {
580                 if (BootstrapRootSet.TRACE) BootstrapRootSet.out.println("Eliminating static method: "+f);
581                 ++jq_Class.NumOfSMethodsEliminated;
582             }
583         }
584         clazz.setDeclaredStaticMethods(sms);
585         
586         /*
587         n=0;
588         for (int i=0; i<declared_interfaces.length; ++i) {
589             jq_Class f = declared_interfaces[i];
590             if (instantiatedTypes.contains(f)) ++n;
591         }
592         jq_Class[] is = new jq_Class[n];
593         for (int i=0, j=-1; j<n-1; ++i) {
594             jq_Class f = declared_interfaces[i];
595             if (instantiatedTypes.contains(f))
596                 is[++j] = f;
597             else
598                 if (trim.TRACE) trim.out.println("Eliminating interface: "+f);
599         }
600         declared_interfaces = is;
601         */
602         
603         clazz.getCP().trim(necessaryFields, necessaryMethods);
604         
605         clazz.prepare();
606     }
607 }