gen_markcompact.c
来自「This is a resource based on j2me embedde」· C语言 代码 · 共 1,514 行 · 第 1/4 页
C
1,514 行
return; } /* * ROM objects should have been filtered out by the time we get here */ CVMassert(!CVMobjectIsInROM(ref)); /* * If this object has not been encountered yet, queue it up. */ if (!CVMobjectMarked(ref)) { CVMClassBlock *cb = CVMobjectGetClass(ref); CVMobjectSetMarked(ref); /* queue it up */ CVMtraceGcCollect(("GC[MC,%d]: Graying object %x\n", thisGen->gen.generationNo, ref)); /* If the object is an array of a basic type or if it is an instance of java.lang.Object, then it contains no references. Hence, no need to queue it for further root traversal: */ if (!CVMisArrayOfAnyBasicType(cb) && (cb != CVMsystemClass(java_lang_Object))) { /* If we get here, then the object might contain some refs. Need to queue it to check for refs later: */ addToTodo(thisGen, ref); } }}static voidCVMgenMarkCompactFilteredUpdateRoot(CVMObject** refPtr, void* data){ CVMGenMarkCompactGeneration* thisGen = (CVMGenMarkCompactGeneration*)data; CVMObject* ref = *refPtr; if (!CVMgenMarkCompactInGeneration(thisGen, ref)) { return; } /* The forwarding address is valid only for already marked objects. If the object is not marked, then this slot has already been 'seen'. */ CVMassert(CVMobjectMarked(ref)); *refPtr = CVMgenMarkCompactGetForwardingPtr(ref);}typedef struct CVMGenMarkCompactTransitiveScanData { CVMExecEnv* ee; CVMGCOptions* gcOpts; CVMGenMarkCompactGeneration* thisGen;} CVMGenMarkCompactTransitiveScanData;/* Scan and mark the references within an object and add them to the todo list if necessary. */static voidCVMgenMarkCompactBlackenObject(CVMGenMarkCompactTransitiveScanData* tsd, CVMObject* ref, CVMClassBlock* refCb){ CVMGenMarkCompactGeneration* thisGen = tsd->thisGen; CVMExecEnv* ee = tsd->ee; CVMGCOptions* gcOpts = tsd->gcOpts; CVMassert(ref != 0); CVMtraceGcCollect(("GC[MC,%d,full]: Blacken object %x\n", thisGen->gen.generationNo, ref)); /* * We'd better have grayed this object already. */ CVMassert(CVMobjectMarked(ref)); /* * Queue up all non-null object references. Handle the class as well. */ CVMobjectWalkRefsWithSpecialHandling(ee, gcOpts, ref, refCb, { if (*refPtr != 0) { CVMgenMarkCompactGrayObject(refPtr, thisGen); } }, CVMgenMarkCompactGrayObject, thisGen);}/* Scan all references in the objects that have been placed on the todo list so that all the children can be scanned and marked as well. */static voidCVMgenMarkCompactFollowRoots(CVMGenMarkCompactGeneration* thisGen, CVMGenMarkCompactTransitiveScanData* tsd){ CVMtraceGcCollect(("GC[MC,%d]: Following roots\n", thisGen->gen.generationNo)); /* Go through the todo list and blacken each object in it. To blacken means to scan the references it contains. Note that this may cause more referred objects to be put on the todolist. We'lll just keep processing the todo list until all objects in it has been blackened. */ while (!todoListIsEmpty(thisGen)) { CVMObject* ref = popFromTodo(thisGen); CVMClassBlock* refCB = CVMobjectGetClass(ref); /* Blackening may queue up more objects: */ CVMgenMarkCompactBlackenObject(tsd, ref, refCB); }}/* Mark the specified object as live and add it to a todo list so that its children can be scanned and marked as live too. */static voidCVMgenMarkCompactScanTransitively(CVMObject** refPtr, void* data){ CVMGenMarkCompactTransitiveScanData* tsd = (CVMGenMarkCompactTransitiveScanData*)data; CVMGenMarkCompactGeneration* thisGen = tsd->thisGen; CVMassert(refPtr != 0); CVMassert(*refPtr != 0); /* Mark the immediate object and put it on the todo list to have its children scanned as well if necessary: */ CVMgenMarkCompactGrayObject(refPtr, thisGen); /* Now scan all its children as well by going through the todo list: */ CVMgenMarkCompactFollowRoots(thisGen, tsd);}/* * Test whether a given reference is live or dying. If the reference * does not point to the current generation, answer TRUE. The generation * that does contain the pointer will give the right answer. */static CVMBoolCVMgenMarkCompactRefIsLive(CVMObject** refPtr, void* data){ CVMObject* ref; CVMassert(refPtr != NULL); ref = *refPtr; CVMassert(ref != NULL);#ifdef CVM_INSPECTOR /* If the VM inspector wants to force all objects to be alive, then we'll say that the object is alive regardless of whether it is reachable or not: */ if (CVMglobals.inspector.keepAllObjectsAlive) { return CVM_TRUE; }#endif /* * ROM objects are always live */ if (CVMobjectIsInROM(ref)) { return CVM_TRUE; } /* Did somebody else already scan or forward this object? It's live then */ return CVMobjectMarked(ref);}static CVMBoolCVMgenMarkCompactCollect(CVMGeneration* gen, CVMExecEnv* ee, CVMUint32 numBytes, /* collection goal */ CVMGCOptions* gcOpts){ CVMGenMarkCompactTransitiveScanData tsd; CVMGenMarkCompactGeneration* thisGen = (CVMGenMarkCompactGeneration*)gen; CVMBool success; CVMGenSpace* extraSpace; CVMUint32* newAllocPtr; CVMGeneration* youngGen = gen->prevGen; CVMtraceGcCollect(("GC[MC,%d,full]: Starting GC\n", gen->generationNo)); CVMtraceGcStartStop(("GC[MC,%d,full]: Collecting\n", gen->generationNo)); CVMassert(GC_PHASE_RESET == thisGen->gcPhase); extraSpace = youngGen->getExtraSpace(youngGen); if (setjmp(thisGen->errorContext) != 0) { goto handleError; } /* Initialize the todoList for use in the "mark" phase of the GC: */ /* Prepare the data structure that preserves original second header words for use in the TODO stack. */ thisGen->preservedItems = (CVMMCPreservedItem*)extraSpace->allocBase; thisGen->preservedIdx = 0; thisGen->preservedSize = (CVMUint32) ((CVMMCPreservedItem*)extraSpace->allocTop - (CVMMCPreservedItem*)extraSpace->allocBase); thisGen->todoList = NULL; /* * Prepare to do transitive scans */ tsd.ee = ee; tsd.gcOpts = gcOpts; tsd.thisGen = thisGen; /* The mark phase */ thisGen->gcPhase = GC_PHASE_MARK; gcOpts->discoverWeakReferences = CVM_TRUE; /* * Scan all roots that point to this generation. The root callback is * transitive, so 'children' are aggressively processed. */ CVMgenScanAllRoots((CVMGeneration*)thisGen, ee, gcOpts, CVMgenMarkCompactScanTransitively, &tsd); CVMthreadSchedHook(CVMexecEnv2threadID(ee)); /* * Don't discover any more weak references. */ gcOpts->discoverWeakReferences = CVM_FALSE; /* * At this point, we know which objects are live and which are not. * Do the special objects processing. */ /* NOTE: ProcessSpecial will call ProcessWeakrefWithLivenessInfo(). However, all transitive scans of weakref related objects will be done before its FinalizeProcessing(). Hence, we'll be able to use CVMweakrefCleanUpForGCAbort() to clean up should we encounter an abort error here because we're guaranteed that we won't encounter it in FinalizeProcessing() even though it does a transitive scan. Its transitive scan will always turn up objects that has already been scanned previously thereby requiring no work that can cause an abort. The processing of interned strings can cause some String objects to be marked. In an abort situation, this is all cleaned up properly by the global unmarks() done in the handleError code below. The processing of unreferencedMonitors will cause those monitors to be released back into the system. This side-effect is harmless and need not be undone. It's as if we did a partial collection where we only collected unreferenced monitors. Since the collection is only done for objects that are no longer live anyway, the object cannot be synchronized on. Hence, it's safe to collect the monitor. */ gcOpts->isUpdatingObjectPointers = CVM_FALSE; CVMgcProcessSpecialWithLivenessInfo(ee, gcOpts, CVMgenMarkCompactRefIsLive, thisGen, CVMgenMarkCompactScanTransitively, &tsd); gcOpts->isUpdatingObjectPointers = CVM_TRUE; /* Reset the data structure that preserves original second header words. We are done with the TODO stack, so we can re-use extraSpace. */ thisGen->preservedItems = (CVMMCPreservedItem*)extraSpace->allocBase; CVMassert(thisGen->preservedIdx == 0); CVMassert(thisGen->preservedSize == (CVMUint32) ((CVMMCPreservedItem*)extraSpace->allocTop - (CVMMCPreservedItem*)extraSpace->allocBase)); /* The sweep phase. This phase computes the new addresses of each object and writes it in the second header word. Evacuated original header words will be kept in the 'preservedItems' list. */ /* NOTE: If an abort happens here within the sweep phase, no weakref processing is involved. Weakref constructs are only updated after the sweeping action of computing forwarding pointers is completed at which point no GC abort can occur. Hence, no cleanup action is required for weakrefs in the sweep phase. The same is true for the processing of interned strings. */ thisGen->gcPhase = GC_PHASE_SWEEP; newAllocPtr = sweep(ee, thisGen, gen->allocBase, gen->allocPtr); CVMassert(newAllocPtr <= gen->allocPtr); /* At this point, the new addresses of each object are written in the headers of the old. Update all pointers to refer to the new copies. */ /* Update the roots */ CVMgenScanAllRoots((CVMGeneration*)thisGen, ee, gcOpts, CVMgenMarkCompactFilteredUpdateRoot, thisGen); CVMgcScanSpecial(ee, gcOpts, CVMgenMarkCompactFilteredUpdateRoot, thisGen); /* NOTE: CVMgenScanAllRoots() only scan the tree of GC roots. Unlike in the mark phase, the scan is not being done transitively. Hence, the objects in the heap are not scanned as part of this traversal. So, we must scan the heap objects explicitly here: */ /* Update all interior pointers. */ scanObjectsInYoungGenRange(thisGen, ee, gcOpts, youngGen->allocBase, youngGen->allocPtr); scanObjectsInRangeSkipUnmarked(thisGen, ee, gcOpts, gen->allocBase, gen->allocPtr); /* Unmark: Clear/reset marks on the objects in the youngGen: */ unmark(thisGen, youngGen->allocBase, youngGen->allocPtr); /* Compact: Move objects and reset marks in the oldGen: */ compact(ee, thisGen, gen->allocBase, gen->allocPtr); /* Restore the "non-trivial" old header words into the object header words which were used for storing forwarding addresses: */ restorePreservedHeaderWords(thisGen); /* Update the allocation pointers: */ gen->allocPtr = newAllocPtr; gen->allocMark = newAllocPtr; /* * Now since we are not in the young generation, we have to * rebuild the barrier structures. */ CVMgenClearBarrierTable(); CVMgenMarkCompactRebuildBarrierTable(thisGen, ee, gcOpts, gen->allocBase, gen->allocPtr); thisGen->gcPhase = GC_PHASE_RESET; /* Determine if we succeed or not based on whether we were able to free up a contiguous chunk of memory of the requested size: */ success = (numBytes/4 <= (CVMUint32)(gen->allocTop - gen->allocPtr)); CVMtraceGcStartStop(("GC[MC,%d,full]: Done, success for %d bytes %s\n", gen->generationNo, numBytes, success ? "TRUE" : "FALSE")); CVMtraceGcCollect(("GC[MC,%d,full]: Ending GC\n", gen->generationNo)); /* * Can we allocate in this space after this GC? */ return success;handleError: /* Undo side-effects of work done before error was detected: */ if (thisGen->gcPhase == GC_PHASE_MARK) { /* Undo the effects of the mark phase: */ /* Restore all the headerwords in the todoList: */ while (!todoListIsEmpty(thisGen)) { popFromTodo(thisGen); } /* Removed all the marks from the objects in both generations: */ unmark(thisGen, youngGen->allocBase, youngGen->allocPtr); unmark(thisGen, gen->allocBase, gen->allocPtr); } else if (thisGen->gcPhase == GC_PHASE_SWEEP) { /* Undo the effects of the sweep phase: */ /* Reset the data structure that preserves original second header words. We are done with the TODO stack, so we can re-use extraSpace. */ thisGen->preservedItems = (CVMMCPreservedItem*)extraSpace->allocBase; thisGen->preservedIdx = 0; thisGen->preservedSize = (CVMUint32) ((CVMMCPreservedItem*)extraSpace->allocTop - (CVMMCPreservedItem*)extraSpace->allocBase); unmark(thisGen, youngGen->allocBase, youngGen->allocPtr); unsweepAndUnmark(thisGen, gen->allocBase, gen->allocPtr);#ifdef CVM_DEBUG } else { CVMpanic("Unknown GC phase!");#endif } CVMweakrefCleanUpForGCAbort(ee); thisGen->gcPhase = GC_PHASE_RESET; return CVM_FALSE;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?