View Javadoc

1   // Bootstrapper.java, created Mon Feb  5 23:23:21 2001 by joewhaley
2   // Copyright (C) 2001-3 John Whaley <jwhaley@alum.mit.edu>
3   // Licensed under the terms of the GNU LGPL; see COPYING for details.
4   package joeq.Main;
5   
6   import java.util.ArrayList;
7   import java.util.Arrays;
8   import java.util.Collections;
9   import java.util.Comparator;
10  import java.util.HashSet;
11  import java.util.Iterator;
12  import java.util.LinkedList;
13  import java.util.Set;
14  import java.util.SortedSet;
15  import java.util.TreeSet;
16  import java.io.BufferedReader;
17  import java.io.DataOutputStream;
18  import java.io.File;
19  import java.io.FileOutputStream;
20  import java.io.FileReader;
21  import java.io.IOException;
22  import java.io.RandomAccessFile;
23  import java.nio.channels.FileChannel;
24  import joeq.Allocator.CodeAllocator;
25  import joeq.Allocator.DefaultCodeAllocator;
26  import joeq.Allocator.HeapAllocator;
27  import joeq.Bootstrap.BootstrapCodeAddress;
28  import joeq.Bootstrap.BootstrapCodeAllocator;
29  import joeq.Bootstrap.BootstrapHeapAddress;
30  import joeq.Bootstrap.BootstrapRootSet;
31  import joeq.Bootstrap.SinglePassBootImage;
32  import joeq.Bootstrap.BootstrapCodeAddress.BootstrapCodeAddressFactory;
33  import joeq.Class.Delegates;
34  import joeq.Class.PrimordialClassLoader;
35  import joeq.Class.jq_Array;
36  import joeq.Class.jq_Class;
37  import joeq.Class.jq_Member;
38  import joeq.Class.jq_Method;
39  import joeq.Class.jq_Reference;
40  import joeq.Class.jq_StaticField;
41  import joeq.Class.jq_StaticMethod;
42  import joeq.Class.jq_Type;
43  import joeq.ClassLib.ClassLibInterface;
44  import joeq.Compiler.CompilationState;
45  import joeq.Compiler.BytecodeAnalysis.Trimmer;
46  import joeq.Compiler.CompilationState.BootstrapCompilation;
47  import joeq.Memory.CodeAddress;
48  import joeq.Memory.HeapAddress;
49  import joeq.Runtime.ObjectTraverser;
50  import joeq.Runtime.Reflection;
51  import joeq.Runtime.SystemInterface;
52  import joeq.Runtime.Unsafe;
53  import joeq.UTF.Utf8;
54  import jwutil.collections.LinearSet;
55  import jwutil.util.Assert;
56  
57  /*
58   * @author  John Whaley <jwhaley@alum.mit.edu>
59   * @version $Id: Bootstrapper.java 2466 2006-06-07 23:12:58Z joewhaley $
60   */
61  public abstract class Bootstrapper {
62  
63      private static SinglePassBootImage objmap;
64      
65      public static void main(String[] args) throws IOException {
66          
67          if (jq.RunningNative) {
68              System.err.println("Error: self-bootstrapping not supported (yet)");
69              System.exit(-1);
70          }
71          
72          String imageName = "jq.obj";
73          //int startAddress = 0x00890000;
74          String rootMethodClassName = "joeq.Main.JoeqVM";
75          String rootMethodName = "boot";
76          String classList = null;
77          String addToClassList = null;
78          boolean TrimAllTypes = false;
79          boolean DUMP_COFF = false;
80          boolean USE_BYTECODE_TRIMMER = true;
81  
82          // initialize list of methods to invoke on joeq startup
83          jq.on_vm_startup = new LinkedList();
84          
85          CodeAddress.FACTORY = joeq.Bootstrap.BootstrapCodeAddress.FACTORY;
86          HeapAddress.FACTORY = joeq.Bootstrap.BootstrapHeapAddress.FACTORY;
87          //StackAddress.FACTORY = joeq.Bootstrap.BootstrapStackAddress.FACTORY;
88          
89          jq.IsBootstrapping = true;
90          ClassLibInterface.useJoeqClasslib(true);
91          
92          CodeAllocator.initializeCompiledMethodMap();
93          HeapAllocator.initializeDataSegment();
94          
95          if (ClassLibInterface.DEFAULT.getClass().toString().indexOf("win32") != -1) {
96              DUMP_COFF = true;
97          } else {
98              DUMP_COFF = false;
99          }
100         String osarch = System.getProperty("os.arch");
101         if (osarch.equals("i386") || osarch.equals("x86")) {
102             try {
103                 Class.forName("joeq.Scheduler.jq_x86RegisterState");
104             } catch (ClassNotFoundException e) {
105                 System.err.println("Error: cannot load x86 module");
106                 System.exit(-1);
107             }
108             String default_compiler_name = System.getProperty("joeq.compiler", "joeq.Compiler.Reference.x86.x86ReferenceCompiler$Factory");
109             Delegates.setDefaultCompiler(default_compiler_name);
110         } else {
111             System.err.println("Error: architecture "+osarch+" is not yet supported.");
112             System.exit(-1);
113         }
114 
115         String classpath = System.getProperty("sun.boot.class.path")+
116                            System.getProperty("path.separator")+
117                            System.getProperty("java.class.path");
118         
119         for (int i=0; i<args.length; ) {
120             int j = TraceFlags.setTraceFlag(args, i);
121             if (i != j) { i = j; continue; }
122             if (args[i].equals("-o")) { // output file
123                 imageName = args[++i];
124                 ++i; continue;
125             }
126             if (args[i].equals("-r")) { // root method
127                 String s = args[++i];
128                 int dotloc = s.lastIndexOf('.');
129                 rootMethodName = s.substring(dotloc+1);
130                 rootMethodClassName = s.substring(0, dotloc);
131                 ++i; continue;
132             }
133             if (args[i].equals("-cp") || args[i].equals("-classpath")) { // class path
134                 classpath = args[++i];
135                 ++i; continue;
136             }
137             if (args[i].equals("-cl") || args[i].equals("-classlist")) { // class path
138                 classList = args[++i];
139                 ++i; continue;
140             }
141             if (args[i].equals("-a2cl") || args[i].equals("-addtoclasslist")) { // class path
142                 addToClassList = args[++i];
143                 ++i; continue;
144             }
145             if (args[i].equals("-t")) { // trim all types
146                 TrimAllTypes = true;
147                 ++i; continue;
148             }
149             if (args[i].equalsIgnoreCase("-borland")) {
150                 SinglePassBootImage.USE_MICROSOFT_STYLE_MUNGE = false;
151                 ++i; continue;
152             }
153             if (args[i].equalsIgnoreCase("-microsoft")) {
154                 SinglePassBootImage.USE_MICROSOFT_STYLE_MUNGE = true;
155                 ++i; continue;
156             }
157             /*
158             if (args[i].equals("-s")) { // start address
159                 startAddress = Integer.parseInt(args[++i], 16);
160                 ++i; continue;
161             }
162              */
163             err("unknown command line argument: "+args[i]);
164         }
165         
166         rootMethodClassName = rootMethodClassName.replace('.','/');
167 
168         System.out.println("Bootstrapping into "+imageName+", "+(DUMP_COFF?"COFF":"ELF")+" format, root method "+rootMethodClassName+"."+rootMethodName+(TrimAllTypes?", trimming all types.":"."));
169         
170         for (Iterator it = PrimordialClassLoader.classpaths(classpath); it.hasNext(); ) {
171             String s = (String)it.next();
172             PrimordialClassLoader.loader.addToClasspath(s);
173         }
174         
175         //Set nullStaticFields = ClassLibInterface.i.bootstrapNullStaticFields();
176         //Set nullInstanceFields = ClassLibInterface.i.bootstrapNullInstanceFields();
177         //System.out.println("Null static fields: "+nullStaticFields);
178         //System.out.println("Null instance fields: "+nullInstanceFields);
179 
180         // install bootstrap code allocator
181         BootstrapCodeAllocator bca = BootstrapCodeAllocator.DEFAULT;
182         DefaultCodeAllocator.default_allocator = bca;
183         CodeAddress.FACTORY = BootstrapCodeAddress.FACTORY = new BootstrapCodeAddressFactory(bca);
184         bca.init();
185         
186         // install object mapper
187         //ObjectTraverser obj_trav = new ObjectTraverser(nullStaticFields, nullInstanceFields);
188         ObjectTraverser obj_trav = ClassLibInterface.DEFAULT.getObjectTraverser();
189         Reflection.obj_trav = obj_trav;
190         obj_trav.initialize();
191         //objmap = new BootImage(bca);
192         objmap = SinglePassBootImage.DEFAULT;
193         //HeapAddress.FACTORY = BootstrapHeapAddress.FACTORY = new BootstrapHeapAddressFactory(objmap);
194         
195         long starttime = System.currentTimeMillis();
196         jq_Class c;
197         c = (jq_Class)PrimordialClassLoader.loader.getOrCreateBSType("L"+rootMethodClassName+";");
198         c.prepare();
199         long loadtime = System.currentTimeMillis() - starttime;
200 
201         jq_StaticMethod rootm = null;
202         Utf8 rootm_name = Utf8.get(rootMethodName);
203         for(Iterator it = Arrays.asList(c.getDeclaredStaticMethods()).iterator();
204             it.hasNext(); ) {
205             jq_StaticMethod m = (jq_StaticMethod)it.next();
206             if (m.getName() == rootm_name) {
207                 rootm = m;
208                 break;
209             }
210         }
211         if (rootm == null)
212             err("root method not found: "+rootMethodClassName+"."+rootMethodName);
213         
214         Set classset = new HashSet();
215         Set methodset;
216         
217         starttime = System.currentTimeMillis();
218         if (addToClassList != null) {
219             BufferedReader dis = new BufferedReader(new FileReader(addToClassList));
220             for (;;) {
221                 String classname = dis.readLine();
222                 if (classname == null) break;
223                 if (classname.charAt(0) == '#') continue;
224                 jq_Type t = PrimordialClassLoader.loader.getOrCreateBSType(classname);
225                 t.prepare();
226                 classset.add(t);
227             }
228         }
229         if (classList != null) {
230             BufferedReader dis = new BufferedReader(new FileReader(classList));
231             for (;;) {
232                 String classname = dis.readLine();
233                 if (classname == null) break;
234                 if (classname.equals("")) continue;
235                 if (classname.charAt(0) == '#') continue;
236                 if (classname.endsWith("*")) {
237                     Assert._assert(classname.startsWith("L"));
238                     Iterator i = PrimordialClassLoader.loader.listPackage(classname.substring(1, classname.length()-1));
239                     while (i.hasNext()) {
240                         String s = (String)i.next();
241                         Assert._assert(s.endsWith(".class"));
242                         s = "L"+s.substring(0, s.length()-6)+";";
243                         jq_Class t = (jq_Class)PrimordialClassLoader.loader.getOrCreateBSType(s);
244                         t.prepare();
245                         classset.add(t);
246                         for (;;) {
247                             jq_Array q = t.getArrayTypeForElementType();
248                             q.prepare();
249                             classset.add(q);
250                             t = t.getSuperclass();
251                             if (t == null) break;
252                             classset.add(t);
253                         }
254                     }
255                 } else {
256                     jq_Type t = PrimordialClassLoader.loader.getOrCreateBSType(classname);
257                     t.prepare();
258                     classset.add(t);
259                     if (t instanceof jq_Class) {
260                         jq_Class q = (jq_Class) t;
261                         for (;;) {
262                             t = q.getArrayTypeForElementType();
263                             t.prepare();
264                             classset.add(t);
265                             q = q.getSuperclass();
266                             if (q == null) break;
267                             classset.add(q);
268                         }
269                     }
270                 }
271             }
272             methodset = new HashSet();
273             Iterator i = classset.iterator();
274             while (i.hasNext()) {
275                 jq_Type t = (jq_Type)i.next();
276                 if (t.isClassType()) {
277                     jq_Class cl = (jq_Class)t;
278                     jq_Method[] ms = cl.getDeclaredStaticMethods();
279                     for (int k=0; k<ms.length; ++k) {
280                         methodset.add(ms[k]);
281                     }
282                     ms = cl.getDeclaredInstanceMethods();
283                     for (int k=0; k<ms.length; ++k) {
284                         methodset.add(ms[k]);
285                     }
286                     ms = cl.getVirtualMethods();
287                     for (int k=0; k<ms.length; ++k) {
288                         methodset.add(ms[k]);
289                     }
290                 }
291             }
292         } else {
293             // traverse the code and data starting at the root set to find all necessary
294             // classes and members.
295             
296             if (USE_BYTECODE_TRIMMER) {
297                 Trimmer trim = new Trimmer(rootm, classset, !TrimAllTypes);
298                 trim.go();
299 
300                 BootstrapRootSet rs = trim.getRootSet();
301                 System.out.println("Number of instantiated types: "+rs.getInstantiatedTypes().size());
302                 //System.out.println("Instantiated types: "+rs.getInstantiatedTypes());
303 
304                 System.out.println("Number of necessary methods: "+rs.getNecessaryMethods().size());
305                 //System.out.println("Necessary methods: "+rs.getNecessaryMethods());
306 
307                 System.out.println("Number of necessary fields: "+rs.getNecessaryFields().size());
308                 //System.out.println("Necessary fields: "+rs.getNecessaryFields());
309                 
310                 // find all used classes.
311                 classset = rs.getNecessaryTypes();
312 
313                 System.out.println("Number of necessary classes: "+classset.size());
314                 //System.out.println("Necessary classes: "+classset);
315 
316                 if (TrimAllTypes) {
317                     // Trim all the types.
318                     Iterator it = classset.iterator();
319                     while (it.hasNext()) {
320                         jq_Type t = (jq_Type)it.next();
321                         System.out.println("Trimming type: "+t.getName());
322                         Assert._assert(t.isPrepared());
323                         if (t.isClassType()) {
324                             rs.trimClass((jq_Class)t);
325                         }
326                     }
327                     System.out.println("Number of instance fields kept: "+jq_Class.NumOfIFieldsKept);
328                     System.out.println("Number of static fields kept: "+jq_Class.NumOfSFieldsKept);
329                     System.out.println("Number of instance methods kept: "+jq_Class.NumOfIMethodsKept);
330                     System.out.println("Number of static methods kept: "+jq_Class.NumOfSMethodsKept);
331 
332                     System.out.println("Number of instance fields eliminated: "+jq_Class.NumOfIFieldsEliminated);
333                     System.out.println("Number of static fields eliminated: "+jq_Class.NumOfSFieldsEliminated);
334                     System.out.println("Number of instance methods eliminated: "+jq_Class.NumOfIMethodsEliminated);
335                     System.out.println("Number of static methods eliminated: "+jq_Class.NumOfSMethodsEliminated);
336                 }
337 
338                 methodset = rs.getNecessaryMethods();
339             } else {
340                 // TODO: use a supplied call graph.
341                 BootstrapRootSet rs = null;
342                 methodset = rs.getNecessaryMethods();
343             }
344         }
345         loadtime += System.currentTimeMillis() - starttime;
346         System.out.println("Load time: "+loadtime/1000f+"s");
347         
348         if (classList == null) {
349             dumpClassSet(classset);
350             dumpMethodSet(methodset);
351         }
352             
353         // initialize the set of boot types
354         objmap.boot_types = classset;
355         BootstrapCompilation comp = (BootstrapCompilation) CompilationState.DEFAULT;
356         comp.setBootTypes(classset);
357         
358         if (false) {
359             ArrayList class_list = new ArrayList(classset);
360             Collections.sort(class_list, new Comparator() {
361                 public int compare(Object o1, Object o2) {
362                     return ((jq_Type)o1).getDesc().toString().compareTo(((jq_Type)o2).getDesc().toString());
363                 }
364                 public boolean equals(Object o) { return this == o; }
365             });
366             System.out.println("Types:");
367             Set packages = new LinearSet();
368             Iterator it = class_list.iterator();
369             while (it.hasNext()) {
370                 jq_Type t = (jq_Type)it.next();
371                 String s = t.getDesc().toString();
372                 System.out.println(s);
373                 if (s.charAt(0) == 'L') {
374                     int index = s.lastIndexOf('/');
375                     if (index == -1) s = "";
376                     else s = s.substring(1, index+1);
377                     packages.add(s);
378                 }
379             }
380             System.out.println("Packages:");
381             it = packages.iterator();
382             while (it.hasNext()) {
383                 System.out.println("L"+it.next()+"*");
384             }
385         }
386         
387         // enable allocations
388         objmap.enableAllocations();
389 
390         starttime = System.currentTimeMillis();
391         
392         // Allocate entrypoints first in data section.
393         // NOTE: will only be first if java.lang.Object doesn't have any static members.
394         SystemInterface._class.sf_initialize();
395 
396         //jq.Assert(SystemInterface._entry.getAddress() == startAddress + ARRAY_HEADER_SIZE,
397         //          "entrypoint is at "+Strings.hex8(SystemInterface._entry.getAddress()));
398         
399         // Allocate space for the static fields of all necessary types.
400         // Note: Static fields that are constant objects (typically java.lang.String)
401         //       are also allocated here.
402         Iterator it = classset.iterator();
403         while (it.hasNext()) {
404             jq_Type t = (jq_Type) it.next();
405             Assert._assert(t.isPrepared());
406             t.sf_initialize();
407         }
408         long sfinittime = System.currentTimeMillis() - starttime;
409         System.out.println("SF init time: "+sfinittime/1000f+"s");
410         
411         // Compile versions of all necessary methods.
412         // Automatically allocates any objects in the constant pool
413         // that are used in the code (via ldc instruction).
414         starttime = System.currentTimeMillis();
415         it = methodset.iterator();
416         while (it.hasNext()) {
417             jq_Member m = (jq_Member)it.next();
418             if (m instanceof jq_Method) {
419                 jq_Method m2 = ((jq_Method)m);
420                 if (m2.getDeclaringClass() == Unsafe._class) continue;
421                 if (m2.getDeclaringClass().isAddressType()) continue;
422                 m2.compile();
423             }
424         }
425         long compiletime = System.currentTimeMillis() - starttime;
426         System.out.println("Compile time: "+compiletime/1000f+"s");
427 
428         // Get the JDK type of each of the classes that could be in our image, so
429         // that we can trigger each of their <clinit> methods, because some
430         // <clinit> methods add Utf8 references to our table.
431         int numTypes = PrimordialClassLoader.loader.getNumTypes();
432         jq_Type[] types = PrimordialClassLoader.loader.getAllTypes();
433         for (int i = 0; i < numTypes; ++i) {
434             jq_Type t = types[i];
435             Reflection.getJDKType(t);
436         }
437 
438         // Now we have compiled everything, most static fields should be pretty much set.
439         // Add the object of every static field.
440         starttime = System.currentTimeMillis();
441         it = classset.iterator();
442         while (it.hasNext()) {
443             jq_Type t = (jq_Type)it.next();
444             Assert._assert(t.isSFInitialized());
445             if (t.isClassType()) {
446                 jq_Class k = (jq_Class)t;
447                 if (k.getSuperclass() != null &&
448                     !classset.contains(k.getSuperclass())) {
449                     Assert.UNREACHABLE(k.getSuperclass()+" (superclass of "+k+") is not in class set!");
450                 }
451                 jq_StaticField[] sfs = k.getDeclaredStaticFields();
452                 for (int j=0; j<sfs.length; ++j) {
453                     jq_StaticField sf = sfs[j];
454                     if (sf.getType().isReferenceType() && !sf.getType().isAddressType()) {
455                         Object val = Reflection.getstatic_A(sf);
456                         objmap.getOrAllocateObject(val);
457                     }
458                 }
459             }
460         }
461         
462         // Initialize and add the jq_Class/jq_Array/jq_Primitive objects for all
463         // necessary types.
464         it = classset.iterator();
465         while (it.hasNext()) {
466             jq_Type t = (jq_Type)it.next();
467             Assert._assert(t.isSFInitialized());
468             
469             if (t == Unsafe._class) continue;
470             //System.out.println("Compiling type: "+t.getName());
471             
472             t.compile();
473             t.cls_initialize();
474             objmap.initializeObject(t);
475         }
476         
477         // Reinitialize jq_Reference and jq_Member objects to match the change in initialization state.
478         objmap.reinitializeObjects();
479         
480         // Reinitialize the TreeMap object in the compiledMethods field.
481         // It has changed because new methods have been compiled.
482         objmap.initializeObject(CodeAllocator.compiledMethods);
483         
484         // Get the set of compiled methods, because it is used during bootstrapping.
485         //CodeAllocator.getCompiledMethods();
486         
487         System.out.println("Number of classes seen = "+PrimordialClassLoader.loader.getNumTypes());
488         System.out.println("Number of classes in image = "+objmap.boot_types.size());
489         
490         // Traverse all of the objects recursively.
491         objmap.handleForwardReferences();
492         
493         // We shouldn't encounter any new Utf8 from this point
494         Utf8.NO_NEW = true;
495 
496         // Now that we have mostly visited all of the objects, the static fields
497         // should be up-to-date, so we can initialize them here.
498         // We also initialize the vtables, because everything is compiled now.
499         // CAVEAT: This assumes that the only important stuff that has changed are
500         // static fields.  If an field of an object that we have already visited has
501         // this will NOT be reflected in the generated image.  If we want it to,
502         // we will need to explicitly call initializeObject() on that object.
503         it = classset.iterator();
504         while (it.hasNext()) {
505             jq_Type t = (jq_Type) it.next();
506             if (t.isReferenceType()) {
507                 jq_Reference r = (jq_Reference) t;
508                 if (r != Unsafe._class) {
509                     objmap.initVTable(r);
510                 }
511                 if (r.isClassType()) {
512                     jq_Class k = (jq_Class) t;
513                     objmap.initStaticFields(k);
514                 }
515             }
516         }
517         
518         jq_Class jq_class = (jq_Class)PrimordialClassLoader.loader.getOrCreateBSType("Ljoeq/Main/jq;");
519         Assert._assert(classset.contains(jq_class));
520         // Turn on jq.RunningNative flag in image.
521         jq_class.setStaticData(jq_class.getOrCreateStaticField("RunningNative","Z"), 1);
522         // Turn off jq.IsBootstrapping flag in image.
523         jq_class.setStaticData(jq_class.getOrCreateStaticField("IsBootstrapping","Z"), 0);
524         jq_Class utf8_class = (jq_Class)PrimordialClassLoader.loader.getOrCreateBSType("Ljoeq/UTF/Utf8;");
525         // Turn off Utf8.NO_NEW flag in image.
526         utf8_class.setStaticData(utf8_class.getOrCreateStaticField("NO_NEW","Z"), 0);
527         
528         // By now we have probably added everything we need for the on_vm_startup list.
529         // Set the "on_vm_startup" field to the current value.
530         // We can't use our normal reflection, because it is in nullStaticFields so it
531         // always just returns null.
532         HeapAddress addr = HeapAddress.addressOf(jq.on_vm_startup);
533         jq_StaticField _on_vm_startup = jq_class.getOrCreateStaticField("on_vm_startup", "Ljava/util/List;");
534         jq_class.setStaticData(_on_vm_startup, addr);
535         objmap.addDataReloc(_on_vm_startup.getAddress(), addr);
536         
537         // Now actually set the field values in the image and add relocs.
538         it = classset.iterator();
539         while (it.hasNext()) {
540             jq_Type t = (jq_Type) it.next();
541             if (t.isClassType()) {
542                 jq_Class k = (jq_Class) t;
543                 objmap.initStaticData(k);
544                 objmap.addStaticFieldRelocs(k);
545             }
546         }
547         
548         // Maybe more stuff has been compiled.
549         objmap.reinitializeObjects();
550         
551         // A static field may have referred to a new object, so traverse any new stuff.
552         objmap.handleForwardReferences();
553         
554         long traversaltime = System.currentTimeMillis() - starttime;
555         
556         // All done with traversal, no more objects can be added to the image.
557         objmap.disableAllocations();
558         
559         System.out.println("Scanned: "+objmap.numOfEntries()+" objects, memory used: "+(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory())+"                    ");
560         System.out.println("Scan time: "+traversaltime/1000f+"s");
561         System.out.println("Total number of Utf8 = "+(Utf8.size+1));
562         System.out.println("Code segment size = "+bca.size());
563         System.out.println("Data segment size = "+objmap.size());
564         
565         // Update code min/max addresses.
566         objmap.initStaticField(CodeAllocator._lowAddress);
567         objmap.initStaticField(CodeAllocator._highAddress);
568         objmap.initStaticData(CodeAllocator._class);
569         
570         // Update heap min/max addresses.
571         HeapAllocator.data_segment_start = new BootstrapHeapAddress(-1);
572         HeapAllocator.data_segment_end = new BootstrapHeapAddress(objmap.size());
573         objmap.initStaticField(HeapAllocator._data_segment_start);
574         objmap.initStaticField(HeapAllocator._data_segment_end);
575         objmap.initStaticData(HeapAllocator._class);
576         
577         // Dump it!
578         File f = new File(imageName);
579         if (f.exists()) f.delete();
580         RandomAccessFile fos = new RandomAccessFile(imageName, "rw");
581         FileChannel fc = fos.getChannel();
582         starttime = System.currentTimeMillis();
583         try {
584             if (DUMP_COFF)
585                 objmap.dumpCOFF(fc, rootm);
586             else
587                 objmap.dumpELF(fc, rootm);
588         } finally {
589             fc.close();
590             fos.close();
591         }
592         long dumptime = System.currentTimeMillis() - starttime;
593         System.out.println("Dump time: "+dumptime/1000f+"s");
594         
595         System.out.println(rootm.getDefaultCompiledVersion());
596 
597         //objmap = null;
598         //System.gc(); System.gc();
599         //System.out.println("total memory = "+Runtime.getRuntime().totalMemory());
600         //System.out.println("free memory = "+Runtime.getRuntime().freeMemory());
601     }
602 
603     public static void dumpClassSet(Set s) throws IOException {
604         DataOutputStream dos = null;
605         try {
606             dos = new DataOutputStream(new FileOutputStream("classlist"));
607             SortedSet ss = new TreeSet();
608             for (Iterator i = s.iterator(); i.hasNext(); ) {
609                 jq_Type t = (jq_Type) i.next();
610                 ss.add(t.toString());
611             }
612             for (Iterator i = ss.iterator(); i.hasNext(); ) {
613                 String t = (String) i.next();
614                 dos.writeBytes(t + "\n");
615             }
616         } finally {
617             if (dos != null) dos.close();
618         }
619     }
620     
621     public static void dumpMethodSet(Set s) throws IOException {
622         DataOutputStream dos = null;
623         try {
624             dos = new DataOutputStream(new FileOutputStream("methodlist"));
625             SortedSet ss = new TreeSet();
626             for (Iterator i = s.iterator(); i.hasNext(); ) {
627                 jq_Method t = (jq_Method) i.next();
628                 ss.add(t.toString());
629             }
630             for (Iterator i = ss.iterator(); i.hasNext(); ) {
631                 String t = (String) i.next();
632                 dos.writeBytes(t + "\n");
633             }
634         } finally {
635             if (dos != null) dos.close();
636         }
637     }
638     
639     public static void err(String s) {
640         System.err.println(s);
641         System.exit(0);
642     }
643 
644 }