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