Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: Bootstrap/BootImage.java


1   // BootImage.java, created Mon Feb  5 23:23:20 2001 by joewhaley
2   // Copyright (C) 2001-3 John Whaley <jwhaley@alum.mit.edu>
3   // Licensed under the terms of the GNU LGPL; see COPYING for details.
4   package Bootstrap;
5   
6   import java.io.IOException;
7   import java.io.PrintStream;
8   import java.lang.reflect.Array;
9   import java.util.ArrayList;
10  import java.util.HashMap;
11  import java.util.HashSet;
12  import java.util.Iterator;
13  import java.util.LinkedList;
14  import java.util.List;
15  import java.util.Map;
16  
17  import Allocator.CodeAllocator;
18  import Allocator.ObjectLayout;
19  import Assembler.x86.Code2CodeReference;
20  import Assembler.x86.Code2HeapReference;
21  import Assembler.x86.DirectBindCall;
22  import Assembler.x86.ExternalReference;
23  import Assembler.x86.Heap2CodeReference;
24  import Assembler.x86.Heap2HeapReference;
25  import Assembler.x86.Reloc;
26  import Clazz.jq_Array;
27  import Clazz.jq_Class;
28  import Clazz.jq_CompiledCode;
29  import Clazz.jq_InstanceField;
30  import Clazz.jq_Member;
31  import Clazz.jq_Method;
32  import Clazz.jq_Primitive;
33  import Clazz.jq_Reference;
34  import Clazz.jq_StaticField;
35  import Clazz.jq_StaticMethod;
36  import Clazz.jq_Type;
37  import Linker.ELF.ELF;
38  import Linker.ELF.ELFConstants;
39  import Linker.ELF.ELFOutput;
40  import Linker.ELF.RelocEntry;
41  import Linker.ELF.Section;
42  import Linker.ELF.SymbolTableEntry;
43  import Main.jq;
44  import Memory.Address;
45  import Memory.CodeAddress;
46  import Memory.HeapAddress;
47  import Run_Time.ExceptionDeliverer;
48  import Run_Time.Reflection;
49  import Run_Time.SystemInterface;
50  import Run_Time.Unsafe;
51  import Scheduler.jq_NativeThread;
52  import Util.Assert;
53  import Util.Strings;
54  import Util.Collections.IdentityHashCodeWrapper;
55  import Util.IO.ExtendedDataOutput;
56  
57  /**
58   * BootImage
59   *
60   * @author  John Whaley <jwhaley@alum.mit.edu>
61   * @version $Id: BootImage.java,v 1.43 2003/08/10 00:14:39 joewhaley Exp $
62   */
63  public class BootImage implements ELFConstants {
64  
65      public static /*final*/ boolean TRACE = false;
66      public static final PrintStream out = System.out;
67      
68      public static final BootImage DEFAULT = new BootImage(BootstrapCodeAllocator.DEFAULT);
69      
70      private final Map/*<IdentityHashCodeWrapper, Entry>*/ hash;
71      private final ArrayList/*<Entry>*/ entries;
72      private int heapCurrent;
73      private final int startAddress;
74  
75      private BootstrapCodeAllocator bca;
76      private List data_relocs;
77      
78      public BootImage(BootstrapCodeAllocator bca, int initialCapacity, float loadFactor) {
79          hash = new HashMap(initialCapacity, loadFactor);
80          entries = new ArrayList(initialCapacity);
81          this.bca = bca;
82          this.heapCurrent = this.startAddress = 0;
83          this.data_relocs = new LinkedList();
84      }
85      public BootImage(BootstrapCodeAllocator bca, int initialCapacity) {
86          hash = new HashMap(initialCapacity);
87          entries = new ArrayList(initialCapacity);
88          this.bca = bca;
89          this.heapCurrent = this.startAddress = 0;
90          this.data_relocs = new LinkedList();
91      }
92      public BootImage(BootstrapCodeAllocator bca) {
93          hash = new HashMap();
94          entries = new ArrayList();
95          this.bca = bca;
96          this.heapCurrent = this.startAddress = 0;
97          this.data_relocs = new LinkedList();
98      }
99  
100     public final HeapAddress addressOf(Object o) {
101         Assert._assert(!(o instanceof Address));
102         return getOrAllocateObject(o);
103     }
104     
105     public final void addCodeReloc(HeapAddress addr, CodeAddress target) {
106         Heap2CodeReference r = new Heap2CodeReference(addr, target);
107         data_relocs.add(r);
108     }
109     public final void addDataReloc(HeapAddress addr, HeapAddress target) {
110         Heap2HeapReference r = new Heap2HeapReference(addr, target);
111         data_relocs.add(r);
112     }
113     
114     public final void invokeclinit(jq_Class c) {
115         // call forName on this type to trigger class initialization
116         String cname = c.getName().toString();
117         try {
118             Class.forName(cname);
119         } catch (ClassNotFoundException x) {
120             // bootstrapping jvm can't find the class?
121             System.err.println("ERROR: bootstrapping jvm cannot find class "+cname);
122             Assert.UNREACHABLE();
123         }
124     }
125 
126     private boolean alloc_enabled = false;
127     
128     public void enableAllocations() { alloc_enabled = true; }
129     public void disableAllocations() { alloc_enabled = false; }
130     
131     public HeapAddress getOrAllocateObject(Object o) {
132         if (o == null) return HeapAddress.getNull();
133         //jq.Assert(!(o instanceof Address));
134         IdentityHashCodeWrapper k = IdentityHashCodeWrapper.create(o);
135         Entry e = (Entry)hash.get(k);
136         if (e != null) return e.getAddress();
137         // not yet allocated, allocate it.
138         Assert._assert(alloc_enabled);
139         Class objType = o.getClass();
140         jq_Reference type = (jq_Reference)Reflection.getJQType(objType);
141         if (!jq.boot_types.contains(type)) {
142             System.err.println("--> class "+type+" is not in the set of boot types!");
143             //new Exception().printStackTrace();
144             return HeapAddress.getNull();
145         }
146         int addr;
147         int size;
148         if (type.isArrayType()) {
149             addr = heapCurrent + ObjectLayout.ARRAY_HEADER_SIZE;
150             size = ((jq_Array)type).getInstanceSize(Array.getLength(o));
151             size = (size+3) & ~3;
152             if (TRACE)
153                 out.println("Allocating entry "+entries.size()+": "+objType+" length "+Array.getLength(o)+" size "+size+" "+Strings.hex(System.identityHashCode(o))+" at "+Strings.hex(addr));
154         } else {
155             Assert._assert(type.isClassType());
156             addr = heapCurrent + ObjectLayout.OBJ_HEADER_SIZE;
157             size = ((jq_Class)type).getInstanceSize();
158             if (TRACE)
159                 out.println("Allocating entry "+entries.size()+": "+objType+" size "+size+" "+Strings.hex(System.identityHashCode(o))+" at "+Strings.hex(addr)+((o instanceof jq_Type)?": "+o:""));
160         }
161         heapCurrent += size;
162         BootstrapHeapAddress a = new BootstrapHeapAddress(addr);
163         e = Entry.create(o, a);
164         hash.put(k, e);
165         entries.add(e);
166         return a;
167     }
168     
169     public static boolean IGNORE_UNKNOWN_OBJECTS = false;
170     
171     public HeapAddress getAddressOf(Object o) {
172         Assert._assert(!(o instanceof Address));
173         if (o == null) return HeapAddress.getNull();
174         IdentityHashCodeWrapper k = IdentityHashCodeWrapper.create(o);
175         Entry e = (Entry)hash.get(k);
176         if (e == null) {
177             System.err.println("Unknown object of type: "+o.getClass()+" address: "+Strings.hex(System.identityHashCode(o))+" value: "+o);
178             if (IGNORE_UNKNOWN_OBJECTS) return HeapAddress.getNull();
179             throw new UnknownObjectException(o);
180         }
181         Class objType = o.getClass();
182         jq_Reference type = (jq_Reference)Reflection.getJQType(objType);
183         Assert._assert(type.isClsInitialized(), type.toString());
184         return e.getAddress();
185     }
186 
187     public Object getObject(int i) {
188         Entry e = (Entry)entries.get(i);
189         return e.getObject();
190     }
191     
192     public void addStaticFieldReloc(jq_StaticField f) {
193         jq_Type ftype = f.getType();
194         if (f.isCodeAddressType()) {
195             CodeAddress addr = (CodeAddress)Reflection.getstatic_P(f);
196             if (addr != null && !addr.isNull()) {
197                 if (TRACE) out.println("Adding code reloc for "+f+": "+f.getAddress().stringRep()+" "+addr.stringRep());
198                 addCodeReloc(f.getAddress(), addr);
199             }
200         } else if (f.isHeapAddressType()) {
201             HeapAddress addr = (HeapAddress)Reflection.getstatic_P(f);
202             if (addr != null && !addr.isNull()) {
203                 if (TRACE) out.println("Adding data reloc for "+f+": "+f.getAddress().stringRep()+" "+addr.stringRep());
204                 addDataReloc(f.getAddress(), addr);
205             }
206         } else if (ftype.isReferenceType()) {
207             Object val = Reflection.getstatic_A(f);
208             if (val != null) {
209                 if (val instanceof Address) {
210                     Assert.UNREACHABLE("Error: "+f+" contains "+((Address)val).stringRep());
211                 }
212                 HeapAddress addr = HeapAddress.addressOf(val);
213                 if (TRACE) out.println("Adding data reloc for "+f+": "+f.getAddress().stringRep()+" "+addr.stringRep());
214                 addDataReloc(f.getAddress(), addr);
215             }
216         }
217     }
218     
219     public void initStaticField(jq_StaticField f) {
220         jq_Class k = f.getDeclaringClass();
221         jq_Type ftype = f.getType();
222         if (ftype.isPrimitiveType()) {
223             if (ftype == jq_Primitive.INT) {
224                 int v = Reflection.getstatic_I(f);
225                 k.setStaticData(f, v);
226             } else if (ftype == jq_Primitive.FLOAT) {
227                 float v = Reflection.getstatic_F(f);
228                 k.setStaticData(f, v);
229             } else if (ftype == jq_Primitive.LONG) {
230                 long v = Reflection.getstatic_L(f);
231                 k.setStaticData(f, v);
232             } else if (ftype == jq_Primitive.DOUBLE) {
233                 double v = Reflection.getstatic_D(f);
234                 k.setStaticData(f, v);
235             } else if (ftype == jq_Primitive.BOOLEAN) {
236                 int v = Reflection.getstatic_Z(f)?1:0;
237                 k.setStaticData(f, v);
238             } else if (ftype == jq_Primitive.BYTE) {
239                 byte v = Reflection.getstatic_B(f);
240                 k.setStaticData(f, v);
241             } else if (ftype == jq_Primitive.SHORT) {
242                 short v = Reflection.getstatic_S(f);
243                 k.setStaticData(f, v);
244             } else if (ftype == jq_Primitive.CHAR) {
245                 char v = Reflection.getstatic_C(f);
246                 k.setStaticData(f, v);
247             } else
248                 Assert.UNREACHABLE();
249         } else if (ftype.isAddressType()) {
250             Address addr = Reflection.getstatic_P(f);
251             if (addr == null) addr = HeapAddress.getNull();
252             if (TRACE) out.println("Initializing static field "+f+" to "+addr.stringRep());
253             k.setStaticData(f, addr);
254         } else {
255             Object val = Reflection.getstatic_A(f);
256             HeapAddress addr = HeapAddress.addressOf(val);
257             if (TRACE) out.println("Initializing static field "+f+" to "+addr.stringRep());
258             k.setStaticData(f, addr);
259         }
260     }
261     
262     public int numOfEntries() { return entries.size(); }
263 
264     public static int UPDATE_PERIOD = 10000;
265 
266     public void find_reachable(int i) {
267         for (; i<entries.size(); ++i) {
268             if ((i % UPDATE_PERIOD) == 0) {
269                 out.print("Scanning: "+i+"/"+entries.size()+" objects, memory used: "+(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory())+"   \r");
270             }
271             Entry e = (Entry)entries.get(i);
272             Object o = e.getObject();
273             if (o == null) continue;
274             HeapAddress addr = e.getAddress();
275             Assert._assert(!addr.isNull());
276             Class objType = o.getClass();
277             jq_Reference jqType = (jq_Reference)Reflection.getJQType(objType);
278             if (TRACE)
279                 out.println("Entry "+i+": "+objType+" "+Strings.hex(System.identityHashCode(o)));
280             addDataReloc((HeapAddress)addr.offset(ObjectLayout.VTABLE_OFFSET), getOrAllocateObject(jqType));
281             if (jqType.isArrayType()) {
282                 jq_Type elemType = ((jq_Array)jqType).getElementType();
283                 if (elemType.isAddressType()) {
284                     // probably a vtable.  skip it -- handled separately.
285                 } else if (elemType.isReferenceType()) {
286                     int length = Array.getLength(o);
287                     Object[] v = (Object[])o;
288                     for (int k=0; k<length; ++k) {
289                         Object o2 = Reflection.arrayload_A(v, k);
290                         if (o2 != null) {
291                             addDataReloc((HeapAddress)addr.offset(k*HeapAddress.size()), getOrAllocateObject(o2));
292                         }
293                     }
294                 }
295             } else {
296                 Assert._assert(jqType.isClassType());
297                 jq_Class clazz = (jq_Class)jqType;
298                 jq_InstanceField[] fields = clazz.getInstanceFields();
299                 for (int k=0; k<fields.length; ++k) {
300                     jq_InstanceField f = fields[k];
301                     jq_Type ftype = f.getType();
302                     if (f.isCodeAddressType()) {
303                         CodeAddress val = (CodeAddress)Reflection.getfield_P(o, f);
304                         if (val != null && !val.isNull())
305                             addCodeReloc((HeapAddress)addr.offset(f.getOffset()), val);
306                     } else if (f.isHeapAddressType()) {
307                         HeapAddress val = (HeapAddress)Reflection.getfield_P(o, f);
308                         if (val != null && !val.isNull())
309                             addDataReloc((HeapAddress)addr.offset(f.getOffset()), val);
310                     } else if (f.isStackAddressType()) {
311                         // no reloc necessary.
312                     } else if (ftype.isReferenceType()) {
313                         Object val = Reflection.getfield_A(o, f);
314                         if (val != null) {
315                             addDataReloc((HeapAddress)addr.offset(f.getOffset()), getOrAllocateObject(val));
316                         }
317                     }
318                 }
319             }
320         }
321     }
322 
323     public int size() { return heapCurrent-startAddress; }
324     
325     private static class Entry {
326         private Object o;            // object in host vm
327         private HeapAddress address; // address in target vm
328         private Entry(Object o, HeapAddress address) { this.o = o; this.address = address; }
329         static Entry create(Object o, HeapAddress address) {
330             Assert._assert(o != null);
331             return new Entry(o, address);
332         }
333         Object getObject() { return o; }
334         HeapAddress getAddress() { return address; }
335     }
336     
337     public static final char F_RELFLG = (char)0x0001;
338     public static final char F_EXEC   = (char)0x0002;
339     public static final char F_LNNO   = (char)0x0004;
340     public static final char F_LSYMS  = (char)0x0008;
341     public static final char F_AR32WR = (char)0x0100;
342     
343     public void dumpFILHDR(ExtendedDataOutput out, int symptr, int nsyms)
344     throws IOException {
345         // FILHDR
346         out.writeUShort((char)0x014c);  // f_magic
347         out.writeUShort((char)2);       // f_nscns
348         long ms = System.currentTimeMillis();
349         int s = (int)(ms/1000);
350         out.writeUInt(s);               // f_timdat
351         out.writeUInt(symptr);          // f_symptr
352         out.writeUInt(nsyms);           // f_nsyms
353         out.writeUShort((char)0);       // f_opthdr
354         out.writeUShort((char)(F_LNNO | F_LSYMS | F_AR32WR)); // f_flags
355     }
356     
357     public static final int STYP_TEXT  = 0x00000020;
358     public static final int STYP_DATA  = 0x00000040;
359     public static final int STYP_BSS   = 0x00000080;
360     public static final int STYP_RELOV = 0x01000000;
361     public static final int STYP_EXEC  = 0x20000000;
362     public static final int STYP_READ  = 0x40000000;
363     public static final int STYP_WRITE = 0x80000000;
364     
365     public void dumpTEXTSCNHDR(ExtendedDataOutput out, int size, int nreloc)
366     throws IOException {
367         // SCNHDR
368         write_bytes(out, ".text", 8);       // s_name
369         out.writeUInt(0);                // s_paddr
370         out.writeUInt(0);                // s_vaddr
371         out.writeUInt(size);             // s_size
372         out.writeUInt(20+40+40);         // s_scnptr
373         out.writeUInt(20+40+40+size);    // s_relptr
374         out.writeUInt(0);                // s_lnnoptr
375         if (nreloc > 65535)
376             out.writeUShort((char)0xffff); // s_nreloc
377         else
378             out.writeUShort((char)nreloc); // s_nreloc
379         out.writeUShort((char)0);         // s_nlnno
380         if (nreloc > 65535)
381             out.writeUInt(STYP_TEXT | STYP_READ | STYP_WRITE | STYP_RELOV); // s_flags
382         else
383             out.writeUInt(STYP_TEXT | STYP_READ | STYP_WRITE); // s_flags
384     }
385     
386     public void dumpDATASCNHDR(ExtendedDataOutput out, int scnptr, int size, int nreloc)
387     throws IOException {
388         // SCNHDR
389         write_bytes(out, ".data", 8);       // s_name
390         out.writeUInt(0);                // s_paddr
391         out.writeUInt(0);                // s_vaddr
392         out.writeUInt(size);             // s_size
393         out.writeUInt(scnptr);           // s_scnptr
394         out.writeUInt(scnptr+size);      // s_relptr
395         out.writeUInt(0);                // s_lnnoptr
396         if (nreloc > 65535)
397             out.writeUShort((char)0xffff); // s_nreloc
398         else
399             out.writeUShort((char)nreloc); // s_nreloc
400         out.writeUShort((char)0);         // s_nlnno
401         if (nreloc > 65535)
402             out.writeUInt(STYP_DATA | STYP_READ | STYP_WRITE | STYP_RELOV); // s_flags
403         else
404             out.writeUInt(STYP_DATA | STYP_READ | STYP_WRITE); // s_flags
405     }
406     
407     public static final char RELOC_ADDR32 = (char)0x0006;
408     public static final char RELOC_REL32  = (char)0x0014;
409     
410     public void dumpLINENO(ExtendedDataOutput out, int addr, char lnno)
411     throws IOException {
412         out.writeUInt(addr);     // l_symndx / l_paddr
413         out.writeUShort(lnno);    // l_lnno
414     }
415     
416     public static final short N_UNDEF = 0;
417     public static final short N_ABS   = -1;
418     public static final short N_DEBUG = -2;
419     
420     public static final char T_NULL   = 0x00;
421     public static final char T_VOID   = 0x01;
422     public static final char T_CHAR   = 0x02;
423     public static final char T_SHORT  = 0x03;
424     public static final char T_INT    = 0x04;
425     public static final char T_LONG   = 0x05;
426     public static final char T_FLOAT  = 0x06;
427     public static final char T_DOUBLE = 0x07;
428     public static final char T_STRUCT = 0x08;
429     public static final char T_UNION  = 0x09;
430     public static final char T_ENUM   = 0x0A;
431     public static final char T_MOE    = 0x0B;
432     public static final char T_UCHAR  = 0x0C;
433     public static final char T_USHORT = 0x0D;
434     public static final char T_UINT   = 0x0E;
435     public static final char T_ULONG  = 0x0F;
436     public static final char T_LNGDBL = 0x10;
437     
438     public static final char DT_NON = 0x0000;
439     public static final char DT_PTR = 0x0100;
440     public static final char DT_FCN = 0x0200;
441     public static final char DT_ARY = 0x0300;
442 
443     public static final byte C_NULL   = 0;
444     public static final byte C_AUTO   = 1;
445     public static final byte C_EXT    = 2;
446     public static final byte C_STAT   = 3;
447     public static final byte C_REG    = 4;
448     public static final byte C_EXTDEF = 5;
449     public static final byte C_LABEL  = 6;
450     public static final byte C_ULABEL = 7;
451     public static final byte C_MOS     = 8;
452     public static final byte C_ARG     = 9;
453     public static final byte C_STRTAG  = 10;
454     public static final byte C_MOU     = 11;
455     public static final byte C_UNTAG   = 12;
456     public static final byte C_TPDEF   = 13;
457     public static final byte C_USTATIC = 14;
458     public static final byte C_ENTAG   = 15;
459     public static final byte C_MOE     = 16;
460     public static final byte C_REGPARM = 17;
461     public static final byte C_FIELD   = 18;
462     public static final byte C_AUTOARG = 19;
463     public static final byte C_LASTENT = 20;
464     public static final byte C_BLOCK   = 100;
465     public static final byte C_FCN     = 101;
466     public static final byte C_EOS     = 102;
467     public static final byte C_FILE    = 103;
468     public static final byte C_SECTION = 104;
469     public static final byte C_WEAKEXT = 105;
470     public static final byte C_EFCN    = -1;
471     
472     public void dumpSECTIONSYMENTs(ExtendedDataOutput out)
473     throws IOException {
474         write_bytes(out, ".text", 8);
475         out.writeUInt(0);
476         out.writeShort((short)1);
477         out.writeUShort((char)0);
478         out.writeUByte(C_STAT);
479         out.writeUByte(0);
480         
481         write_bytes(out, ".data", 8);
482         out.writeUInt(0);
483         out.writeShort((short)2);
484         out.writeUShort((char)0);
485         out.writeUByte(C_STAT);
486         out.writeUByte(0);
487     }
488     
489     public static boolean USE_MICROSOFT_STYLE_MUNGE = true;
490     
491     public static final int NUM_OF_EXTERNAL_SYMS = 7;
492     public void dumpEXTSYMENTs(ExtendedDataOutput out, jq_StaticMethod rootm)
493     throws IOException {
494         // NOTE!!! If you change anything here, be SURE to change the number above!!!
495         String s;
496         if (USE_MICROSOFT_STYLE_MUNGE) s = "_entry@0";
497         else s = "entry";
498         write_bytes(out, s, 8);  // s_name
499         CodeAddress addr = rootm.getDefaultCompiledVersion().getEntrypoint();
500         out.writeUInt(addr.to32BitValue());
501         out.writeShort((short)1);
502         out.writeUShort((char)DT_FCN);
503         out.writeUByte(C_EXT);
504         out.writeUByte(0);
505         
506         out.writeUInt(0);    // e_zeroes
507         if (USE_MICROSOFT_STYLE_MUNGE) s = "_trap_handler@4";
508         else s = "trap_handler";
509         int idx = alloc_string(s);
510         out.writeUInt(idx);  // e_offset
511         addr = ExceptionDeliverer._trap_handler.getDefaultCompiledVersion().getEntrypoint();
512         out.writeUInt(addr.to32BitValue());
513         out.writeShort((short)1);
514         out.writeUShort((char)DT_FCN);
515         out.writeUByte(C_EXT);
516         out.writeUByte(0);
517 
518         out.writeUInt(0);    // e_zeroes
519         if (USE_MICROSOFT_STYLE_MUNGE) s = "_debug_trap_handler@4";
520         else s = "debug_trap_handler";
521         idx = alloc_string(s);
522         out.writeUInt(idx);  // e_offset
523         addr = ExceptionDeliverer._debug_trap_handler.getDefaultCompiledVersion().getEntrypoint();
524         out.writeUInt(addr.to32BitValue());
525         out.writeShort((short)1);
526         out.writeUShort((char)DT_FCN);
527         out.writeUByte(C_EXT);
528         out.writeUByte(0);
529         
530         out.writeUInt(0);    // e_zeroes
531         if (USE_MICROSOFT_STYLE_MUNGE) s = "_threadSwitch@4";
532         else s = "threadSwitch";
533         idx = alloc_string(s);
534         out.writeUInt(idx);  // e_offset
535         addr = jq_NativeThread._threadSwitch.getDefaultCompiledVersion().getEntrypoint();
536         out.writeUInt(addr.to32BitValue());
537         out.writeShort((short)1);
538         out.writeUShort((char)DT_FCN);
539         out.writeUByte(C_EXT);
540         out.writeUByte(0);
541         
542         out.writeUInt(0);    // e_zeroes
543         if (USE_MICROSOFT_STYLE_MUNGE) s = "_ctrl_break_handler@0";
544         else s = "ctrl_break_handler";
545         idx = alloc_string(s);
546         out.writeUInt(idx);  // e_offset
547         addr = jq_NativeThread._ctrl_break_handler.getDefaultCompiledVersion().getEntrypoint();
548         out.writeUInt(addr.to32BitValue());
549         out.writeShort((short)1);
550         out.writeUShort((char)DT_FCN);
551         out.writeUByte(C_EXT);
552         out.writeUByte(0);
553 
554         out.writeUInt(0);    // e_zeroes
555         if (USE_MICROSOFT_STYLE_MUNGE) s = "_joeq_code_startaddress";
556         else s = "joeq_code_startaddress";
557         idx = alloc_string(s);
558         out.writeUInt(idx);  // e_offset
559         out.writeUInt(0);
560         out.writeShort((short)1);
561         out.writeUShort((char)(DT_PTR | T_VOID));
562         out.writeUByte(C_EXT);
563         out.writeUByte(0);
564 
565         out.writeUInt(0);    // e_zeroes
566         if (USE_MICROSOFT_STYLE_MUNGE) s = "_joeq_data_startaddress";
567         else s = "joeq_data_startaddress";
568         idx = alloc_string(s);
569         out.writeUInt(idx); // e_offset
570         out.writeUInt(0); // e_value
571         out.writeShort((short)2); // e_scnum
572         out.writeUShort((char)(DT_PTR | T_VOID)); // e_type
573         out.writeUByte(C_EXT); // e_sclass
574         out.writeUByte(0); // e_numaux
575     }
576     
577     public void dumpEXTDEFSYMENTs(ExtendedDataOutput out, List extrefs)
578     throws IOException {
579         Iterator i = extrefs.iterator();
580         int k = 2+NUM_OF_EXTERNAL_SYMS;
581         while (i.hasNext()) {
582             ExternalReference extref = (ExternalReference)i.next();
583             Assert._assert(extref.getSymbolIndex() == k);
584             String name = extref.getName();
585             if (name.length() <= 8) {
586                 write_bytes(out, name, 8);  // s_name
587             } else {
588                 out.writeUInt(0);    // e_zeroes
589                 int idx = alloc_string(name);
590                 out.writeUInt(idx);  // e_offset
591             }
592             out.writeUInt(0);
593             out.writeShort((short)0);
594             out.writeUShort((char)DT_FCN);
595             out.writeUByte(C_EXT);
596             out.writeUByte(0);
597             ++k;
598         }
599     }
600     
601     public void dumpSFIELDSYMENT(ExtendedDataOutput out, jq_StaticField sf)
602     throws IOException {
603         //String name = sf.getName().toString();
604         String name = mungeMemberName(sf);
605         if (name.length() <= 8) {
606             write_bytes(out, name, 8);  // s_name
607         } else {
608             out.writeUInt(0);    // e_zeroes
609             int idx = alloc_string(name);
610             out.writeUInt(idx);  // e_offset
611         }
612         HeapAddress addr = sf.getAddress();
613         out.writeUInt(addr.to32BitValue()); // e_value
614         out.writeShort((short)2); // e_scnum
615         jq_Type t = sf.getType();
616         char type = (char)0;
617         if (t.isArrayType()) {
618             t = ((jq_Array)t).getElementType();
619             type = DT_ARY;
620         } else if (t.isReferenceType()) {
621             type = DT_PTR;
622         }
623         if (t.isPrimitiveType()) {
624             if (t == jq_Primitive.INT) type |= T_LONG;
625             else if (t == jq_Primitive.LONG) type |= T_LNGDBL;
626             else if (t == jq_Primitive.FLOAT) type |= T_FLOAT;
627             else if (t == jq_Primitive.DOUBLE) type |= T_DOUBLE;
628             else if (t == jq_Primitive.BYTE) type |= T_CHAR;
629             else if (t == jq_Primitive.BOOLEAN) type |= T_UCHAR;
630             else if (t == jq_Primitive.SHORT) type |= T_SHORT;
631             else if (t == jq_Primitive.CHAR) type |= T_USHORT;
632             else Assert.UNREACHABLE();
633         } else {
634             type |= T_STRUCT;
635         }
636         out.writeUShort(type);  // e_type
637         out.writeUByte(C_STAT); // e_sclass
638         out.writeUByte(0);      // e_numaux
639     }
640 
641     public void dumpIFIELDSYMENT(ExtendedDataOutput out, jq_InstanceField f)
642     throws IOException {
643         String name = f.getName().toString();
644         if (name.length() <= 8) {
645             write_bytes(out, name, 8);  // s_name
646         } else {
647             out.writeUInt(0);    // e_zeroes
648             int idx = alloc_string(name);
649             out.writeUInt(idx);  // e_offset
650         }
651         int off = f.getOffset();
652         out.writeUInt(off);      // e_value
653         out.writeShort((short)2); // e_scnum
654         jq_Type t = f.getType();
655         char type = (char)0;
656         if (t.isArrayType()) {
657             t = ((jq_Array)t).getElementType();
658             type = DT_ARY;
659         } else if (t.isReferenceType()) {
660             type = DT_PTR;
661         }
662         if (t.isPrimitiveType()) {
663             if (t == jq_Primitive.INT) type |= T_LONG;
664             else if (t == jq_Primitive.LONG) type |= T_LNGDBL;
665             else if (t == jq_Primitive.FLOAT) type |= T_FLOAT;
666             else if (t == jq_Primitive.DOUBLE) type |= T_DOUBLE;
667             else if (t == jq_Primitive.BYTE) type |= T_CHAR;
668             else if (t == jq_Primitive.BOOLEAN) type |= T_UCHAR;
669             else if (t == jq_Primitive.SHORT) type |= T_SHORT;
670             else if (t == jq_Primitive.CHAR) type |= T_USHORT;
671             else Assert.UNREACHABLE();
672         } else {
673             type |= T_STRUCT;
674         }
675         out.writeUShort(type); // e_type
676         out.writeUByte(C_MOS); // e_sclass
677         out.writeUByte(0);     // e_numaux
678     }
679     
680     public void dumpMETHODSYMENT(ExtendedDataOutput out, jq_CompiledCode cc)
681     throws IOException {
682         jq_Method m = cc.getMethod();
683         String name;
684         if (m == null) {
685             name = "unknown@"+cc.getEntrypoint().stringRep();
686         } else { 
687             //name = m.getName().toString();
688             name = mungeMemberName(m);
689         }
690         if (name.length() <= 8) {
691             write_bytes(out, name, 8);    // s_name
692         } else {
693             out.writeUInt(0);          // e_zeroes
694             int idx = alloc_string(name);
695             out.writeUInt(idx);        // e_offset
696         }
697         CodeAddress addr = cc.getEntrypoint();
698         out.writeUInt(addr.to32BitValue()); // e_value
699         out.writeShort((short)1);      // e_scnum
700         out.writeUShort((char)DT_FCN); // e_type
701         out.writeUByte(C_EXT);         // e_sclass
702         out.writeUByte(0);             // e_numaux
703     }
704     
705     public void addSystemInterfaceRelocs_COFF(List extref, List heap2code) {
706         jq_StaticField[] fs = SystemInterface._class.getDeclaredStaticFields();
707         int total = 1+NUM_OF_EXTERNAL_SYMS;
708         for (int i=0; i<fs.length; ++i) {
709             jq_StaticField f = fs[i];
710             if (f.isFinal()) continue;
711             if (f.getType() != CodeAddress._class) continue;
712             {
713                 String name = f.getName().toString();
714                 int ind = name.lastIndexOf('_');
715                 if (USE_MICROSOFT_STYLE_MUNGE)
716                     name = "_"+name.substring(0, ind)+"@"+name.substring(ind+1);
717                 else
718                     name = name.substring(0, ind);
719                 if (TRACE) System.out.println("External ref="+f+", symndx="+(total+1)+" address="+f.getAddress().stringRep());
720                 ExternalReference r = new ExternalReference(f.getAddress(), name);
721                 r.setSymbolIndex(++total);
722                 extref.add(r);
723                 heap2code.add(r);
724             }
725         }
726         //return total-3;
727     }
728 
729     public void addSystemInterfaceRelocs_ELF(List extref, List heap2code) {
730         jq_StaticField[] fs = SystemInterface._class.getDeclaredStaticFields();
731         int total = 1+NUM_OF_EXTERNAL_SYMS;
732         for (int i=0; i<fs.length; ++i) {
733             jq_StaticField f = fs[i];
734             if (f.isFinal()) continue;
735             if (f.getType() != CodeAddress._class) continue;
736             {
737                 String name = f.getName().toString();
738                 int ind = name.lastIndexOf('_');
739                 name = name.substring(0, ind);
740                 if (TRACE) System.out.println("External ref="+f+", symndx="+(total+1)+" address="+f.getAddress().stringRep());
741                 ExternalReference r = new ExternalReference(f.getAddress(), name);
742                 r.setSymbolIndex(++total);
743                 extref.add(r);
744                 heap2code.add(r);
745             }
746         }
747     }
748     
749     public int addVTableRelocs(List list) {
750         int total = 0;
751         Iterator i = jq.boot_types.iterator();
752         while (i.hasNext()) {
753             jq_Type t = (jq_Type)i.next();
754             if (t.isReferenceType()) {
755                 if (t == Unsafe._class) continue;
756                 try {
757                     if (TRACE) System.out.println("Adding vtable relocs for: "+t);
758                     Address[] vtable = (Address[])((jq_Reference)t).getVTable();
759                     HeapAddress addr = getAddressOf(vtable);
760                     //jq.Assert(vtable[0] != 0, t.toString());
761                     Heap2HeapReference r1 = new Heap2HeapReference(addr, (HeapAddress) vtable[0]);
762                     list.add(r1);
763                     for (int j=1; j<vtable.length; ++j) {
764                         Heap2CodeReference r2 = new Heap2CodeReference((HeapAddress) addr.offset(CodeAddress.size()*j), (CodeAddress) vtable[j]);
765                         list.add(r2);
766                     }
767                     total += vtable.length;
768                 } catch (UnknownObjectException x) {
769                     x.appendMessage("vtable for "+t);
770                     x.setObject(null);
771                     throw x;
772                 }
773             }
774         }
775         return total;
776     }
777     
778     public void dumpCOFF(ExtendedDataOutput out, jq_StaticMethod rootm) throws IOException {
779         
780         final List text_relocs1 = bca.getAllCodeRelocs();
781         final List text_relocs2 = bca.getAllDataRelocs();
782         
783         Iterator i = text_relocs1.iterator();
784         while (i.hasNext()) {
785             Object r = i.next();
786             ((Reloc)r).patch();
787             // directly bound calls do not need to be relocated,
788             // because they are relative offsets, not absolute addresses.
789             if (r instanceof DirectBindCall)
790                 i.remove();
791         }
792         
793         // calculate sizes/offsets
794         final int textsize = bca.size();
795         final List exts = new LinkedList();
796         final int nlinenum = 0;
797         int ntextreloc = text_relocs1.size() + text_relocs2.size();
798         if (ntextreloc > 65535) ++ntextreloc;
799         final int datastart = 20+40+40+textsize+(10*ntextreloc);
800         final int datasize = heapCurrent;
801         final int numOfVTableRelocs = addVTableRelocs(data_relocs);
802         addSystemInterfaceRelocs_COFF(exts, data_relocs);
803         int ndatareloc = data_relocs.size();
804         if (ndatareloc > 65535) ++ndatareloc;
805         final int symtabstart = datastart+datasize+(10*ndatareloc)+(10*nlinenum);
806         final int num_ccs = CodeAllocator.getNumberOfCompiledMethods();
807         final int nsyms = 2+NUM_OF_EXTERNAL_SYMS+num_ccs+exts.size();
808         
809         if (TRACE) {
810             System.out.println("Text size="+textsize);
811             System.out.println("Num text relocs="+ntextreloc);
812             System.out.println("Data start="+datastart);
813             System.out.println("Data size="+datasize);
814             System.out.println("Num of VTable relocs="+numOfVTableRelocs);
815             System.out.println("Num data relocs="+ntextreloc);
816             System.out.println("Sym tab start="+symtabstart);
817             System.out.println("Num syms="+nsyms);
818         }
819         
820         // write file header
821         dumpFILHDR(out, symtabstart, nsyms);
822         
823         // write section headers
824         dumpTEXTSCNHDR(out, textsize, ntextreloc);
825         dumpDATASCNHDR(out, datastart, datasize, ndatareloc);
826         
827         // write text section
828         bca.dump(out);
829         
830         // write text relocs
831         if (ntextreloc > 65535) {
832             out.writeUInt(ntextreloc);
833             out.writeUInt(0);
834             out.writeUShort((char)0);
835         }
836         Iterator it = text_relocs1.iterator();
837         while (it.hasNext()) {
838             Reloc r = (Reloc)it.next();
839             r.dumpCOFF(out);
840         }
841         it = text_relocs2.iterator();
842         while (it.hasNext()) {
843             Reloc r = (Reloc)it.next();
844             r.dumpCOFF(out);
845         }
846         //out.flush();
847         
848         // write data section
849         try {
850             dumpHeap(out);
851         } catch (UnknownObjectException x) {
852             Object u = x.getObject();
853             HashSet visited = new HashSet();
854             findReferencePath(u, x, visited);
855             throw x;
856         }
857         
858         // write data relocs
859         int j=0;
860         if (ndatareloc > 65535) {
861             out.writeUInt(ndatareloc);
862             out.writeUInt(0);
863             out.writeUShort((char)0);
864             ++j;
865         }
866         it = data_relocs.iterator();
867         while (it.hasNext()) {
868             if ((j % UPDATE_PERIOD) == 0) {
869                 BootImage.out.print("Written: "+j+"/"+ndatareloc+" relocations\r");
870             }
871             Reloc r = (Reloc)it.next();
872             r.dumpCOFF(out);
873             ++j;
874         }
875         BootImage.out.println("Written: "+ndatareloc+" relocations                    \n");
876         Assert._assert(j == ndatareloc);
877         
878         // write line numbers
879         
880         // write symbol table
881         dumpSECTIONSYMENTs(out);
882         dumpEXTSYMENTs(out, rootm);
883         dumpEXTDEFSYMENTs(out, exts);
884         it = CodeAllocator.getCompiledMethods();
885         j=0;
886         while (it.hasNext()) {
887             jq_CompiledCode r = (jq_CompiledCode)it.next();
888             dumpMETHODSYMENT(out, r);
889             ++j;
890         }
891         Assert._assert(j == num_ccs);
892         
893         // write string table
894         dump_strings(out);
895         
896         //out.flush();
897     }
898 
899     static class UnknownObjectException extends RuntimeException {
900         Object o; StringBuffer message;
901         UnknownObjectException(Object o) {
902             this.o = o;
903             this.message = new StringBuffer();
904             this.message.append("type: ");
905             this.message.append(o.getClass().toString());
906             this.message.append(" address: ");
907             this.message.append(Strings.hex(System.identityHashCode(o)));
908             this.message.append(' ');
909         }
910         void setObject(Object o) { this.o = o; }
911         Object getObject() { return o; }
912         void prependMessage(String s) {
913             StringBuffer sb = new StringBuffer();
914             sb.append(s);
915             sb.append(this.message);
916             this.message = sb;
917         }
918         void appendMessage(String s) { this.message.append(s); }
919         public String toString() { return this.message.toString(); }
920     }
921 
922     private jq_StaticField searchStaticVariables(Object p) {
923         Iterator i = PrimordialClassLoader.loader.getAllTypes().iterator();
924         while (i.hasNext()) {
925             Object o = i.next();
926             if (!(o instanceof jq_Class)) continue;
927             jq_Class k = (jq_Class)o;
928             if (!k.isLoaded()) continue;
929             jq_StaticField[] fs = k.getDeclaredStaticFields();
930             for (int j=0; j<fs.length; ++j) {
931                 jq_StaticField f = fs[j];
932                 if (f.getType().isAddressType()) {
933                     // not a possible path.
934                 } else if (f.getType().isReferenceType()) {
935                     Object val = Reflection.getstatic_A(f);
936                     if (val == p) return f;
937                 }
938             }
939         }
940         return null;
941     }
942 
943     private boolean findReferencePath(Object p, UnknownObjectException x, HashSet visited) {
944         jq_StaticField sf = searchStaticVariables(p);
945         if (sf != null) {
946             x.appendMessage(sf.getDeclaringClass()+"."+sf.getName());
947             return true;
948         }
949         Iterator i = entries.iterator();
950         while (i.hasNext()) {
951             Entry e = (Entry)i.next();
952             Object o = e.getObject();
953             IdentityHashCodeWrapper w = IdentityHashCodeWrapper.create(o);
954             if (visited.contains(w)) continue;
955             Class objType = o.getClass();
956             jq_Reference jqType = (jq_Reference)Reflection.getJQType(objType);
957             if (jqType.isArrayType()) {
958                 jq_Type elemType = ((jq_Array)jqType).getElementType();
959                 if (elemType.isAddressType()) {
960                     // not a possible path.
961                 } else if (elemType.isReferenceType()) {
962                     int length = Array.getLength(o);
963                     Object[] v = (Object[])o;
964                     for (int k=0; k<length; ++k) {
965                         Object o2 = Reflection.arrayload_A(v, k);
966                         if (o2 == p) {
967                             System.err.println("Possible path: ["+k+"]");
968                             visited.add(w);
969                             if (findReferencePath(o, x, visited)) {
970                                 x.appendMessage("["+k+"]");
971                                 return true;
972                             } else {
973                                 System.err.println("Backtracking ["+k+"]");
974                             }
975                         }
976                     }
977                 }
978             } else {
979                 Assert._assert(jqType.isClassType());
980                 jq_Class clazz = (jq_Class)jqType;
981                 jq_InstanceField[] fields = clazz.getInstanceFields();
982                 for (int k=0; k<fields.length; ++k) {
983                     jq_InstanceField f = fields[k];
984                     jq_Type ftype = f.getType();
985                     if (ftype.isAddressType()) {
986                         // not a possible path.
987                     } else if (ftype.isReferenceType()) {
988                         Object val = Reflection.getfield_A(o, f);
989                         if (val == p) {
990                             System.err.println("Possible path: ."+f.getName());
991                             visited.add(w);
992                             if (findReferencePath(o, x, visited)) {
993                                 x.appendMessage("."+f.getName());
994                                 return true;
995                             } else {
996                                 System.err.println("Backtracking ."+f.getName());
997                             }
998                         }
999                     }
1000                }
1001            }
1002        }
1003        return false;
1004    }
1005    
1006    private void dumpHeap(ExtendedDataOutput out)
1007    throws IOException {
1008        Assert._assert(ObjectLayout.ARRAY_LENGTH_OFFSET == -12);
1009        Assert._assert(ObjectLayout.STATUS_WORD_OFFSET == -8);
1010        Assert._assert(ObjectLayout.VTABLE_OFFSET == -4);
1011        Assert._assert(ObjectLayout.OBJ_HEADER_SIZE == 8);
1012        Assert._assert(ObjectLayout.ARRAY_HEADER_SIZE == 12);
1013        Iterator i = entries.iterator();
1014        int currentAddr=0;
1015        int j=0;
1016        while (i.hasNext()) {
1017        if ((j % UPDATE_PERIOD) == 0) {
1018        System.out.print("Written: "+j+"/"+entries.size()+" objects, "+currentAddr+"/"+heapCurrent+" bytes\r");
1019        }
1020            Entry e = (Entry)i.next();
1021            Object o = e.getObject();
1022            HeapAddress addr = e.getAddress();
1023            Class objType = o.getClass();
1024            jq_Reference jqType = (jq_Reference)Reflection.getJQType(objType);
1025            if (TRACE)
1026                BootImage.out.println("Dumping entry "+j+": "+objType+" "+Strings.hex(System.identityHashCode(o))+" addr "+addr.stringRep());
1027            Assert._assert(!jqType.isAddressType());
1028            if (!jqType.isClsInitialized()) {
1029                Assert.UNREACHABLE(jqType.toString());
1030                return;
1031            }
1032            HeapAddress vtable;
1033            try { vtable = getAddressOf(jqType.getVTable()); }
1034            catch (UnknownObjectException x) {
1035                x.appendMessage("vtable for "+jqType);  
1036                x.setObject(null);
1037                throw x;
1038            }
1039            if (jqType.isArrayType()) {
1040                while (currentAddr+ObjectLayout.ARRAY_HEADER_SIZE < addr.to32BitValue()) {
1041                    out.writeByte((byte)0); ++currentAddr;
1042                }
1043                int length = Array.getLength(o);
1044                out.writeUInt(length);
1045                out.writeUInt(0);
1046                out.writeUInt(vtable.to32BitValue());
1047                currentAddr += ObjectLayout.ARRAY_HEADER_SIZE;
1048                Assert._assert(addr.to32BitValue() == currentAddr);
1049                jq_Type elemType = ((jq_Array)jqType).getElementType();
1050                if (elemType.isPrimitiveType()) {
1051                    if (elemType == jq_Primitive.INT) {
1052                        int[] v = (int[])o;
1053                        for (int k=0; k<length; ++k)
1054                            out.writeUInt(v[k]);
1055                        currentAddr += length << 2;
1056                    } else if (elemType == jq_Primitive.FLOAT) {
1057                        float[] v = (float[])o;
1058                        for (int k=0; k<length; ++k)
1059                            out.writeUInt(Float.floatToRawIntBits(v[k]));
1060                        currentAddr += length << 2;
1061                    } else if (elemType == jq_Primitive.LONG) {
1062                        long[] v = (long[])o;
1063                        for (int k=0; k<length; ++k)
1064                            out.writeULong(v[k]);
1065                        currentAddr += length << 3;
1066                    } else if (elemType == jq_Primitive.DOUBLE) {
1067                        double[] v = (double[])o;
1068                        for (int k=0; k<length; ++k)
1069                            out.writeULong(Double.doubleToRawLongBits(v[k]));
1070                        currentAddr += length << 3;
1071                    } else if (elemType == jq_Primitive.BOOLEAN) {
1072                        boolean[] v = (boolean[])o;
1073                        for (int k=0; k<length; ++k)
1074                            out.writeUByte(v[k]?1:0);
1075                        currentAddr += length;
1076                    } else if (elemType == jq_Primitive.BYTE) {
1077                        byte[] v = (byte[])o;
1078                        for (int k=0; k<length; ++k)
1079                            out.writeByte(v[k]);
1080                        currentAddr += length;
1081                    } else if (elemType == jq_Primitive.SHORT) {
1082                        short[] v = (short[])o;
1083                        for (int k=0; k<length; ++k)
1084                            out.writeShort(v[k]);
1085                        currentAddr += length << 1;
1086                    } else if (elemType == jq_Primitive.CHAR) {
1087                        char[] v = (char[])o;
1088                        for (int k=0; k<length; ++k)
1089                            out.writeUShort(v[k]);
1090                        currentAddr += length << 1;
1091                    } else Assert.UNREACHABLE();
1092                } else if (elemType.isAddressType()) {
1093                    Address[] v = (Address[])o;
1094                    for (int k=0; k<length; ++k) {
1095                        out.writeUInt(v[k]==null?0:v[k].to32BitValue());
1096                    }
1097                    currentAddr += length << 2;
1098                } else {
1099                    Object[] v = (Object[])o;
1100                    for (int k=0; k<length; ++k) {
1101                        Object o2 = Reflection.arrayload_A(v, k);
1102                        try { out.writeUInt(getAddressOf(o2).to32BitValue()); }
1103                        catch (UnknownObjectException x) {
1104                            System.err.println("Object array element #"+k);
1105                            //x.appendMessage("Object array element #"+k+" in ");
1106                            //x.setObject(v);
1107                            throw x;
1108                        }
1109                    }
1110                    currentAddr += length << 2;
1111                }
1112            } else {
1113                Assert._assert(jqType.isClassType());
1114                jq_Class clazz = (jq_Class)jqType;
1115                while (currentAddr+ObjectLayout.OBJ_HEADER_SIZE < addr.to32BitValue()) {
1116                    out.writeByte((byte)0); ++currentAddr;
1117                }
1118                out.writeUInt(0);
1119                out.writeUInt(vtable.to32BitValue());
1120                currentAddr += 8;
1121                Assert._assert(addr.to32BitValue() == currentAddr);
1122                jq_InstanceField[] fields = clazz.getInstanceFields();
1123                for (int k=0; k<fields.length; ++k) {
1124                    jq_InstanceField f = fields[k];
1125                    jq_Type ftype = f.getType();
1126                    int foffset = f.getOffset();
1127                    if (TRACE) BootImage.out.println("Field "+f+" offset "+Strings.shex(foffset)+": "+System.identityHashCode(Reflection.getfield(o, f)));
1128                    while (currentAddr != addr.offset(foffset).to32BitValue()) {
1129                        out.writeByte((byte)0); ++currentAddr;
1130                    }
1131                    if (ftype.isPrimitiveType()) {
1132                        if (ftype == jq_Primitive.INT)
1133                            out.writeUInt(Reflection.getfield_I(o, f));
1134                        else if (ftype == jq_Primitive.FLOAT)
1135                            out.writeUInt(Float.floatToRawIntBits(Reflection.getfield_F(o, f)));
1136                        else if (ftype == jq_Primitive.LONG)
1137                            out.writeULong(Reflection.getfield_L(o, f));
1138                        else if (ftype == jq_Primitive.DOUBLE)
1139                            out.writeULong(Double.doubleToRawLongBits(Reflection.getfield_D(o, f)));
1140                        else if (ftype == jq_Primitive.BOOLEAN)
1141                            out.writeUByte(Reflection.getfield_Z(o, f)?1:0);
1142                        else if (ftype == jq_Primitive.BYTE)
1143                            out.writeByte(Reflection.getfield_B(o, f));
1144                        else if (ftype == jq_Primitive.SHORT)
1145                            out.writeShort(Reflection.getfield_S(o, f));
1146                        else if (ftype == jq_Primitive.CHAR)
1147                            out.writeUShort(Reflection.getfield_C(o, f));
1148                        else Assert.UNREACHABLE();
1149                    } else if (ftype.isAddressType()) {
1150                        Address a = Reflection.getfield_P(o, f);
1151                        out.writeUInt(a==null?0:a.to32BitValue());
1152                    } else {
1153                        try { out.writeUInt(getAddressOf(Reflection.getfield_A(o, f)).to32BitValue()); }
1154                        catch (UnknownObjectException x) {
1155                            System.err.println("Instance field "+f);
1156                            //x.appendMessage("field "+f.getName()+" in ");
1157                            //x.setObject(o);
1158                            throw x;
1159                        }
1160                    }
1161                    currentAddr += f.getSize();
1162                }
1163            }
1164            ++j;
1165        }
1166        while (currentAddr < heapCurrent) {
1167            out.writeByte((byte)0); ++currentAddr;
1168        }
1169        System.out.println("Written: "+j+" objects, "+heapCurrent+" bytes                    ");
1170    }
1171    
1172    public static void write_bytes(ExtendedDataOutput out, String s, int len)
1173    throws IOException {
1174        Assert._assert(s.length() <= len);
1175        int i;
1176        for (i=0; ; ++i) {
1177            if (i == s.length()) {
1178                for (; i<len; ++i) {
1179                    out.write((byte)0);
1180                }
1181                return;
1182            }
1183            out.write((byte)s.charAt(i));
1184        }
1185    }
1186    
1187    private String mungeMemberName(jq_Member m) {
1188        String name = m.getDeclaringClass().getName().toString() +
1189                      "_"+m.getName()+
1190                      "_"+m.getDesc();
1191        return name;
1192    }
1193    
1194    int stringTableOffset = 4;
1195    List stringTable = new LinkedList();
1196    private int alloc_string(String name) {
1197        int off = stringTableOffset;
1198        byte[] b = SystemInterface.toCString(name);
1199        stringTable.add(b);
1200        stringTableOffset += b.length;
1201        return off;
1202    }
1203
1204    private void dump_strings(ExtendedDataOutput out)
1205    throws IOException {
1206        Iterator i = stringTable.iterator();
1207        out.writeUInt(stringTableOffset);
1208        while (i.hasNext()) {
1209            byte[] b = (byte[])i.next();
1210            out.write(b);
1211        }
1212    }
1213
1214    
1215    public void dumpELF(ExtendedDataOutput out, jq_StaticMethod rootm) throws IOException {
1216        final List text_relocs1 = bca.getAllCodeRelocs();
1217        final List text_relocs2 = bca.getAllDataRelocs();
1218        Iterator i = text_relocs1.iterator();
1219        while (i.hasNext()) {
1220            Object r = i.next();
1221            ((Reloc)r).patch();
1222            // directly bound calls do not need to be relocated,
1223            // because they are relative offsets, not absolute addresses.
1224            if (r instanceof DirectBindCall)
1225                i.remove();
1226        }
1227
1228        System.out.print("Initializing ELF data structures...");
1229        long time = System.currentTimeMillis();
1230        final int datasize = heapCurrent;
1231        ELFOutput f = new ELFOutput(ELFDATA2LSB, ET_REL, EM_386, 0, out);
1232        f.setLittleEndian();
1233        Section.NullSection empty = Section.NullSection.INSTANCE;
1234        Section.StrTabSection shstrtab = new Section.StrTabSection(".shstrtab", 0, 0);
1235        Section.StrTabSection strtab = new Section.StrTabSection(".strtab", 0, 0);
1236        Section.SymTabSection symtab = new Section.SymTabSection(".symtab", 0, 0, strtab);
1237        Section.ProgBitsSection text = new TextSection();
1238        Section.ProgBitsSection data = new DataSection();
1239        Section.RelSection textrel = new Section.RelSection(".rel.text", 0, 0, symtab, text);
1240        Section.RelSection datarel = new Section.RelSection(".rel.data", 0, 0, symtab, data);
1241        f.setSectionHeaderStringTable(shstrtab);
1242        //f.setSymbolStringTable(strtab);
1243        f.addSection(empty);
1244        f.addSection(shstrtab);
1245        f.addSection(strtab);
1246        f.addSection(symtab);
1247        f.addSection(text);
1248        f.addSection(data);
1249        f.addSection(textrel);
1250        f.addSection(datarel);
1251
1252        final List exts = new LinkedList();
1253        final int numOfVTableRelocs = addVTableRelocs(data_relocs);
1254        addSystemInterfaceRelocs_ELF(exts, data_relocs);
1255
1256        symtab.addSymbol(new SymbolTableEntry("", 0, 0, SymbolTableEntry.STB_LOCAL, SymbolTableEntry.STT_NOTYPE, empty));
1257        
1258        SymbolTableEntry textsyment = new SymbolTableEntry("", 0, 0, SymbolTableEntry.STB_LOCAL, SymbolTableEntry.STT_SECTION, text);
1259        SymbolTableEntry datasyment = new SymbolTableEntry("", 0, 0, SymbolTableEntry.STB_LOCAL, SymbolTableEntry.STT_SECTION, data);
1260        symtab.addSymbol(textsyment);
1261        symtab.addSymbol(datasyment);
1262
1263        Iterator it = exts.iterator();
1264        while (it.hasNext()) {
1265            ExternalReference r = (ExternalReference)it.next();
1266            SymbolTableEntry e = new SymbolTableEntry(r.getName(), 0, 0, SymbolTableEntry.STB_GLOBAL, SymbolTableEntry.STT_FUNC, empty);
1267            symtab.addSymbol(e);
1268            datarel.addReloc(new RelocEntry(r.getAddress().to32BitValue(), e, RelocEntry.R_386_32));
1269        }
1270
1271        it = CodeAllocator.getCompiledMethods();
1272        while (it.hasNext()) {
1273            jq_CompiledCode cc = (jq_CompiledCode)it.next();
1274            jq_Method m = cc.getMethod();
1275            String name;
1276            if (m == null) {
1277                name = "unknown@"+cc.getEntrypoint().stringRep();
1278            } else {
1279                name = mungeMemberName(m);
1280            }
1281            SymbolTableEntry e = new SymbolTableEntry(name, cc.getEntrypoint().to32BitValue(), cc.getLength(), STB_LOCAL, STT_FUNC, text);
1282            symtab.addSymbol(e);
1283        }
1284
1285        {
1286            jq_CompiledCode cc = rootm.getDefaultCompiledVersion();
1287            SymbolTableEntry e = new SymbolTableEntry("entry", cc.getEntrypoint().to32BitValue(), cc.getLength(), STB_GLOBAL, STT_FUNC, text);
1288            symtab.addSymbol(e);
1289
1290            cc = ExceptionDeliverer._trap_handler.getDefaultCompiledVersion();
1291            e = new SymbolTableEntry("trap_handler", cc.getEntrypoint().to32BitValue(), cc.getLength(), STB_GLOBAL, STT_FUNC, text);
1292            symtab.addSymbol(e);
1293
1294            cc = ExceptionDeliverer._debug_trap_handler.getDefaultCompiledVersion();
1295            e = new SymbolTableEntry("debug_trap_handler", cc.getEntrypoint().to32BitValue(), cc.getLength(), STB_GLOBAL, STT_FUNC, text);
1296            symtab.addSymbol(e);
1297            
1298            cc = jq_NativeThread._threadSwitch.getDefaultCompiledVersion();
1299            e = new SymbolTableEntry("threadSwitch", cc.getEntrypoint().to32BitValue(), cc.getLength(), STB_GLOBAL, STT_FUNC, text);
1300            symtab.addSymbol(e);
1301
1302            cc = jq_NativeThread._ctrl_break_handler.getDefaultCompiledVersion();
1303            e = new SymbolTableEntry("ctrl_break_handler", cc.getEntrypoint().to32BitValue(), cc.getLength(), STB_GLOBAL, STT_FUNC, text);
1304            symtab.addSymbol(e);
1305
1306            e = new SymbolTableEntry("joeq_code_startaddress", 0, 0, STB_GLOBAL, STT_OBJECT, text);
1307            symtab.addSymbol(e);
1308
1309            e = new SymbolTableEntry("joeq_data_startaddress", 0, 0, STB_GLOBAL, STT_OBJECT, data);
1310            symtab.addSymbol(e);
1311        }
1312
1313        it = text_relocs1.iterator();
1314        while (it.hasNext()) {
1315            Reloc r = (Reloc)it.next();
1316            if (r instanceof Code2CodeReference) {
1317                Code2CodeReference cr = (Code2CodeReference)r;
1318                textrel.addReloc(new RelocEntry(cr.getFrom().to32BitValue(), datasyment, RelocEntry.R_386_32));
1319            } else {
1320                Assert.UNREACHABLE(r.toString());
1321            }
1322        }
1323        
1324        it = text_relocs2.iterator();
1325        while (it.hasNext()) {
1326            Reloc r = (Reloc)it.next();
1327            if (r instanceof Code2HeapReference) {
1328                Code2HeapReference cr = (Code2HeapReference)r;
1329                textrel.addReloc(new RelocEntry(cr.getFrom().to32BitValue(), datasyment, RelocEntry.R_386_32));
1330            } else {
1331                Assert.UNREACHABLE(r.toString());
1332            }
1333        }
1334        
1335        it = data_relocs.iterator();
1336        while (it.hasNext()) {
1337            Reloc r = (Reloc)it.next();
1338            if (r instanceof Heap2HeapReference) {
1339                Heap2HeapReference cr = (Heap2HeapReference)r;
1340                datarel.addReloc(new RelocEntry(cr.getFrom().to32BitValue(), datasyment, RelocEntry.R_386_32));
1341            } else if (r instanceof Heap2CodeReference) {
1342                Heap2CodeReference cr = (Heap2CodeReference)r;
1343                datarel.addReloc(new RelocEntry(cr.getFrom().to32BitValue(), textsyment, RelocEntry.R_386_32));
1344            } else if (r instanceof ExternalReference) {
1345                // already done.
1346            } else {
1347                Assert.UNREACHABLE(r.toString());
1348            }
1349        }
1350        
1351        time = System.currentTimeMillis() - time;
1352        System.out.println("done. ("+(time/1000.)+" seconds)");
1353        
1354        f.write();
1355        
1356        //out.flush();
1357    }
1358
1359    class TextSection extends Section.ProgBitsSection {
1360        TextSection() {
1361            super(".text", Section.SHF_ALLOC | Section.SHF_EXECINSTR | Section.SHF_WRITE, 0);
1362        }
1363        public int getSize() { return bca.size(); }
1364        public int getAddrAlign() { return 64; }
1365        public void writeData(ELF file) throws IOException {
1366            ExtendedDataOutput out = (ExtendedDataOutput) ((ELFOutput)file).getOutput();
1367            bca.dump(out);
1368        }
1369        public void load(Section.UnloadedSection s, ELF file) throws IOException {
1370            Assert.UNREACHABLE();
1371        }
1372    }
1373
1374    class DataSection extends Section.ProgBitsSection {
1375        DataSection() {
1376            super(".data", Section.SHF_ALLOC | Section.SHF_WRITE, 0);
1377        }
1378        public int getSize() { return heapCurrent; }
1379        public int getAddrAlign() { return 64; }
1380        public void writeData(ELF file) throws IOException {
1381            try {
1382                ExtendedDataOutput out = (ExtendedDataOutput) ((ELFOutput)file).getOutput();
1383                dumpHeap(out);
1384            } catch (UnknownObjectException x) {
1385                Object u = x.getObject();
1386                HashSet visited = new HashSet();
1387                findReferencePath(u, x, visited);
1388                throw x;
1389            }
1390        }
1391        public void load(Section.UnloadedSection s, ELF file) throws IOException {
1392            Assert.UNREACHABLE();
1393        }
1394    }
1395    
1396    public static final jq_StaticField _DEFAULT;
1397    static {
1398        jq_Class k = (jq_Class) PrimordialClassLoader.loader.getOrCreateBSType("LBootstrap/BootImage;");
1399        _DEFAULT = k.getOrCreateStaticField("DEFAULT", "LBootstrap/BootImage;");
1400    }
1401
1402}