本文介绍在压缩内存后更新对象引用的代码,这部分的代码如下:
// 修改指针
updateRootObjects(¤tTable);
updateHeapObjects(¤tTable, freeStart);
其中updateRootObjects的代码如下:
static void
updateRootObjects(breakTableStruct *currentTable)
{
HASHTABLE stringTable;
cellOrPointer *ptr, *endptr;
// 1. 修改roots 的指针
ptr = &GlobalRoots[0];
endptr = ptr + GlobalRootsLength;
for ( ; ptr < endptr; ptr++) {
updatePointer(ptr->cellpp, currentTable);
}
// 2. 修改临时root的指针
ptr = &TemporaryRoots[0];
endptr = ptr + TemporaryRootsLength;
for ( ; ptr < endptr; ptr++) {
cellOrPointer location = *ptr;
if (location.cell == -1) {
/* Actual Location is ptr[1], base is ptr[2] */
long offset = *(ptr[1].charpp) - ptr[2].charp;
updatePointer(&ptr[2], currentTable);
*(ptr[1].charpp) = ptr[2].charp + offset;
ptr += 2;
} else {
updatePointer(location.cellpp, currentTable);
}
}
#if ASYNCHRONOUS_NATIVE_FUNCTIONS
{
// 3. 修改ASYNCIOCB
int i;
for (i = 0 ; i < ASYNC_IOCB_COUNT ; i++) {
ASYNCIOCB *aiocb = &IocbRoots[i];
updatePointer(&aiocb->thread, currentTable);
updatePointer(&aiocb->instance, currentTable);
updatePointer(&aiocb->array, currentTable);
}
}
#endif
#if ROMIZING
{
/* In RELOCATABLE_ROM builds, we have a pointer to the static data.
* In !RELOCATABLE_ROM builds, we have the actual array.
*/
// 4. 修改静态指针
#if RELOCATABLE_ROM
long *staticPtr = KVM_staticDataPtr;
#else
long *staticPtr = KVM_staticData;
#endif
int refCount = staticPtr[0];
for( ; refCount > 0; refCount--) {
updatePointer(&staticPtr[refCount], currentTable);
}
}
#endif /* ROMIZING */
// 5. 修改InternStringTable
stringTable = InternStringTable;
if (ROMIZING || stringTable != NULL) {
int count = stringTable->bucketCount;
while (--count >= 0) {
INTERNED_STRING_INSTANCE instance =
(INTERNED_STRING_INSTANCE)stringTable->bucket[count];
for ( ; instance != NULL; instance = instance->next) {
updateMonitor((OBJECT)instance, currentTable);
}
}
}
// 6. 修改class
if (ROMIZING || ClassTable != NULL) {
FOR_ALL_CLASSES(clazz)
updateMonitor((OBJECT)clazz, currentTable);
if (!IS_ARRAY_CLASS(clazz)) {
INSTANCE_CLASS iclazz = (INSTANCE_CLASS)clazz;
POINTERLIST statics = iclazz->staticFields;
THREAD initThread = iclazz->initThread;
if (initThread != NULL) {
updatePointer(&initThread, currentTable);
setClassInitialThread(iclazz, initThread);
}
if (clazz->accessFlags & ACC_ROM_CLASS) {
continue;
}
if (USESTATIC) {
updatePointer(&iclazz->constPool, currentTable);
updatePointer(&iclazz->ifaceTable, currentTable);
updatePointer(&iclazz->fieldTable, currentTable);
updatePointer(&iclazz->methodTable, currentTable);
}
if (statics != NULL) {
int count = statics->length;
while (--count >= 0) {
updatePointer(&statics->data[count].cellp, currentTable);
}
}
if (iclazz->status == CLASS_VERIFIED) {
continue;
}
FOR_EACH_METHOD(thisMethod, iclazz->methodTable)
if (!(thisMethod->accessFlags & ACC_NATIVE)) {
if (!USESTATIC || inCurrentHeap(thisMethod)) {
updatePointer(&thisMethod->u.java.stackMaps.verifierMap, currentTable);
} else {
POINTERLIST oldValue = thisMethod->u.java.stackMaps.verifierMap;
POINTERLIST newValue = oldValue;
updatePointer(&newValue, currentTable);
if (oldValue != newValue) {
CONSTANTPOOL cp = iclazz->constPool;
int offset = (char *)&thisMethod->u.java.stackMaps.pointerMap
- (char *)cp;
modifyStaticMemory(cp, offset, &newValue, sizeof(POINTERLIST));
}
}
}
END_FOR_EACH_METHOD
}
END_FOR_ALL_CLASSES
}
}
此处比较重要的是updatePointer.其代码如下:
static void
updatePointer(void *address, breakTableStruct *currentTable)
{
breakTableEntryStruct *table;
cell *value = *(cell **)address;
int low, high, middle;
// 1. 如果address 不在合理的地址范围,则直接return
if (value == NULL || value < CurrentHeap || value >= CurrentHeapEnd) {
return;
}
low = -1;
high = currentTable->length - 1;
table = currentTable->table;
// 2. 通过2分查找,找到和address最接近的table
while (low < high) {
middle = (low + high + 1) >> 1;
if (value >= table[middle].address) {
low = middle;
} else {
high = middle - 1;
}
}
if (low != high) {
fatalError(KVM_MSG_BREAK_TABLE_CORRUPTED);
}
if (low < 0) {
/* We are smaller than the first item in the table 如果小于0,则意味着当前对象没有移动,因此不需要进行修改*/
} else {
int offset = table[low].offset; // 获得对象移动的偏移量
cell* result = PTR_OFFSET(value, -offset); // 获得对象移动后的值
*(cell **)address = result;// 修改引用
}
}
而updateHeapObjects的代码如下:
static void
updateHeapObjects(breakTableStruct *currentTable, cell* endScanPoint)
{
cell* scanner;
for ( scanner = CurrentHeap;
scanner < endScanPoint;
scanner += SIZE(*scanner) + HEADERSIZE) {
cell *header = scanner;
cell *object = scanner + 1;
GCT_ObjectType gctype = TYPE(*header);
switch (gctype) {
int length;
cell **ptr;
case GCT_INSTANCE:
case GCT_WEAKREFERENCE: {
/* The object is a Java object instance. Mark pointer fields */
INSTANCE instance = (INSTANCE)object;
INSTANCE_CLASS clazz = instance->ofClass;
updateMonitor((OBJECT)instance, currentTable);
while (clazz) {
FOR_EACH_FIELD(thisField, clazz->fieldTable)
/* Is this a non-static pointer field? */
if ((thisField->accessFlags & (ACC_POINTER | ACC_STATIC))
== ACC_POINTER) {
updatePointer(&instance->data[thisField->u.offset].cellp,
currentTable);
}
END_FOR_EACH_FIELD
clazz = clazz->superClass;
}
break;
}
case GCT_ARRAY: {
/* The object is a Java array with primitive values. */
/* Only the possible monitor will have to be marked alive. */
updateMonitor((OBJECT)object, currentTable);
}
break;
case GCT_POINTERLIST: {
POINTERLIST list = (POINTERLIST)object;
length = list->length;
ptr = &list->data[0].cellp;
goto markArray;
}
case GCT_WEAKPOINTERLIST: {
WEAKPOINTERLIST list = (WEAKPOINTERLIST)object;
length = list->length;
ptr = &list->data[0].cellp;
goto markArray;
}
case GCT_OBJECTARRAY: {
/* The object is a Java array with object references. */
/* The contents of the array and the possible monitor */
/* will have to be scanned. */
ARRAY array = (ARRAY)object;
updateMonitor((OBJECT)array, currentTable);
length = array->length;
ptr = &array->data[0].cellp;
/* FALL THROUGH */
}
markArray:
/* Keep objects in the array alive. */
while (--length >= 0) {
updatePointer(ptr, currentTable);
ptr++;
}
break;
case GCT_MONITOR: {
MONITOR monitor = (MONITOR)object;
updatePointer(&monitor->owner, currentTable);
updatePointer(&monitor->monitor_waitq, currentTable);
updatePointer(&monitor->condvar_waitq, currentTable);
#if INCLUDEDEBUGCODE
updatePointer(&monitor->object, currentTable);
#endif
break;
}
case GCT_THREAD: {
THREAD thread = (THREAD)object;
updatePointer(&thread->nextAliveThread, currentTable);
updatePointer(&thread->nextThread, currentTable);
updatePointer(&thread->javaThread, currentTable);
updatePointer(&thread->monitor, currentTable);
updatePointer(&thread->nextAlarmThread, currentTable);
updatePointer(&thread->stack, currentTable);
#if ENABLE_JAVA_DEBUGGER
{
updatePointer(&thread->stepInfo.fp, currentTable);
}
#endif
if (thread->fpStore != NULL) {
updateThreadAndStack(thread, currentTable);
}
break;
}
case GCT_METHODTABLE:
FOR_EACH_METHOD(thisMethod, ((METHODTABLE)object))
if ((thisMethod->accessFlags & ACC_NATIVE) == 0) {
updatePointer(&thisMethod->u.java.code, currentTable);
updatePointer(&thisMethod->u.java.handlers, currentTable);
}
END_FOR_EACH_METHOD
break;
case GCT_NOPOINTERS:
break;
case GCT_EXECSTACK:
/* This is handled by the thread that the stack belongs to. */
break;
default:
/* We should never get here as isValidHeapPointer should */
/* guarantee that the header tag of this object is in the */
/* range GCT_FIRSTVALIDTAG && GCT_LASTVALIDTAG */
fatalError(KVM_MSG_BAD_DYNAMIC_HEAP_OBJECTS_FOUND);
} /* End of switch statement */
} /* End of for statement */
}
此方法比较简单,其功能就是扫描堆中存活的对象,跟新对象的引用.其中updatePointer的方法已经在上文介绍过了.其余部分,结合之前文章的介绍也能看懂,此处就不做过多解释了.