📄 gc_impl.c
字号:
/* * @(#)gc_impl.c 1.61 06/10/10 * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. * *//* * This file includes the implementation of a simple, * semispace copying collector. */#include "javavm/include/defs.h"#include "javavm/include/objects.h"#include "javavm/include/classes.h"#include "javavm/include/directmem.h"#include "javavm/include/porting/time.h"/* * This file is generated from the GC choice given at build time. */#include "generated/javavm/include/gc_config.h"#include "javavm/include/gc_common.h"#include "javavm/include/gc/gc_impl.h"#include "javavm/include/gc/semispace/semispace.h"#ifdef CVM_JVMPI#include "javavm/include/jvmpi_impl.h"#endif/* * Time of the last major GC */static CVMInt64 lastMajorGCTime;/* * Define to GC on every n-th allocation try *//*#define CVM_SS_GC_ON_EVERY_ALLOC*/#define CVM_SS_NO_ALLOCS_UNTIL_GC 1/* * GC when 1 / CVM_SS_GC_THRESHOLD remains of the current semispace */#define CVM_SS_GC_THRESHOLD 8/* * A quick way to get to the heap */static CVMSsHeap* theHeap = 0;#ifdef CVM_JVMPI/* The number of live objects at the end of the GC cycle: */static CVMUint32 liveObjectCount;#endif/* * The quick access to the allocation semispace */static CVMUint32* allocPtr;static CVMUint32* allocBase;static CVMUint32* allocTop;/* * The threshold at which to GC */static CVMUint32* allocThreshold;/* * The pointers used for the Cheney style copying. After the root * scan, [copyBase, copyTop) includes all root objects. We copy all * live objects starting from copyBase. We increment copyTop when a * new object is copied. Copying is all done when copyBase == copyTop. */static CVMUint32* copyBase;static CVMUint32* copyTop;/* * Initialize GC global state */voidCVMgcimplInitGlobalState(CVMGCGlobalState* globalState){ CVMtraceMisc(("GC: Initializing global state for semi-space copying GC\n")); theHeap = 0; allocPtr = 0; allocBase = 0; allocTop = 0; allocThreshold = 0; copyBase = 0; copyTop = 0;}/* * The 'forwarded' array maps each allocated word to a bit. * * For a given "byte index" byteIdx_ in the heap, CVM_SS_BITMAP_IDX * finds the corresponding bitmap word for byteIdx_, and * CVM_SS_BITMAP_MASK computes the appropriate bit mask. */#define CVM_SS_BITMAP_IDX(byteIdx_) ((byteIdx_) >> 7)#define CVM_SS_BITMAP_MASK(byteIdx_) (1 << (((byteIdx_) & 0x7f) / 4))/* * Set bit corresponding to heap addr 'addr' in the bits array * (the forwarded array) */static voidCVMssSetBitFor(CVMUint32* heapPtr, CVMUint32* bitmap){ CVMUint32 byteIdx; CVMassert((heapPtr >= allocBase) && (heapPtr < allocTop)); byteIdx = (CVMUint8*)heapPtr - (CVMUint8*)allocBase; bitmap[CVM_SS_BITMAP_IDX(byteIdx)] |= CVM_SS_BITMAP_MASK(byteIdx);}/* * Check if bit corresponding to heap addr 'addr' in a bits array is marked. */static CVMBoolCVMssMarkedIn(CVMUint32* heapPtr, CVMUint32* bitmap){ CVMUint32 byteIdx; CVMassert((heapPtr >= allocBase) && (heapPtr < allocTop)); byteIdx = (CVMUint8*)heapPtr - (CVMUint8*)allocBase; return ((bitmap[CVM_SS_BITMAP_IDX(byteIdx)] & CVM_SS_BITMAP_MASK(byteIdx)) != 0);}static CVMSsSemispace*CVMssAllocSemiSpace(CVMUint32 noBytes){ CVMUint32 allocSize = sizeof(CVMSsSemispace) - sizeof(CVMUint32) + noBytes; CVMSsSemispace* space = (CVMSsSemispace*)malloc(allocSize); CVMUint32 noWords = noBytes / 4; if (space != 0) { space->topData = &space->data[noWords]; space->allocPtr = &space->data[0]; /* %comment:f008 */ space->threshold = space->topData - noWords / CVM_SS_GC_THRESHOLD; } return space;}static voidCVMssMakeSpaceCurrent(CVMSsSemispace* space){ allocPtr = space->allocPtr; allocBase = space->data; allocTop = space->topData; allocThreshold = space->threshold;}/* * Initialize a heap of 'heapSize' bytes. heapSize is guaranteed to be * divisible by 4. *//* Returns: CVM_TRUE if successful, else CVM_FALSE. */CVMBoolCVMgcimplInitHeap(CVMGCGlobalState* globalState, CVMUint32 startSize, CVMUint32 minHeapSize, CVMUint32 maxHeapSize, CVMBool startIsUnspecified, CVMBool minIsUnspecified, CVMBool maxIsUnspecified){ CVMSsHeap* heap = (CVMSsHeap*)calloc(sizeof(CVMSsHeap), 1); CVMSsSemispace* fromSpace; CVMSsSemispace* toSpace; CVMUint32 heapSize = maxHeapSize; if (heap == 0) { return CVM_FALSE; } /* * The area for the objects. The initialization code must have * rounded heapSize up to the nearest double-word multiple. */ CVMassert(heapSize % 8 == 0); heap->size = heapSize; fromSpace = CVMssAllocSemiSpace(heapSize); toSpace = CVMssAllocSemiSpace(heapSize); if ((fromSpace == 0) || (toSpace == 0)) { free(fromSpace); free(toSpace); return CVM_FALSE; } /* * Initialize heap. */ heap->from = fromSpace; heap->to = toSpace; /* The following need a bit per word allocated */ heap->sizeOfBitmaps = (heapSize + 31) / 32; heap->forwarded = (CVMUint32*)calloc(heap->sizeOfBitmaps, 1); if (heap->forwarded == 0) { free(fromSpace); free(toSpace); return CVM_FALSE; }#ifdef CVM_JVMPI liveObjectCount = 0;#endif /* * Now make the heap visible to the outside world. */ globalState->heap = heap; theHeap = heap; /* * Start the world on fromSpace */ CVMssMakeSpaceCurrent(fromSpace); /* * Initialize GC times. Let heap initialization be the first * major GC. */ lastMajorGCTime = CVMtimeMillis();#ifdef CVM_JVMPI CVMgcimplPostJVMPIArenaNewEvent();#endif CVMtraceMisc(("GC: Initialized heap for semi-space copying GC\n")); return CVM_TRUE;}/* * The alloc* pointers are still pointing to the old semispace at * GC time. */static CVMBoolCVMssInOldSemispace(CVMObject* ref){ CVMUint32* ptr = (CVMUint32*)ref; return ((ptr >= allocBase) && (ptr < allocTop));}#if defined(CVM_JVMPI) || defined(CVM_JVMTI)/* Purpose: Checks to see if the specified object pointer is in the range of the new semispace (i.e. the copy space). */static CVMBoolCVMssInNewSemispace(CVMObject *ref){ CVMUint32* ptr = (CVMUint32*)ref; return ((ptr >= copyBase) && (ptr < copyTop));}#endifstatic CVMObject*CVMssGetForwardingPtr(CVMObject* ref){ CVMUint32* objData = (CVMUint32*)ref; /* The old data for object */ CVMassert(CVMssInOldSemispace(ref)); CVMassert(CVMssMarkedIn(objData, theHeap->forwarded)); return (CVMObject*)objData[0];}/* * Copy numBytes from 'source' to 'dest'. Assume word copy, and assume * that the copy regions are disjoint. */static voidCVMssCopyDisjointWords(CVMUint32* dest, CVMUint32* source, CVMUint32 numBytes){ CVMUint32* sourceEnd = source + numBytes / 4; while (source < sourceEnd) { *dest++ = *source++; }}/* * Copy object, leave forwarding pointer behind */static CVMObject*CVMssForwardObject(CVMObject* ref){ CVMUint32 objSize = CVMobjectSize(ref); CVMObject* ret = (CVMObject*)copyTop; /* The copy destination */ CVMUint32* objData = (CVMUint32*)ref; /* The old data for object */ CVMtraceGcCollect(("GC: Forwarding object %x (len %d, class %C), to %x\n", ref, objSize, CVMobjectGetClass(ref), copyTop)); CVMssCopyDisjointWords(copyTop, objData, objSize); copyTop += objSize / 4;#ifdef CVM_JVMPI if (CVMjvmpiEventObjectMoveIsEnabled()) { CVMjvmpiPostObjectMoveEvent(1, objData, 1, copyTop); }#endif /* * Set forwarding pointer */ CVMssSetBitFor(objData, theHeap->forwarded); objData[0] = (CVMUint32)ret; return ret;}/* * Gray an object known to be in the old semispace */static voidCVMssGrayObject(CVMObject** refPtr){ CVMObject* ref = *refPtr; CVMtraceGcCollect(("GC: Graying object %x\n", ref)); /* * Don't deal with ROM objects */ if (CVMobjectIsInROM(ref)) { CVMtraceGcCollect(("GC: Ignoring ROM object %x\n", ref)); return; } /* we should not be trying to gray things already pointing to the new semispace. */ CVMassert(CVMssInOldSemispace(ref)); /* * If the object is in old space it might already be * forwarded. Check that. If it has been forwarded, set the slot * to refer to the new copy. If it has not been forwarded, copy * the object, and set the forwarding pointer. */ if (CVMssMarkedIn((CVMUint32*)ref, theHeap->forwarded)) { *refPtr = CVMssGetForwardingPtr(ref); CVMtraceGcCollect(("GC: Object already forwarded: %x -> %x\n", ref, *refPtr)); } else { *refPtr = CVMssForwardObject(ref); }#if 0 /* * Debugging code that will tell you each time a ClassLoader or * Class instance is reached. Useful for debugging class unloading. */ { CVMClassBlock* cb = CVMobjectGetClass(*refPtr); while (cb != NULL) { if (cb == CVMsystemClass(java_lang_ClassLoader)) { CVMconsolePrintf("grey: %O\n", *refPtr); } cb = CVMcbSuperclass(cb); } } if (CVMobjectGetClass(*refPtr) == CVMsystemClass(java_lang_Class)) { CVMClassBlock* cb = *((CVMClassBlock**)(*refPtr) + CVMoffsetOfjava_lang_Class_classBlockPointer); if (CVMcbClassLoader(cb) != NULL) { CVMconsolePrintf("grey: %C\n", cb); } }#endif}#ifdef DEBUG/* * Utility function to get an object reference, forwarded or not */CVMObject*CVMssGetObject(CVMObject* ref){ if (ref == NULL) { return ref; } if (CVMobjectIsInROM(ref)) { return ref; } if (CVMssMarkedIn((CVMUint32*)ref, theHeap->forwarded)) { return CVMssGetForwardingPtr(ref); } else { return ref; }}#endif/* * Copy one object to the next space. This is passed as a callback to * the class scanners. */static voidCVMssHandleNonNullReference(CVMObject** ref, void* data){ CVMassert(ref != 0); CVMassert(*ref != 0); CVMtraceGcScan(("GC: Root: [0x%x] = 0x%x\n", ref, *ref));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -