View Javadoc

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