Index: build.xml
===================================================================
--- build.xml (revision 14341)
+++ build.xml (working copy)
@@ -1137,7 +1137,6 @@
-
Index: tools/bootImageWriter/src/org/jikesrvm/tools/bootImageWriter/BootImageWriterConstants.java
===================================================================
--- tools/bootImageWriter/src/org/jikesrvm/tools/bootImageWriter/BootImageWriterConstants.java (revision 14341)
+++ tools/bootImageWriter/src/org/jikesrvm/tools/bootImageWriter/BootImageWriterConstants.java (working copy)
@@ -33,6 +33,11 @@
Address OBJECT_NOT_PRESENT = Address.fromIntSignExtend(0xeeeeeee2);
/**
+ * Address to associate with objects that have their allocation deferred.
+ */
+ Address OBJECT_ALLOCATION_DEFERRED = Address.fromIntSignExtend(0xeeeeeee3);
+
+ /**
* Starting index for objects in VM_TypeDictionary.
* = 1, since slot 0 is reserved for null
*/
Index: tools/bootImageWriter/src/org/jikesrvm/tools/bootImageWriter/BootImageWriter.java
===================================================================
--- tools/bootImageWriter/src/org/jikesrvm/tools/bootImageWriter/BootImageWriter.java (revision 14341)
+++ tools/bootImageWriter/src/org/jikesrvm/tools/bootImageWriter/BootImageWriter.java (working copy)
@@ -12,16 +12,21 @@
*/
package org.jikesrvm.tools.bootImageWriter;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.Iterator;
import java.util.Hashtable;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.PriorityQueue;
+import java.util.Queue;
import java.util.SortedSet;
-import java.util.Iterator;
+import java.util.Stack;
import java.util.TreeSet;
import java.util.Vector;
-import java.util.Stack;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Arrays;
-import java.util.BitSet;
import java.util.concurrent.*;
import java.io.*;
@@ -30,8 +35,6 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
-import java.util.Comparator;
-import java.util.HashSet;
import org.jikesrvm.*;
import org.jikesrvm.compilers.common.VM_CompiledMethod;
@@ -138,7 +141,7 @@
*/
private static class FieldInfo {
/**
- * Field table from JDK verion of class
+ * Field table from JDK version of class
*/
final Field[] jdkFields;
@@ -161,13 +164,13 @@
/**
* Jdk type associated with this Field info
*/
- final Class jdkType;
+ final Class> jdkType;
/**
* Constructor.
* @param jdkType the type to associate with the key
*/
- public FieldInfo(Class jdkType, VM_Type rvmType) {
+ public FieldInfo(Class> jdkType, VM_Type rvmType) {
this.jdkFields = jdkType.getDeclaredFields();
this.jdkType = jdkType;
this.rvmType = rvmType;
@@ -181,19 +184,19 @@
/**
* Jdk type
*/
- final Class jdkType;
+ final Class> jdkType;
/**
* Constructor.
* @param jdkType the type to associate with the key
*/
- public Key(Class jdkType) { this.jdkType = jdkType; }
+ public Key(Class> jdkType) { this.jdkType = jdkType; }
/**
* Returns a hash code value for the key.
* @return a hash code value for this key
*/
- public int hashCode() { return System.identityHashCode(jdkType); }
+ public int hashCode() { return jdkType.hashCode(); }
/**
* Indicates whether some other key is "equal to" this one.
@@ -206,6 +209,225 @@
}
}
+ /**
+ * Comparator that always says entries are equivalent. For use when
+ * comparator defers to another comparator.
+ */
+ private static final class IdenticalComparator implements Comparator {
+ public int compare(BootImageMap.Entry a, BootImageMap.Entry b) {
+ return 0;
+ }
+ }
+
+ /**
+ * Comparator of boot image entries that sorts according to the type
+ * reference ID.
+ */
+ private static final class TypeReferenceComparator implements Comparator {
+ public int compare(BootImageMap.Entry a, BootImageMap.Entry b) {
+ VM_TypeReference aRef = VM_TypeReference.findOrCreate(a.jdkObject.getClass());
+ VM_TypeReference bRef = VM_TypeReference.findOrCreate(b.jdkObject.getClass());
+ return aRef.getId() - bRef.getId();
+ }
+ }
+
+ /**
+ * Comparator of boot image entries that sorts according to the name of the
+ * classes.
+ */
+ private static final class ClassNameComparator implements Comparator {
+ public int compare(BootImageMap.Entry a, BootImageMap.Entry b) {
+ return -a.jdkObject.getClass().toString().compareTo(b.jdkObject.getClass().toString());
+ }
+ }
+
+ /**
+ * Comparator of boot image entries that sorts according to the size of
+ * the objects.
+ */
+ private static final class ObjectSizeComparator implements Comparator {
+ private final Comparator identicalSizeComparator;
+ ObjectSizeComparator(Comparator identicalSizeComparator) {
+ this.identicalSizeComparator = identicalSizeComparator;
+ }
+ public int compare(BootImageMap.Entry a, BootImageMap.Entry b) {
+ VM_TypeReference aRef = VM_TypeReference.findOrCreate(a.jdkObject.getClass());
+ VM_TypeReference bRef = VM_TypeReference.findOrCreate(b.jdkObject.getClass());
+ if ((!aRef.isResolved() && !aRef.isResolved()) || (aRef == bRef)) {
+ return identicalSizeComparator.compare(a, b);
+ } else if (!aRef.isResolved()) {
+ return -1;
+ } else if (!bRef.isResolved()) {
+ return 1;
+ } else {
+ int aSize = getSize(aRef.peekType(), a.jdkObject);
+ int bSize = getSize(bRef.peekType(), b.jdkObject);
+ if (aSize == bSize) {
+ return identicalSizeComparator.compare(a, b);
+ } else {
+ return aSize - bSize;
+ }
+ }
+ }
+ }
+
+ /**
+ * Comparator of boot image entries that sorts according to the number of
+ * references within the objects.
+ */
+ private static final class NumberOfReferencesComparator implements Comparator {
+ private final Comparator identicalSizeComparator;
+ NumberOfReferencesComparator(Comparator identicalSizeComparator) {
+ this.identicalSizeComparator = identicalSizeComparator;
+ }
+ public int compare(BootImageMap.Entry a, BootImageMap.Entry b) {
+ VM_TypeReference aRef = VM_TypeReference.findOrCreate(a.jdkObject.getClass());
+ VM_TypeReference bRef = VM_TypeReference.findOrCreate(b.jdkObject.getClass());
+ if ((!aRef.isResolved() && !aRef.isResolved()) || (aRef == bRef)) {
+ return identicalSizeComparator.compare(a, b);
+ } else if (!aRef.isResolved()) {
+ return 1;
+ } else if (!bRef.isResolved()) {
+ return -1;
+ } else {
+ int aSize = getNumberOfReferences(aRef.peekType(), a.jdkObject);
+ int bSize = getNumberOfReferences(bRef.peekType(), b.jdkObject);
+ if (aSize == bSize) {
+ return identicalSizeComparator.compare(a, b);
+ } else {
+ return bSize - aSize;
+ }
+ }
+ }
+ }
+
+ /**
+ * Comparator of boot image entries that sorts according to the number of
+ * non-final references within the objects.
+ */
+ private static final class NumberOfNonFinalReferencesComparator implements Comparator {
+ private final Comparator identicalSizeComparator;
+ NumberOfNonFinalReferencesComparator(Comparator identicalSizeComparator) {
+ this.identicalSizeComparator = identicalSizeComparator;
+ }
+ public int compare(BootImageMap.Entry a, BootImageMap.Entry b) {
+ VM_TypeReference aRef = VM_TypeReference.findOrCreate(a.jdkObject.getClass());
+ VM_TypeReference bRef = VM_TypeReference.findOrCreate(b.jdkObject.getClass());
+ if ((!aRef.isResolved() && !aRef.isResolved()) || (aRef == bRef)) {
+ return identicalSizeComparator.compare(a, b);
+ } else if (!aRef.isResolved()) {
+ return 1;
+ } else if (!bRef.isResolved()) {
+ return -1;
+ } else {
+ int aSize = getNumberOfNonFinalReferences(aRef.peekType(), a.jdkObject);
+ int bSize = getNumberOfNonFinalReferences(bRef.peekType(), b.jdkObject);
+ if (aSize == bSize) {
+ return identicalSizeComparator.compare(a, b);
+ } else {
+ return bSize - aSize;
+ }
+ }
+ }
+ }
+
+ /**
+ * Comparator of boot image entries that sorts according to the density of
+ * non-final references within the objects.
+ */
+ private static final class NonFinalReferenceDensityComparator implements Comparator {
+ private final Comparator identicalSizeComparator;
+ NonFinalReferenceDensityComparator(Comparator identicalSizeComparator) {
+ this.identicalSizeComparator = identicalSizeComparator;
+ }
+ public int compare(BootImageMap.Entry a, BootImageMap.Entry b) {
+ VM_TypeReference aRef = VM_TypeReference.findOrCreate(a.jdkObject.getClass());
+ VM_TypeReference bRef = VM_TypeReference.findOrCreate(b.jdkObject.getClass());
+ if ((!aRef.isResolved() && !aRef.isResolved()) || (aRef == bRef)) {
+ return identicalSizeComparator.compare(a, b);
+ } else if (!aRef.isResolved()) {
+ return 1;
+ } else if (!bRef.isResolved()) {
+ return -1;
+ } else {
+ double aSize = (double)getNumberOfNonFinalReferences(aRef.peekType(), a.jdkObject) / (double)getSize(aRef.peekType(), a.jdkObject);
+ double bSize = (double)getNumberOfNonFinalReferences(bRef.peekType(), b.jdkObject) / (double)getSize(bRef.peekType(), b.jdkObject);
+ int result = Double.compare(aSize, bSize);
+ if (result == 0) {
+ return identicalSizeComparator.compare(a, b);
+ } else {
+ return -result;
+ }
+ }
+ }
+ }
+
+ /**
+ * Comparator of boot image entries that sorts according to the density of
+ * references within the objects.
+ */
+ private static final class ReferenceDensityComparator implements Comparator {
+ private final Comparator identicalSizeComparator;
+ ReferenceDensityComparator(Comparator identicalSizeComparator) {
+ this.identicalSizeComparator = identicalSizeComparator;
+ }
+ public int compare(BootImageMap.Entry a, BootImageMap.Entry b) {
+ VM_TypeReference aRef = VM_TypeReference.findOrCreate(a.jdkObject.getClass());
+ VM_TypeReference bRef = VM_TypeReference.findOrCreate(b.jdkObject.getClass());
+ if ((!aRef.isResolved() && !aRef.isResolved()) || (aRef == bRef)) {
+ return identicalSizeComparator.compare(a, b);
+ } else if (!aRef.isResolved()) {
+ return 1;
+ } else if (!bRef.isResolved()) {
+ return -1;
+ } else {
+ double aSize = (double)getNumberOfReferences(aRef.peekType(), a.jdkObject) / (double)getSize(aRef.peekType(), a.jdkObject);
+ double bSize = (double)getNumberOfReferences(bRef.peekType(), b.jdkObject) / (double)getSize(bRef.peekType(), b.jdkObject);
+ int result = Double.compare(aSize, bSize);
+ if (result == 0) {
+ return identicalSizeComparator.compare(a, b);
+ } else {
+ return -result;
+ }
+ }
+ }
+ }
+
+ /**
+ * Entries yet to be written into the boot image
+ */
+ private static final Queue pendingEntries;
+ static {
+ if (true) // depth first traversal
+ pendingEntries = new LinkedList() {
+ public BootImageMap.Entry remove() {
+ return removeLast();
+ }};
+ else if (false) pendingEntries = new LinkedList(); // breadth first traversal
+ else if (false) pendingEntries = new PriorityQueue(11, new TypeReferenceComparator());
+ else if (false) pendingEntries = new PriorityQueue(11, new ClassNameComparator());
+ else if (false) pendingEntries = new PriorityQueue(11,
+ new ObjectSizeComparator(new IdenticalComparator()));
+ else if (false) pendingEntries = new PriorityQueue(11,
+ new NumberOfReferencesComparator(new IdenticalComparator()));
+ else if (false) pendingEntries = new PriorityQueue(11,
+ new NumberOfNonFinalReferencesComparator(new IdenticalComparator()));
+ else if (false) pendingEntries = new PriorityQueue(11,
+ new NumberOfNonFinalReferencesComparator(new ObjectSizeComparator(new TypeReferenceComparator())));
+ else if (false) pendingEntries = new PriorityQueue(11,
+ new NumberOfReferencesComparator(new ObjectSizeComparator(new ClassNameComparator())));
+ else if (false) pendingEntries = new PriorityQueue(11,
+ new NumberOfReferencesComparator(new ObjectSizeComparator(new TypeReferenceComparator())));
+ else if (false) pendingEntries = new PriorityQueue(11,
+ new ReferenceDensityComparator(new IdenticalComparator()));
+ else if (false) pendingEntries = new PriorityQueue(11,
+ new NonFinalReferenceDensityComparator(new IdenticalComparator()));
+ else if (false) pendingEntries = new PriorityQueue(11,
+ new ReferenceDensityComparator(new TypeReferenceComparator()));
+ else if (false) pendingEntries = new PriorityQueue(11,
+ new NonFinalReferenceDensityComparator(new TypeReferenceComparator()));
+ }
+
private static final boolean STATIC_FIELD = true;
private static final boolean INSTANCE_FIELD = false;
@@ -259,12 +481,6 @@
private static boolean profile = false;
/**
- * What is the threshold (in ms) for compilation of a single class
- * to be reported as excessively long (when profiling is true)
- */
- private static final int classCompileThreshold = 5000;
-
- /**
* A wrapper around the calling context to aid in tracing.
*/
private static class TraceContext extends Stack {
@@ -707,9 +923,10 @@
if (verbose >= 1) say("copying statics");
try {
int refSlotSize = VM_Statics.getReferenceSlotSize();
+ //copyToBootImage(VM_Statics.getSlotsAsIntArray(), false, Address.max(), null, false);
for (int i = VM_Statics.middleOfTable+refSlotSize, n = VM_Statics.getHighestInUseSlot();
- i <= n;
- i+= refSlotSize) {
+ i <= n;
+ i+= refSlotSize) {
if(!VM_Statics.isReference(i)) {
throw new Error("Static " + i + " of " + n + " isn't reference");
}
@@ -724,17 +941,20 @@
continue;
if (verbose >= 2) traceContext.push(jdkObject.getClass().getName(),
- getRvmStaticField(jtocOff) + "");
- Address imageAddress = copyToBootImage(jdkObject, false, Address.max(), VM_Statics.getSlotsAsIntArray(), false);
- if (imageAddress.EQ(OBJECT_NOT_PRESENT)) {
- // object not part of bootimage: install null reference
- if (verbose >= 2) traceContext.traceObjectNotInBootImage();
- bootImage.setNullAddressWord(jtocPtr.plus(jtocOff), false, false, false);
- } else {
- bootImage.setAddressWord(jtocPtr.plus(jtocOff), imageAddress.toWord(), false, false);
- }
+ getRvmStaticField(jtocOff) + "");
+ copyReferenceFieldToBootImage(jtocPtr.plus(jtocOff), jdkObject, VM_Statics.getSlotsAsIntArray(), false, false, null, null);
if (verbose >= 2) traceContext.pop();
}
+ // Copy entries that are in the pending queue
+ processPendingEntries();
+ // Find and copy unallocated entries
+ for (int i=0; i < BootImageMap.objectIdToEntry.size(); i++) {
+ BootImageMap.Entry mapEntry = BootImageMap.objectIdToEntry.get(i);
+ if (mapEntry.imageAddress.EQ(OBJECT_NOT_ALLOCATED)) {
+ mapEntry.imageAddress = copyToBootImage(mapEntry.jdkObject, false, Address.max(), null, false);
+ fixupLinkAddresses(mapEntry);
+ }
+ }
} catch (IllegalAccessException e) {
fail("unable to copy statics: "+e);
}
@@ -775,6 +995,8 @@
VM.sysWriteln("newBootRecordImageOffset = ", newBootRecordImageAddress);
VM._assert(newBootRecordImageAddress.EQ(bootRecordImageAddress));
}
+ // Make sure pending entries are fully written out
+ processPendingEntries();
} catch (IllegalAccessException e) {
fail("unable to update boot record: "+e);
}
@@ -1166,7 +1388,7 @@
if (!rvmType.isClassType())
continue; // arrays and primitives have no static or instance fields
- Class jdkType = getJdkType(rvmType);
+ Class> jdkType = getJdkType(rvmType);
if (jdkType == null)
continue; // won't need the field info
@@ -1180,7 +1402,7 @@
bootImageTypeFields.put(key, fieldInfo);
// Now do all the superclasses if they don't already exist
// Can't add them in next loop as Iterator's don't allow updates to collection
- for (Class cls = jdkType.getSuperclass(); cls != null; cls = cls.getSuperclass()) {
+ for (Class> cls = jdkType.getSuperclass(); cls != null; cls = cls.getSuperclass()) {
key = new Key(cls);
fieldInfo = bootImageTypeFields.get(key);
if (fieldInfo != null) {
@@ -1200,7 +1422,7 @@
if (verbose >= 1) say("bootImageTypeField entry has no rvmType:"+fieldInfo.jdkType);
continue;
}
- Class jdkType = fieldInfo.jdkType;
+ Class> jdkType = fieldInfo.jdkType;
if (verbose >= 1) say("building static and instance fieldinfo for " + rvmType);
// First the static fields
@@ -1289,7 +1511,7 @@
if (!rvmType.isClassType())
continue; // arrays and primitives have no static fields
- Class jdkType = getJdkType(rvmType);
+ Class> jdkType = getJdkType(rvmType);
if (jdkType == null && verbose >= 1) {
say("host has no class \"" + rvmType + "\"");
}
@@ -1481,6 +1703,101 @@
}
/**
+ * Write a field that contains a reference to the boot image
+ * @param fieldLocation address in boot image of field
+ * @param referencedObject the object whose address will be written at this
+ * location
+ * @param parentObject object containing this fieldLocation
+ * @param objField true if this word is an object field (as opposed
+ * to a static, or tib, or some other metadata)
+ * @param root Does this slot contain a possible reference into the heap?
+ * (objField must also be true)
+ * @param rvmFieldName Name of the field
+ * @param rvmFieldType Type of the field
+ */
+ private static void copyReferenceFieldToBootImage(Address fieldLocation, Object referencedObject,
+ Object parentObject, boolean objField, boolean root, String rvmFieldName,
+ VM_TypeReference rvmFieldType) throws IllegalAccessException {
+ if (referencedObject == null) {
+ bootImage.setNullAddressWord(fieldLocation, objField, root, true);
+ } else {
+ BootImageMap.Entry mapEntry = BootImageMap.findOrCreateEntry(referencedObject);
+ if (mapEntry.imageAddress.EQ(OBJECT_NOT_PRESENT)) {
+ if (rvmFieldName == null || !copyKnownClasspathInstanceField(parentObject, rvmFieldName, rvmFieldType, fieldLocation)) {
+ // object not part of bootimage: install null reference
+ if (verbose >= 2) traceContext.traceObjectNotInBootImage();
+ bootImage.setNullAddressWord(fieldLocation, objField, root, false);
+ }
+ } else if (mapEntry.imageAddress.EQ(OBJECT_NOT_ALLOCATED)) {
+ Address imageAddress;
+ if (true) {
+ // Normal collection based traversal
+ mapEntry.addLinkingAddress(fieldLocation, objField, root, rvmFieldName, rvmFieldType, parentObject);
+ if (!pendingEntries.contains(mapEntry)) {
+ pendingEntries.add(mapEntry);
+ }
+ imageAddress = OBJECT_ALLOCATION_DEFERRED;
+ root = false;
+ } else {
+ // Recurse placing work on the stack
+ mapEntry.imageAddress = copyToBootImage(referencedObject, false, Address.max(), parentObject, false);
+ imageAddress = mapEntry.imageAddress;
+ }
+ if (imageAddress.EQ(OBJECT_NOT_PRESENT)) {
+ if (verbose >= 2) traceContext.traceObjectNotInBootImage();
+ if (!copyKnownClasspathInstanceField(parentObject, rvmFieldName, rvmFieldType, fieldLocation)) {
+ // object not part of bootimage: install null reference
+ if (verbose >= 2) traceContext.traceObjectNotInBootImage();
+ bootImage.setNullAddressWord(fieldLocation, objField, root, false);
+ }
+ } else {
+ bootImage.setAddressWord(fieldLocation, imageAddress.toWord(), objField, root);
+ }
+ } else {
+ bootImage.setAddressWord(fieldLocation, mapEntry.imageAddress.toWord(), objField, root);
+ }
+ }
+ }
+
+ /**
+ * Process any entries that have been deferred
+ * @throws IllegalAccessException
+ */
+ private static void processPendingEntries() throws IllegalAccessException {
+ while (!pendingEntries.isEmpty()) {
+ BootImageMap.Entry mapEntry = pendingEntries.remove();
+ if (mapEntry.imageAddress.EQ(OBJECT_NOT_ALLOCATED)) {
+ mapEntry.imageAddress = copyToBootImage(mapEntry.jdkObject, false, Address.max(), null, false);
+ }
+ fixupLinkAddresses(mapEntry);
+ }
+ }
+
+ /**
+ * Iterate over link address registered with entry writing out boot image address
+ * @param mapEntry entry containing addresses to fix up
+ * @return number of entries fixed up
+ * @throws IllegalAccessException
+ */
+ private static int fixupLinkAddresses(BootImageMap.Entry mapEntry) throws IllegalAccessException {
+ int count = 0;
+ BootImageMap.Entry.LinkInfo info = mapEntry.removeLinkingAddress();
+ while(info != null) {
+ if (mapEntry.imageAddress.EQ(OBJECT_NOT_PRESENT)) {
+ if (info.rvmFieldName == null || !copyKnownClasspathInstanceField(info.parent, info.rvmFieldName, info.rvmFieldType, info.addressToFixup)) {
+ // object not part of bootimage: install null reference
+ if (verbose >= 2) traceContext.traceObjectNotInBootImage();
+ bootImage.setNullAddressWord(info.addressToFixup, info.objField, info.root, false);
+ }
+ } else {
+ bootImage.setAddressWord(info.addressToFixup, mapEntry.imageAddress.toWord(), info.objField, info.root);
+ }
+ info = mapEntry.removeLinkingAddress();
+ count++;
+ }
+ return count;
+ }
+ /**
* Copy an object (and, recursively, any of its fields or elements that
* are references) from host jdk address space into image.
*
@@ -1497,19 +1814,15 @@
Address overwriteAddress, Object parentObject, boolean untraced) throws IllegalAccessException
{
try {
- //
// Return object if it is already copied and not being overwritten
- //
BootImageMap.Entry mapEntry = BootImageMap.findOrCreateEntry(jdkObject);
- if ((!mapEntry.imageAddress.EQ(OBJECT_NOT_ALLOCATED)) && overwriteAddress.isMax())
+ if ((!mapEntry.imageAddress.EQ(OBJECT_NOT_ALLOCATED)) && overwriteAddress.isMax()) {
return mapEntry.imageAddress;
+ }
if (verbose >= 2) depth++;
-
- //
// fetch object's type information
- //
- Class jdkType = jdkObject.getClass();
+ Class> jdkType = jdkObject.getClass();
VM_Type rvmType = getRvmType(jdkType);
if (rvmType == null) {
if (verbose >= 2) traverseObject(jdkObject);
@@ -1517,369 +1830,342 @@
return OBJECT_NOT_PRESENT; // object not part of bootimage
}
- //
// copy object to image
- //
if (jdkType.isArray()) {
+ // allocate space in image prior to recursing
+ int arrayCount = Array.getLength(jdkObject);
VM_Array rvmArrayType = rvmType.asArray();
-
- //
- // allocate space in image
- //
- int arrayCount = Array.getLength(jdkObject);
Address arrayImageAddress = (overwriteAddress.isMax()) ? bootImage.allocateArray(rvmArrayType, arrayCount) : overwriteAddress;
mapEntry.imageAddress = arrayImageAddress;
+ mapEntry.imageAddress = copyArrayToBootImage(arrayCount, arrayImageAddress, jdkObject, jdkType,
+ rvmArrayType, allocOnly, overwriteAddress, parentObject, untraced);
+ // copy object's type information block into image, if it's not there
+ // already
+ if (!allocOnly) {
- if (verbose >= 2) {
- if (depth == depthCutoff)
- say(SPACES.substring(0,depth+1), "TOO DEEP: cutting off");
- else if (depth < depthCutoff) {
- String tab = SPACES.substring(0,depth+1);
- if (depth == 0 && jtocCount >= 0)
- tab = tab + "jtoc #" + String.valueOf(jtocCount) + ": ";
- int arraySize = rvmArrayType.getInstanceSize(arrayCount);
- say(tab, "Copying array ", jdkType.getName(),
- " length=", String.valueOf(arrayCount),
- (arraySize >= LARGE_ARRAY_SIZE) ? " large object!!!" : "");
+ if (verbose >= 2) traceContext.push("", jdkObject.getClass().getName(), "tib");
+ Address tibImageAddress = copyToBootImage(rvmType.getTypeInformationBlock(), allocOnly, Address.max(), jdkObject, false);
+ if (verbose >= 2) traceContext.pop();
+ if (tibImageAddress.EQ(OBJECT_NOT_ALLOCATED)) {
+ fail("can't copy tib for " + jdkObject);
}
+ VM_ObjectModel.setTIB(bootImage, mapEntry.imageAddress, tibImageAddress, rvmType);
}
+ } else if (rvmType == VM_Type.ObjectReferenceArrayType || rvmType.getTypeRef().isRuntimeTable()) {
+ Object backing = getBackingArray(rvmType, jdkObject);
- VM_Type rvmElementType = rvmArrayType.getElementType();
+ /* Copy the backing array, and then replace its TIB */
+ mapEntry.imageAddress = copyToBootImage(backing, allocOnly, overwriteAddress, jdkObject, rvmType.getTypeRef().isRuntimeTable());
- // Show info on reachability of int arrays
- //
- if (false && rvmElementType.equals(VM_Type.IntType)) {
- if (parentObject != null) {
- Class parentObjectType = parentObject.getClass();
- VM.sysWrite("Copying int array (", 4 * ((int []) jdkObject).length);
- VM.sysWriteln(" bytes) from parent object of type ", parentObjectType.toString());
- } else {
- VM.sysWriteln("Copying int array from no parent object");
+ if (!allocOnly) {
+ if (verbose >= 2) {
+ depth--;
+ traceContext.push("", jdkObject.getClass().getName(), "tib");
}
- }
-
- //
- // copy array elements from host jdk address space into image
- // recurse on values that are references
- //
- if (rvmElementType.isPrimitiveType()) {
- // array element is logical or numeric type
- if (rvmElementType.equals(VM_Type.BooleanType)) {
- boolean[] values = (boolean[]) jdkObject;
- for (int i = 0; i < arrayCount; ++i)
- bootImage.setByte(arrayImageAddress.plus(i), values[i] ? 1 : 0);
- } else if (rvmElementType.equals(VM_Type.ByteType)) {
- byte[] values = (byte[]) jdkObject;
- for (int i = 0; i < arrayCount; ++i)
- bootImage.setByte(arrayImageAddress.plus(i), values[i]);
- } else if (rvmElementType.equals(VM_Type.CharType)) {
- char[] values = (char[]) jdkObject;
- for (int i = 0; i < arrayCount; ++i)
- bootImage.setHalfWord(arrayImageAddress.plus(i << LOG_BYTES_IN_CHAR), values[i]);
- } else if (rvmElementType.equals(VM_Type.ShortType)) {
- short[] values = (short[]) jdkObject;
- for (int i = 0; i < arrayCount; ++i)
- bootImage.setHalfWord(arrayImageAddress.plus(i << LOG_BYTES_IN_SHORT), values[i]);
- } else if (rvmElementType.equals(VM_Type.IntType)) {
- int[] values = (int[]) jdkObject;
- for (int i = 0; i < arrayCount; ++i)
- bootImage.setFullWord(arrayImageAddress.plus(i << LOG_BYTES_IN_INT), values[i]);
- } else if (rvmElementType.equals(VM_Type.LongType)) {
- long[] values = (long[]) jdkObject;
- for (int i = 0; i < arrayCount; ++i)
- bootImage.setDoubleWord(arrayImageAddress.plus(i << LOG_BYTES_IN_LONG), values[i]);
- } else if (rvmElementType.equals(VM_Type.FloatType)) {
- float[] values = (float[]) jdkObject;
- for (int i = 0; i < arrayCount; ++i)
- bootImage.setFullWord(arrayImageAddress.plus(i << LOG_BYTES_IN_FLOAT),
- Float.floatToIntBits(values[i]));
- } else if (rvmElementType.equals(VM_Type.DoubleType)) {
- double[] values = (double[]) jdkObject;
- for (int i = 0; i < arrayCount; ++i)
- bootImage.setDoubleWord(arrayImageAddress.plus(i << LOG_BYTES_IN_DOUBLE),
- Double.doubleToLongBits(values[i]));
- } else {
- fail("unexpected primitive array type: " + rvmArrayType);
+ Address tibImageAddress = copyToBootImage(rvmType.getTypeInformationBlock(), allocOnly, Address.max(), jdkObject, false);
+ if (verbose >= 2) {
+ traceContext.pop();
+ depth++;
}
- } else {
- // array element is reference type
- boolean isTIB = parentObject instanceof VM_TIB;
- Object[] values = (Object []) jdkObject;
- Class jdkClass = jdkObject.getClass();
- if (!allocOnly) {
- for (int i = 0; i= 2) traceContext.push(values[i].getClass().getName(), jdkClass.getName(), i);
- if (isTIB && values[i] instanceof Word) {
- bootImage.setAddressWord(arrayImageAddress.plus(i << LOG_BYTES_IN_ADDRESS), (Word)values[i], false, false);
- } else if (isTIB && values[i] == VM_LazyCompilationTrampoline.instructions) {
- Address codeAddress = arrayImageAddress.plus(((VM_TIB)parentObject).lazyMethodInvokerTrampolineIndex() << LOG_BYTES_IN_ADDRESS);
- bootImage.setAddressWord(arrayImageAddress.plus(i << LOG_BYTES_IN_ADDRESS), codeAddress.toWord(), false, false);
- } else {
- Address imageAddress = copyToBootImage(values[i], allocOnly, Address.max(), jdkObject, false);
- if (imageAddress.EQ(OBJECT_NOT_PRESENT)) {
- // object not part of bootimage: install null reference
- if (verbose >= 2) traceContext.traceObjectNotInBootImage();
- bootImage.setNullAddressWord(arrayImageAddress.plus(i << LOG_BYTES_IN_ADDRESS), !untraced, !untraced, false);
- } else {
- bootImage.setAddressWord(arrayImageAddress.plus(i << LOG_BYTES_IN_ADDRESS), imageAddress.toWord(), !untraced, !untraced);
- }
- }
- if (verbose >= 2) traceContext.pop();
- } else {
- bootImage.setNullAddressWord(arrayImageAddress.plus(i << LOG_BYTES_IN_ADDRESS), !untraced, !untraced, true);
- }
- }
+ if (tibImageAddress.EQ(OBJECT_NOT_ALLOCATED)) {
+ fail("can't copy tib for " + jdkObject);
}
+ VM_ObjectModel.setTIB(bootImage, mapEntry.imageAddress, tibImageAddress, rvmType);
}
+ } else if (rvmType.getTypeRef().isUnboxedArrayType() ||
+ rvmType.getTypeRef().isRuntimeTable() ||
+ rvmType == VM_Type.AddressArrayType ||
+ rvmType == VM_Type.CodeArrayType ||
+ rvmType == VM_Type.ExtentArrayType ||
+ rvmType == VM_Type.OffsetArrayType ||
+ rvmType == VM_Type.ObjectReferenceArrayType ||
+ rvmType == VM_Type.WordArrayType) {
+ Object backing = getBackingArray(rvmType, jdkObject);
+ mapEntry.imageAddress = copyMagicArrayToBootImage(backing, rvmType.asArray(), allocOnly, overwriteAddress, parentObject);
+ } else if (rvmType.getTypeRef().isMagicType()) {
+ VM.sysWriteln("Unhandled copying of magic type: " + rvmType.getDescriptor().toString() +
+ " in object of type " + parentObject.getClass().toString());
+ VM.sysFail("incomplete boot image support");
} else {
- if (rvmType == VM_Type.ObjectReferenceArrayType || rvmType.getTypeRef().isRuntimeTable()) {
- if (verbose >= 2) depth--;
- Object backing;
- if (rvmType == VM_Type.ObjectReferenceArrayType) {
- backing = ((ObjectReferenceArray)jdkObject).getBacking();
- } else if (rvmType == VM_Type.TIBType) {
- backing = ((VM_TIB)jdkObject).getBacking();
- } else if (rvmType == VM_Type.IMTType) {
- backing = ((VM_IMT)jdkObject).getBacking();
- } else if (rvmType == VM_Type.ITableType) {
- backing = ((VM_ITable)jdkObject).getBacking();
- } else if (rvmType == VM_Type.ITableArrayType) {
- backing = ((VM_ITableArray)jdkObject).getBacking();
- } else if (rvmType == VM_Type.ProcessorTableType) {
- backing = ((VM_ProcessorTable)jdkObject).getBacking();
- } else if (rvmType == VM_Type.FunctionTableType) {
- backing = ((VM_FunctionTable)jdkObject).getBacking();
- } else {
- fail("unexpected runtime table type: " + rvmType);
- backing = null;
- }
+ // allocate space in image
+ VM_Class rvmScalarType = rvmType.asClass();
+ Address scalarImageAddress = (overwriteAddress.isMax()) ? bootImage.allocateScalar(rvmScalarType) : overwriteAddress;
+ mapEntry.imageAddress = scalarImageAddress;
+ mapEntry.imageAddress = copyClassToBootImage(scalarImageAddress, jdkObject, jdkType, rvmScalarType,
+ allocOnly, overwriteAddress, parentObject, untraced);
+ // copy object's type information block into image, if it's not there
+ // already
+ if (!allocOnly) {
- /* Copy the backing array, and then replace its TIB */
- mapEntry.imageAddress = copyToBootImage(backing, allocOnly, overwriteAddress, jdkObject, rvmType.getTypeRef().isRuntimeTable());
-
- if (!allocOnly) {
- if (verbose >= 2) traceContext.push("", jdkObject.getClass().getName(), "tib");
- Address tibImageAddress = copyToBootImage(rvmType.getTypeInformationBlock(), allocOnly, Address.max(), jdkObject, false);
- if (verbose >= 2) traceContext.pop();
- if (tibImageAddress.EQ(OBJECT_NOT_ALLOCATED)) {
- fail("can't copy tib for " + jdkObject);
- }
- VM_ObjectModel.setTIB(bootImage, mapEntry.imageAddress, tibImageAddress, rvmType);
+ if (verbose >= 2) traceContext.push("", jdkObject.getClass().getName(), "tib");
+ Address tibImageAddress = copyToBootImage(rvmType.getTypeInformationBlock(), allocOnly, Address.max(), jdkObject, false);
+ if (verbose >= 2) traceContext.pop();
+ if (tibImageAddress.EQ(OBJECT_NOT_ALLOCATED)) {
+ fail("can't copy tib for " + jdkObject);
}
-
- return mapEntry.imageAddress;
+ VM_ObjectModel.setTIB(bootImage, mapEntry.imageAddress, tibImageAddress, rvmType);
}
+ }
- if (rvmType == VM_Type.AddressArrayType) {
- if (verbose >= 2) depth--;
- AddressArray addrArray = (AddressArray) jdkObject;
- Object backing = addrArray.getBacking();
- return copyMagicArrayToBootImage(backing, rvmType.asArray(), allocOnly, overwriteAddress, parentObject);
- }
+ if (verbose >= 2) depth--;
+ return mapEntry.imageAddress;
- if (rvmType == VM_Type.OffsetArrayType) {
- if (verbose >= 2) depth--;
- OffsetArray addrArray = (OffsetArray) jdkObject;
- Object backing = addrArray.getBacking();
- return copyMagicArrayToBootImage(backing, rvmType.asArray(), allocOnly, overwriteAddress, parentObject);
- }
+ } catch (Error e) {
+ e = new Error(e.getMessage()+ "\nwhile copying " +
+ jdkObject + (jdkObject != null ? ":"+jdkObject.getClass():"") + " from " +
+ parentObject + (parentObject != null ? ":"+parentObject.getClass():""),
+ e.getCause() != null? e.getCause() : e);
+ throw e;
+ }
+ }
- if (rvmType == VM_Type.WordArrayType) {
- if (verbose >= 2) depth--;
- WordArray addrArray = (WordArray) jdkObject;
- Object backing = addrArray.getBacking();
- return copyMagicArrayToBootImage(backing, rvmType.asArray(), allocOnly, overwriteAddress, parentObject);
- }
+ /**
+ * Write an object instantiating a class to the boot image
+ * @param scalarImageAddress address already allocated for object
+ * @param jdkObject object to write
+ * @param jdkType java.lang.Class of object
+ * @param rvmScalarType RVM class loader version of type
+ * @param allocOnly allocate the object only?
+ * @param overwriteAddress
+ * @param parentObject
+ * @param untraced
+ * @return
+ * @throws IllegalAccessException
+ */
+ private static Address copyClassToBootImage(Address scalarImageAddress, Object jdkObject, Class> jdkType,
+ VM_Class rvmScalarType, boolean allocOnly, Address overwriteAddress, Object parentObject, boolean untraced)
+ throws IllegalAccessException {
+ if (verbose >= 2) {
+ if (depth == depthCutoff)
+ say(SPACES.substring(0,depth+1), "TOO DEEP: cutting off");
+ else if (depth < depthCutoff) {
+ String tab = SPACES.substring(0,depth+1);
+ if (depth == 0 && jtocCount >= 0)
+ tab = tab + "jtoc #" + String.valueOf(jtocCount) + " ";
+ int scalarSize = rvmScalarType.getInstanceSize();
+ say(tab, "Copying object ", jdkType.getName(),
+ " size=", String.valueOf(scalarSize),
+ (scalarSize >= LARGE_SCALAR_SIZE) ? " large object!!!" : "");
+ }
+ }
- if (rvmType == VM_Type.ExtentArrayType) {
- if (verbose >= 2) depth--;
- ExtentArray addrArray = (ExtentArray) jdkObject;
- Object backing = addrArray.getBacking();
- return copyMagicArrayToBootImage(backing, rvmType.asArray(), allocOnly, overwriteAddress, parentObject);
- }
+ // copy object fields from host jdk address space into image
+ // recurse on values that are references
+ VM_Field[] rvmFields = rvmScalarType.getInstanceFields();
+ for (int i = 0; i < rvmFields.length; ++i) {
+ VM_Field rvmField = rvmFields[i];
+ VM_TypeReference rvmFieldType = rvmField.getType();
+ Address rvmFieldAddress = scalarImageAddress.plus(rvmField.getOffset());
+ String rvmFieldName = rvmField.getName().toString();
+ Field jdkFieldAcc = getJdkFieldAccessor(jdkType, i, INSTANCE_FIELD);
- if (rvmType == VM_Type.CodeArrayType) {
- if (verbose >= 2) depth--;
- VM_CodeArray codeArray = (VM_CodeArray) jdkObject;
- Object backing = codeArray.getBacking();
- return copyMagicArrayToBootImage(backing, rvmType.asArray(), allocOnly, overwriteAddress, parentObject);
- }
+ boolean untracedField = rvmField.isUntraced() || untraced;
- if (rvmType.getTypeRef().isMagicType()) {
- VM.sysWriteln("Unhandled copying of magic type: " + rvmType.getDescriptor().toString() +
- " in object of type " + parentObject.getClass().toString());
- VM.sysFail("incomplete boot image support");
+ if (jdkFieldAcc == null) {
+ // Field not found via reflection
+ if (!copyKnownClasspathInstanceField(jdkObject, rvmFieldName, rvmFieldType, rvmFieldAddress)) {
+ // Field wasn't a known Classpath field so write null
+ if (verbose >= 2) traceContext.push(rvmFieldType.toString(),
+ jdkType.getName(), rvmFieldName);
+ if (verbose >= 2) traceContext.traceFieldNotInHostJdk();
+ if (verbose >= 2) traceContext.pop();
+ if (rvmFieldType.isPrimitiveType()) {
+ switch (rvmField.getType().getMemoryBytes()) {
+ case 1: bootImage.setByte(rvmFieldAddress, 0); break;
+ case 2: bootImage.setHalfWord(rvmFieldAddress, 0); break;
+ case 4: bootImage.setFullWord(rvmFieldAddress, 0); break;
+ case 8: bootImage.setDoubleWord(rvmFieldAddress, 0L); break;
+ default:fail("unexpected field type: " + rvmFieldType); break;
+ }
+ } else {
+ bootImage.setNullAddressWord(rvmFieldAddress, !untracedField, !untracedField, false);
+ }
}
+ continue;
+ }
- //
- // allocate space in image
- //
- VM_Class rvmScalarType = rvmType.asClass();
- Address scalarImageAddress = (overwriteAddress.isMax()) ? bootImage.allocateScalar(rvmScalarType) : overwriteAddress;
- mapEntry.imageAddress = scalarImageAddress;
-
- if (verbose >= 2) {
- if (depth == depthCutoff)
- say(SPACES.substring(0,depth+1), "TOO DEEP: cutting off");
- else if (depth < depthCutoff) {
- String tab = SPACES.substring(0,depth+1);
- if (depth == 0 && jtocCount >= 0)
- tab = tab + "jtoc #" + String.valueOf(jtocCount) + " ";
- int scalarSize = rvmScalarType.getInstanceSize();
- say(tab, "Copying object ", jdkType.getName(),
- " size=", String.valueOf(scalarSize),
- (scalarSize >= LARGE_SCALAR_SIZE) ? " large object!!!" : "");
+ if (rvmFieldType.isPrimitiveType()) {
+ // field is logical or numeric type
+ if (rvmFieldType.isBooleanType()) {
+ bootImage.setByte(rvmFieldAddress,
+ jdkFieldAcc.getBoolean(jdkObject) ? 1 : 0);
+ } else if (rvmFieldType.isByteType()) {
+ bootImage.setByte(rvmFieldAddress,
+ jdkFieldAcc.getByte(jdkObject));
+ } else if (rvmFieldType.isCharType()) {
+ bootImage.setHalfWord(rvmFieldAddress,
+ jdkFieldAcc.getChar(jdkObject));
+ } else if (rvmFieldType.isShortType()) {
+ bootImage.setHalfWord(rvmFieldAddress,
+ jdkFieldAcc.getShort(jdkObject));
+ } else if (rvmFieldType.isIntType()) {
+ try {
+ bootImage.setFullWord(rvmFieldAddress, jdkFieldAcc.getInt(jdkObject));
+ } catch (IllegalArgumentException ex) {
+ System.out.println("type " + rvmScalarType + ", field " + rvmField);
+ throw ex;
}
+ } else if (rvmFieldType.isLongType()) {
+ bootImage.setDoubleWord(rvmFieldAddress,
+ jdkFieldAcc.getLong(jdkObject));
+ } else if (rvmFieldType.isFloatType()) {
+ float f = jdkFieldAcc.getFloat(jdkObject);
+ bootImage.setFullWord(rvmFieldAddress,
+ Float.floatToIntBits(f));
+ } else if (rvmFieldType.isDoubleType()) {
+ double d = jdkFieldAcc.getDouble(jdkObject);
+ bootImage.setDoubleWord(rvmFieldAddress,
+ Double.doubleToLongBits(d));
+ } else if (rvmFieldType.equals(VM_TypeReference.Address) ||
+ rvmFieldType.equals(VM_TypeReference.Word) ||
+ rvmFieldType.equals(VM_TypeReference.Extent) ||
+ rvmFieldType.equals(VM_TypeReference.Offset)) {
+ Object o = jdkFieldAcc.get(jdkObject);
+ String msg = " instance field " + rvmField.toString();
+ boolean warn = rvmFieldType.equals(VM_TypeReference.Address);
+ bootImage.setAddressWord(rvmFieldAddress, getWordValue(o, msg, warn), false, false);
+ } else {
+ fail("unexpected primitive field type: " + rvmFieldType);
}
+ } else {
+ // field is reference type
+ Object value = jdkFieldAcc.get(jdkObject);
+ if (!allocOnly) {
+ Class> jdkClass = jdkFieldAcc.getDeclaringClass();
+ if (verbose >= 2) traceContext.push(value.getClass().getName(),
+ jdkClass.getName(),
+ jdkFieldAcc.getName());
+ copyReferenceFieldToBootImage(rvmFieldAddress, value, jdkObject,
+ !untracedField, !(untracedField || rvmField.isFinal()), rvmFieldName, rvmFieldType);
+ }
+ }
+ }
+ return scalarImageAddress;
+ }
- //
- // copy object fields from host jdk address space into image
- // recurse on values that are references
- //
- VM_Field[] rvmFields = rvmScalarType.getInstanceFields();
- for (int i = 0, n = rvmFields.length; i < n; ++i) {
- VM_Field rvmField = rvmFields[i];
- VM_TypeReference rvmFieldType = rvmField.getType();
- Address rvmFieldAddress = scalarImageAddress.plus(rvmField.getOffset());
- String rvmFieldName = rvmField.getName().toString();
- Field jdkFieldAcc = getJdkFieldAccessor(jdkType, i, INSTANCE_FIELD);
+ /**
+ * Write array to boot image
+ * @param arrayCount
+ * @param arrayImageAddress
+ * @param jdkObject
+ * @param jdkType
+ * @param rvmArrayType
+ * @param allocOnly
+ * @param overwriteAddress
+ * @param parentObject
+ * @param untraced
+ * @return
+ * @throws IllegalAccessException
+ */
+ private static Address copyArrayToBootImage(int arrayCount, Address arrayImageAddress, Object jdkObject, Class> jdkType, VM_Array rvmArrayType,
+ boolean allocOnly, Address overwriteAddress, Object parentObject, boolean untraced)
+ throws IllegalAccessException {
+ if (verbose >= 2) {
+ if (depth == depthCutoff)
+ say(SPACES.substring(0,depth+1), "TOO DEEP: cutting off");
+ else if (depth < depthCutoff) {
+ String tab = SPACES.substring(0,depth+1);
+ if (depth == 0 && jtocCount >= 0)
+ tab = tab + "jtoc #" + String.valueOf(jtocCount) + ": ";
+ int arraySize = rvmArrayType.getInstanceSize(arrayCount);
+ say(tab, "Copying array ", jdkType.getName(),
+ " length=", String.valueOf(arrayCount),
+ (arraySize >= LARGE_ARRAY_SIZE) ? " large object!!!" : "");
+ }
+ }
- boolean untracedField = rvmField.isUntraced() || untraced;
+ VM_Type rvmElementType = rvmArrayType.getElementType();
- if (jdkFieldAcc == null) {
- // Field not found via reflection
- if (!copyKnownClasspathInstanceField(jdkObject, rvmFieldName, rvmFieldType, rvmFieldAddress)) {
- // Field wasn't a known Classpath field so write null
- if (verbose >= 2) traceContext.push(rvmFieldType.toString(),
- jdkType.getName(), rvmFieldName);
- if (verbose >= 2) traceContext.traceFieldNotInHostJdk();
- if (verbose >= 2) traceContext.pop();
- if (rvmFieldType.isPrimitiveType()) {
- switch (rvmField.getType().getMemoryBytes()) {
- case 1: bootImage.setByte(rvmFieldAddress, 0); break;
- case 2: bootImage.setHalfWord(rvmFieldAddress, 0); break;
- case 4: bootImage.setFullWord(rvmFieldAddress, 0); break;
- case 8: bootImage.setDoubleWord(rvmFieldAddress, 0L); break;
- default:fail("unexpected field type: " + rvmFieldType); break;
- }
- } else {
- bootImage.setNullAddressWord(rvmFieldAddress, !untracedField, !untracedField, false);
- }
- }
- continue;
- }
-
- if (rvmFieldType.isPrimitiveType()) {
- // field is logical or numeric type
- if (rvmFieldType.isBooleanType()) {
- bootImage.setByte(rvmFieldAddress,
- jdkFieldAcc.getBoolean(jdkObject) ? 1 : 0);
- } else if (rvmFieldType.isByteType()) {
- bootImage.setByte(rvmFieldAddress,
- jdkFieldAcc.getByte(jdkObject));
- } else if (rvmFieldType.isCharType()) {
- bootImage.setHalfWord(rvmFieldAddress,
- jdkFieldAcc.getChar(jdkObject));
- } else if (rvmFieldType.isShortType()) {
- bootImage.setHalfWord(rvmFieldAddress,
- jdkFieldAcc.getShort(jdkObject));
- } else if (rvmFieldType.isIntType()) {
- try {
- bootImage.setFullWord(rvmFieldAddress,
- jdkFieldAcc.getInt(jdkObject));
- } catch (IllegalArgumentException ex) {
- System.out.println("type " + rvmScalarType + ", field " + rvmField);
- throw ex;
- }
- } else if (rvmFieldType.isLongType()) {
- bootImage.setDoubleWord(rvmFieldAddress,
- jdkFieldAcc.getLong(jdkObject));
- } else if (rvmFieldType.isFloatType()) {
- float f = jdkFieldAcc.getFloat(jdkObject);
- bootImage.setFullWord(rvmFieldAddress,
- Float.floatToIntBits(f));
- } else if (rvmFieldType.isDoubleType()) {
- double d = jdkFieldAcc.getDouble(jdkObject);
- bootImage.setDoubleWord(rvmFieldAddress,
- Double.doubleToLongBits(d));
- } else if (rvmFieldType.equals(VM_TypeReference.Address) ||
- rvmFieldType.equals(VM_TypeReference.Word) ||
- rvmFieldType.equals(VM_TypeReference.Extent) ||
- rvmFieldType.equals(VM_TypeReference.Offset)) {
- Object o = jdkFieldAcc.get(jdkObject);
- String msg = " instance field " + rvmField.toString();
- boolean warn = rvmFieldType.equals(VM_TypeReference.Address);
- bootImage.setAddressWord(rvmFieldAddress, getWordValue(o, msg, warn), false, false);
+ // copy array elements from host jdk address space into image
+ // recurse on values that are references
+ if (rvmElementType.isPrimitiveType()) {
+ // array element is logical or numeric type
+ if (rvmElementType.equals(VM_Type.BooleanType)) {
+ boolean[] values = (boolean[]) jdkObject;
+ for (int i = 0; i < arrayCount; ++i)
+ bootImage.setByte(arrayImageAddress.plus(i), values[i] ? 1 : 0);
+ } else if (rvmElementType.equals(VM_Type.ByteType)) {
+ byte[] values = (byte[]) jdkObject;
+ for (int i = 0; i < arrayCount; ++i)
+ bootImage.setByte(arrayImageAddress.plus(i), values[i]);
+ } else if (rvmElementType.equals(VM_Type.CharType)) {
+ char[] values = (char[]) jdkObject;
+ for (int i = 0; i < arrayCount; ++i)
+ bootImage.setHalfWord(arrayImageAddress.plus(i << LOG_BYTES_IN_CHAR), values[i]);
+ } else if (rvmElementType.equals(VM_Type.ShortType)) {
+ short[] values = (short[]) jdkObject;
+ for (int i = 0; i < arrayCount; ++i)
+ bootImage.setHalfWord(arrayImageAddress.plus(i << LOG_BYTES_IN_SHORT), values[i]);
+ } else if (rvmElementType.equals(VM_Type.IntType)) {
+ int[] values = (int[]) jdkObject;
+ for (int i = 0; i < arrayCount; ++i)
+ bootImage.setFullWord(arrayImageAddress.plus(i << LOG_BYTES_IN_INT), values[i]);
+ } else if (rvmElementType.equals(VM_Type.LongType)) {
+ long[] values = (long[]) jdkObject;
+ for (int i = 0; i < arrayCount; ++i)
+ bootImage.setDoubleWord(arrayImageAddress.plus(i << LOG_BYTES_IN_LONG), values[i]);
+ } else if (rvmElementType.equals(VM_Type.FloatType)) {
+ float[] values = (float[]) jdkObject;
+ for (int i = 0; i < arrayCount; ++i)
+ bootImage.setFullWord(arrayImageAddress.plus(i << LOG_BYTES_IN_FLOAT),
+ Float.floatToIntBits(values[i]));
+ } else if (rvmElementType.equals(VM_Type.DoubleType)) {
+ double[] values = (double[]) jdkObject;
+ for (int i = 0; i < arrayCount; ++i)
+ bootImage.setDoubleWord(arrayImageAddress.plus(i << LOG_BYTES_IN_DOUBLE),
+ Double.doubleToLongBits(values[i]));
+ } else {
+ fail("unexpected primitive array type: " + rvmArrayType);
+ }
+ } else {
+ // array element is reference type
+ boolean isTIB = parentObject instanceof VM_TIB;
+ Object[] values = (Object []) jdkObject;
+ Class> jdkClass = jdkObject.getClass();
+ if (!allocOnly) {
+ for (int i = 0; i= 2) traceContext.push(values[i].getClass().getName(), jdkClass.getName(), i);
+ if (isTIB && values[i] instanceof Word) {
+ bootImage.setAddressWord(arrayImageAddress.plus(i << LOG_BYTES_IN_ADDRESS), (Word)values[i], false, false);
+ } else if (isTIB && values[i] == VM_LazyCompilationTrampoline.instructions) {
+ Address codeAddress = arrayImageAddress.plus(((VM_TIB)parentObject).lazyMethodInvokerTrampolineIndex() << LOG_BYTES_IN_ADDRESS);
+ bootImage.setAddressWord(arrayImageAddress.plus(i << LOG_BYTES_IN_ADDRESS), codeAddress.toWord(), false, false);
} else {
- fail("unexpected primitive field type: " + rvmFieldType);
+ copyReferenceFieldToBootImage(arrayImageAddress.plus(i << LOG_BYTES_IN_ADDRESS), values[i],
+ jdkObject, !untraced, !untraced, null, null);
}
+ if (verbose >= 2) traceContext.pop();
} else {
- // field is reference type
- Object value = jdkFieldAcc.get(jdkObject);
- if (!allocOnly) {
- if (value != null) {
- Class jdkClass = jdkFieldAcc.getDeclaringClass();
- if (verbose >= 2) traceContext.push(value.getClass().getName(),
- jdkClass.getName(),
- jdkFieldAcc.getName());
- Address imageAddress = copyToBootImage(value, allocOnly, Address.max(), jdkObject, false);
- if (imageAddress.EQ(OBJECT_NOT_PRESENT)) {
- if (!copyKnownClasspathInstanceField(jdkObject, rvmFieldName, rvmFieldType, rvmFieldAddress)) {
- // object not part of bootimage: install null reference
- if (verbose >= 2) traceContext.traceObjectNotInBootImage();
- bootImage.setNullAddressWord(rvmFieldAddress, !untracedField, !untracedField, false);
- }
- } else
- bootImage.setAddressWord(rvmFieldAddress, imageAddress.toWord(), !untracedField, !(untracedField || rvmField.isFinal()));
- if (verbose >= 2) traceContext.pop();
- } else {
- bootImage.setNullAddressWord(rvmFieldAddress, !untracedField, !untracedField, true);
- }
- }
+ bootImage.setNullAddressWord(arrayImageAddress.plus(i << LOG_BYTES_IN_ADDRESS), !untraced, !untraced, true);
}
}
}
-
- //
- // copy object's type information block into image, if it's not there
- // already
- //
- if (!allocOnly) {
-
- if (verbose >= 2) traceContext.push("", jdkObject.getClass().getName(), "tib");
- Address tibImageAddress = copyToBootImage(rvmType.getTypeInformationBlock(), allocOnly, Address.max(), jdkObject, false);
- if (verbose >= 2) traceContext.pop();
- if (tibImageAddress.EQ(OBJECT_NOT_ALLOCATED)) {
- fail("can't copy tib for " + jdkObject);
- }
- VM_ObjectModel.setTIB(bootImage, mapEntry.imageAddress, tibImageAddress, rvmType);
- }
-
- if (verbose >= 2) depth--;
-
- return mapEntry.imageAddress;
- } catch (Error e) {
- e = new Error(e.getMessage()+ "\nwhile copying " +
- jdkObject + (jdkObject != null ? ":"+jdkObject.getClass():"") + " from " +
- parentObject + (parentObject != null ? ":"+parentObject.getClass():""),
- e.getCause() != null? e.getCause() : e);
- throw e;
}
+ return arrayImageAddress;
}
+ /**
+ * Copy a unboxed array type to the boot image
+ * @param jdkObject object representation
+ * @param rvmArrayType type of array
+ * @param allocOnly allocate object don't write to fields
+ * @param overwriteAddress addresss to write to if overwriting
+ * @param parentObject object containing array
+ * @return address of array
+ * @throws IllegalAccessException
+ */
private static Address copyMagicArrayToBootImage(Object jdkObject,
VM_Array rvmArrayType,
boolean allocOnly,
Address overwriteAddress,
Object parentObject)
throws IllegalAccessException {
- //
// Return object if it is already copied and not being overwritten
- //
BootImageMap.Entry mapEntry = BootImageMap.findOrCreateEntry(jdkObject);
- if ((!mapEntry.imageAddress.EQ(OBJECT_NOT_ALLOCATED)) && overwriteAddress.isMax())
+ if ((!mapEntry.imageAddress.EQ(OBJECT_NOT_ALLOCATED)) && overwriteAddress.isMax()) {
return mapEntry.imageAddress;
+ }
if (verbose >= 2) depth++;
@@ -1982,7 +2268,7 @@
* @param rvmFieldName the name of the field
* @param rvmFieldType the type reference of the field
*/
- private static boolean copyKnownClasspathStaticField(Class jdkType, String rvmFieldName,
+ private static boolean copyKnownClasspathStaticField(Class> jdkType, String rvmFieldName,
VM_TypeReference rvmFieldType,
Offset rvmFieldOffset) {
if (jdkType.equals(java.lang.Number.class)) {
@@ -2128,7 +2414,7 @@
* @param jdkObject the object containing the field
* @param rvmFieldName the name of the field
* @param rvmFieldType the type reference of the field
- * @param rvmFieldAddress
+ * @param rvmFieldAddress the address that the field is being written to
*/
private static boolean copyKnownClasspathInstanceField(Object jdkObject, String rvmFieldName, VM_TypeReference rvmFieldType, Address rvmFieldAddress)
throws IllegalAccessException {
@@ -2165,9 +2451,9 @@
} else if (jdkObject == java.lang.Void.TYPE) {
value = VM_Type.VoidType;
} else {
- value = VM_TypeReference.findOrCreate((Class)jdkObject).peekType();
+ value = VM_TypeReference.findOrCreate((Class>)jdkObject).peekType();
if (value == null) {
- throw new Error("Failed to populate Class.type for " + jdkObject);
+ fail("Failed to populate Class.type for " + jdkObject);
}
}
fieldName = "type";
@@ -2197,7 +2483,7 @@
return false;
}
} else if (jdkObject instanceof java.lang.reflect.Constructor) {
- Constructor cons = (Constructor)jdkObject;
+ Constructor> cons = (Constructor>)jdkObject;
if(rvmFieldName.equals("cons")) {
// fill in this VM_Method field
String typeName = "L" + cons.getDeclaringClass().getName().replace('.','/') + ";";
@@ -2206,7 +2492,7 @@
throw new Error("Failed to find type for Constructor.constructor: " + cons + " " + typeName);
}
final VM_Class klass = type.asClass();
- Class[] consParams = cons.getParameterTypes();
+ Class>[] consParams = cons.getParameterTypes();
VM_Method constructor = null;
loop_over_all_constructors:
for (VM_Method vmCons : klass.getConstructorMethods()) {
@@ -2338,7 +2624,7 @@
//
// fetch object's type information
//
- Class jdkType = jdkObject.getClass();
+ Class> jdkType = jdkObject.getClass();
int size = OBJECT_HEADER_SIZE;
//
@@ -2351,7 +2637,7 @@
// traverse array elements
// recurse on values that are references
//
- Class jdkElementType = jdkType.getComponentType();
+ Class> jdkElementType = jdkType.getComponentType();
if (jdkElementType.isPrimitive()) {
// array element is logical or numeric type
if (jdkElementType == Boolean.TYPE) {
@@ -2403,12 +2689,12 @@
// traverse object fields
// recurse on values that are references
//
- for (Class type = jdkType; type != null; type = type.getSuperclass()) {
+ for (Class> type = jdkType; type != null; type = type.getSuperclass()) {
Field[] jdkFields = type.getDeclaredFields();
for (int i = 0, n = jdkFields.length; i < n; ++i) {
Field jdkField = jdkFields[i];
jdkField.setAccessible(true);
- Class jdkFieldType = jdkField.getType();
+ Class> jdkFieldType = jdkField.getType();
if (jdkFieldType.isPrimitive()) {
// field is logical or numeric type
@@ -2495,7 +2781,7 @@
* @return rvm type (null --> type does not appear in list of classes
* comprising bootimage)
*/
- private static VM_Type getRvmType(Class jdkType) {
+ private static VM_Type getRvmType(Class> jdkType) {
return bootImageTypes.get(jdkType.getName());
}
@@ -2505,7 +2791,7 @@
* @param rvmType rvm type
* @return jdk type (null --> type does not exist in host namespace)
*/
- private static Class getJdkType(VM_Type rvmType) {
+ private static Class> getJdkType(VM_Type rvmType) {
Throwable x;
try {
return Class.forName(rvmType.toString());
@@ -2537,7 +2823,7 @@
* @param isStatic is field from Static field table, indicates which table to consult
* @return field accessor (null --> host class does not have specified field)
*/
- private static Field getJdkFieldAccessor(Class jdkType, int index, boolean isStatic) {
+ private static Field getJdkFieldAccessor(Class> jdkType, int index, boolean isStatic) {
FieldInfo fInfo = bootImageTypeFields.get(new Key(jdkType));
Field f;
if (isStatic == STATIC_FIELD) {
@@ -2800,7 +3086,7 @@
}
// Extra information on the layout of objects in the boot image
- if (false) {
+ if (true) {
out.println();
out.println("Object Map");
out.println("----------");
@@ -2833,21 +3119,6 @@
}
/**
- * Read an integer value from the JTOC
- * @param jtocOff offset in JTOC
- * @return integer at offset
- */
- private static int getIVal(Offset jtocOff) {
- int ival;
- if (VM.BuildFor32Addr) {
- ival = VM_Statics.getSlotContentsAsInt(jtocOff);
- } else {
- ival = (int)VM_Statics.getSlotContentsAsLong(jtocOff); // just a cookie
- }
- return ival;
- }
-
- /**
* Read a reference from the JTOC
* @param jtocOff offset in JTOC
* @param fatalIfNotFound whether to terminate on failure
@@ -2905,4 +3176,93 @@
}
return backing;
}
+
+ /**
+ * Get the size of the object in the boot image
+ * @param type of object
+ * @param obj we want the size of
+ * @return size of object
+ */
+ private static int getSize(VM_Type type, Object obj) {
+ if (type.isArrayType()) {
+ if (type.getTypeRef().isUnboxedArrayType() ||
+ type.getTypeRef().isRuntimeTable() ||
+ obj instanceof AddressArray ||
+ obj instanceof VM_CodeArray ||
+ obj instanceof ExtentArray ||
+ obj instanceof ObjectReferenceArray ||
+ obj instanceof OffsetArray ||
+ obj instanceof WordArray) {
+ obj = getBackingArray(type, obj);
+ }
+ if (!obj.getClass().isArray()) {
+ fail("This should be an array " + obj.getClass() + " " + type);
+ }
+ return type.asArray().getInstanceSize(Array.getLength(obj));
+ } else {
+ return type.asClass().getInstanceSize();
+ }
+ }
+
+ private static final HashMap typeSizes = new HashMap();
+
+ /**
+ * Get the number of non-final references of the object in the boot image
+ * @param type of object
+ * @param obj we want the size of
+ * @return number of non-final references
+ */
+ private static int getNumberOfNonFinalReferences(VM_Type type, Object obj) {
+ if (type.isArrayType()) {
+ if (type.asArray().getElementType().isReferenceType()) {
+ if (obj instanceof ObjectReferenceArray) {
+ obj = getBackingArray(type, obj);
+ }
+ if (!obj.getClass().isArray()) {
+ fail("This should be an array " + obj.getClass() + " " + type);
+ }
+ return Array.getLength(obj);
+ } else {
+ return 0;
+ }
+ } else {
+ Integer size = typeSizes.get(type);
+ if (size == null) {
+ // discount final references that aren't part of the boot image
+ size = type.asClass().getNumberOfNonFinalReferences();
+ typeSizes.put(type, size);
+ }
+ return size;
+ }
+ }
+
+ /**
+ * Get the number of non-final references of the object in the boot image
+ * @param type of object
+ * @param obj we want the size of
+ * @return number of non-final references
+ */
+ private static int getNumberOfReferences(VM_Type type, Object obj) {
+ if (type.isArrayType()) {
+ if (type.asArray().getElementType().isReferenceType()) {
+ if (obj instanceof ObjectReferenceArray) {
+ obj = getBackingArray(type, obj);
+ }
+ if (!obj.getClass().isArray()) {
+ fail("This should be an array " + obj.getClass() + " " + type);
+ }
+ return Array.getLength(obj);
+ } else {
+ return 0;
+ }
+ } else {
+ Integer size = typeSizes.get(type);
+ if (size == null) {
+ // discount final references that aren't part of the boot image
+ size = type.asClass().getReferenceOffsets().length;
+ typeSizes.put(type, size);
+ }
+ return size;
+ }
+ }
}
Index: tools/bootImageWriter/src/org/jikesrvm/tools/bootImageWriter/BootImageMap.java
===================================================================
--- tools/bootImageWriter/src/org/jikesrvm/tools/bootImageWriter/BootImageMap.java (revision 14341)
+++ tools/bootImageWriter/src/org/jikesrvm/tools/bootImageWriter/BootImageMap.java (working copy)
@@ -15,7 +15,10 @@
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
+import java.util.LinkedList;
+import java.util.Queue;
import org.vmmagic.unboxed.Address;
+import org.jikesrvm.classloader.VM_TypeReference;
/**
* Correlate objects in host jdk with corresponding objects in target rvm
@@ -31,7 +34,7 @@
/**
* objectId->Entry map
*/
- private static final ArrayList objectIdToEntry;
+ static final ArrayList objectIdToEntry;
/**
* Entry used to represent null object
@@ -58,7 +61,8 @@
objectIdToEntry = new ArrayList(5000);
idGenerator = 0;
// predefine "null" object
- nullEntry = new Entry(newId(), null, Address.zero());
+ nullEntry = new Entry(newId(), null);
+ nullEntry.imageAddress = Address.zero();
// slot 0 reserved for "null" object entry
objectIdToEntry.add(nullEntry);
}
@@ -125,17 +129,58 @@
*/
Address imageAddress;
+ public static class LinkInfo {
+ final Address addressToFixup;
+ final boolean objField;
+ final boolean root;
+ final String rvmFieldName;
+ final VM_TypeReference rvmFieldType;
+ final Object parent;
+ LinkInfo(Address a, boolean o, boolean r, String rvmFieldName, VM_TypeReference rvmFieldType, Object parent) {
+ addressToFixup = a;
+ objField = o;
+ root = r;
+ this.rvmFieldName = rvmFieldName;
+ this.rvmFieldType = rvmFieldType;
+ this.parent = parent;
+ }
+ }
+
/**
+ * A list of addresses where when this value is not OBJECT_NOT_ALLOCATED
+ */
+ private Queue linkingAddresses;
+
+ /**
* Constructor.
* @param objectId unique id
* @param jdkObject the JDK object
* @param imageAddress the address of the object in the bootimage
*/
- public Entry(Address objectId, Object jdkObject, Address imageAddress) {
+ public Entry(Address objectId, Object jdkObject) {
this.objectId = objectId;
this.jdkObject = jdkObject;
- this.imageAddress = imageAddress;
+ this.imageAddress = OBJECT_NOT_ALLOCATED;
}
+
+ synchronized void addLinkingAddress(Address toBeLinked, boolean objField, boolean root, String rvmFieldName, VM_TypeReference rvmFieldType, Object parent) {
+ if (linkingAddresses == null) {
+ linkingAddresses = new LinkedList();
+ }
+ linkingAddresses.add(new LinkInfo(toBeLinked, objField, root, rvmFieldName, rvmFieldType, parent));
+ }
+
+ synchronized LinkInfo removeLinkingAddress() {
+ if (linkingAddresses == null) {
+ return null;
+ } else {
+ if (linkingAddresses.peek() != null) {
+ return linkingAddresses.remove();
+ } else {
+ return null;
+ }
+ }
+ }
}
/**
@@ -154,7 +199,7 @@
Key key = new Key(jdkObject);
Entry entry = keyToEntry.get(key);
if (entry == null) {
- entry = new Entry(newId(), jdkObject, OBJECT_NOT_ALLOCATED);
+ entry = new Entry(newId(), jdkObject);
keyToEntry.put(key, entry);
objectIdToEntry.add(entry);
}