gc_impl.c
来自「This is a resource based on j2me embedde」· C语言 代码 · 共 1,897 行 · 第 1/5 页
C
1,897 行
numRefs++; } } } else CVMobjectWalkRefs(ee, gcOpts, currObj, currCb, { CVMJavaVal32* heapRef = *((CVMJavaVal32**)refPtr); /* * Handle the range check here. If the pointer we found * points to the old generation, * don't do the callback. We are only interested in pointers * to the young generation. * * This one filters out NULL pointers as well. * * %comment: f011 */ /* Only scan youngGen pointers: */ if ((heapRef >= youngGenStart) && (heapRef < youngGenEnd)) { if ((CVMJavaVal32*)refPtr >= regionEnd) { /* We ran off the edge of the card */ goto returnStatus; } else if ((CVMJavaVal32*)refPtr >= regionStart) { /* Call the callback if we are within the bounds */ if (numRefs < CVM_GENGC_SUMMARY_COUNT) { summEntry->offsets[numRefs] = (CVMUint8) ((CVMJavaVal32*)refPtr - cardBoundary); } numRefs++; (*callback)(refPtr, callbackData); } } }); /* iterate */ curr += objSize / sizeof(CVMJavaVal32); } returnStatus: /* If already marked dirty, don't undo it. Otherwise figure out what flag card should contain */ if (scanStatus != CARD_DIRTY_BYTE) { if (numRefs == 0) { scanStatus = CARD_CLEAN_BYTE; } else if (numRefs <= CVM_GENGC_SUMMARY_COUNT) { scanStatus = CARD_SUMMARIZED_BYTE; } else { scanStatus = CARD_DIRTY_BYTE; } } return scanStatus;}/* Purpose: Given the starting address for the heap location that correspond to the specified card, find the starting address of the object that occupies the specified heap address. */static CVMJavaVal32* findObjectStart(CVMUint8* card, CVMJavaVal32* heapAddrForCard){ CVMInt8* hdr = HEADER_TABLE_SLOT_ADDRESS_FOR_CARD(card); CVMInt8 n; /* The header table entry must be within the range of the header table: */ CVMassert(hdr >= CVMglobals.gc.objectHeaderTable); CVMassert(hdr < CVMglobals.gc.objectHeaderTable + CVMglobals.gc.cardTableSize); /* The header info from the entry is encoded in the following way: 1. If the header info is >= 0, then it represents the absolute value of the negative offset (in terms of number of words) from the specified heap address to the start of the object that occupies that heap address. The start address of the object is less that the specified heap address by definition. Hence, the start address of the object is computed by: obj = heapAddrForCard - n; 2. If the header info is < 0, then it represents the negative offset to the next piece of header info that may contain the offset to the start of the object as in case 1 above. Since the maximum negative offset is -128, if the actual offset to the header info that contains the object header offset is greater than -128, then the info will be expressed in a chain of -128 (or greater) offsets until we come to a positive header info which will be intepreted analogously as is done in case 1 above. */ n = *hdr; CVMassert(HEAP_ADDRESS_FOR_CARD(card) == heapAddrForCard); if (n >= 0) { return heapAddrForCard - n; } else { CVMJavaVal32* heapAddr = heapAddrForCard; do { hdr = hdr + n; /* Go back! */ heapAddr = heapAddr + n * NUM_WORDS_PER_CARD; CVMassert(hdr >= CVMglobals.gc.objectHeaderTable); CVMassert(hdr < CVMglobals.gc.objectHeaderTable + CVMglobals.gc.cardTableSize); n = *hdr; } while (n < 0); CVMassert(heapAddr < heapAddrForCard); return heapAddr - n; }}/*#define CARD_STATS*/#ifdef CARD_STATStypedef struct cardStats { CVMUint32 cardsScanned; CVMUint32 cardsSummarized; CVMUint32 cardsClean; CVMUint32 cardsDirty;} cardStats;static cardStats cStats = {0, 0, 0, 0};#define cardStatsOnly(x) x#else#define cardStatsOnly(x)#endifstatic voidcallbackIfNeeded(CVMExecEnv* ee, CVMGCOptions* gcOpts, CVMUint8* card, CVMJavaVal32* lowerLimit, CVMJavaVal32* higherLimit, CVMUint32* genLower, CVMUint32* genHigher, CVMRefCallbackFunc callback, void* callbackData){ CVMassert(card >= CVMglobals.gc.cardTable); CVMassert(card < CVMglobals.gc.cardTable + CVMglobals.gc.cardTableSize); cardStatsOnly(cStats.cardsScanned++); switch (*card) { case CARD_SUMMARIZED_BYTE: { /* * This card has not been dirtied since it was summarized. Scan the * summary. */ CVMJavaVal32* cardBoundary = CARD_BOUNDARY_FOR(lowerLimit); CVMGenSummaryTableEntry* summEntry = SUMMARY_TABLE_SLOT_ADDRESS_FOR_CARD(card); CVMUint32 i; CVMBool hasNoCrossGenPointer = CVM_TRUE; CVMGeneration* youngGen = CVMglobals.gc.CVMgenGenerations[0]; CVMObject *youngGenStart = (CVMObject *)youngGen->heapBase; CVMObject *youngGenEnd = (CVMObject *)youngGen->heapTop; CVMUint8 offset; i = 0; /* If this card is summarized, it must have at least one entry */ CVMassert(summEntry->offsets[0] != 0xff); while ((i < CVM_GENGC_SUMMARY_COUNT) && ((offset = summEntry->offsets[i]) != 0xff)) { CVMObject** refPtr = (CVMObject**)(cardBoundary + offset); CVMObject *ref; /* We could not have summarized a NULL pointer */ CVMassert(*refPtr != NULL); (*callback)(refPtr, callbackData); /* Check to see if we still have a cross generational pointer: */ ref = *refPtr; if ((ref >= youngGenStart) && (ref < youngGenEnd)) { hasNoCrossGenPointer = CVM_FALSE; } i++; } /* If we didn't encounter any cross generational pointers, then all the pointers in this card must either have been nullified, or are now referring to objects which have been promoted to the oldGen. Hence, we can declare the card as clean to keep us from having to keep scanning it. If a cross-generational pointer gets added later, the card will be marked dirty by the write barrier. */ if (hasNoCrossGenPointer) { *card = CARD_CLEAN_BYTE; } CVMassert(i <= CVM_GENGC_SUMMARY_COUNT); cardStatsOnly(cStats.cardsSummarized++); } break; case CARD_DIRTY_BYTE: { CVMJavaVal32* objStart; CVMGenSummaryTableEntry* summEntry; /* Make sure the heap pointer and the card we are scanning are in alignment */ CVMassert(HEAP_ADDRESS_FOR_CARD(card) == CARD_BOUNDARY_FOR(lowerLimit)); CVMassert(higherLimit - lowerLimit <= NUM_WORDS_PER_CARD); objStart = findObjectStart(card, CARD_BOUNDARY_FOR(lowerLimit)); summEntry = SUMMARY_TABLE_SLOT_ADDRESS_FOR_CARD(card); *card = scanAndSummarizeObjectsOnCard(ee, gcOpts, objStart, summEntry, lowerLimit, higherLimit, genLower, callback, callbackData); cardStatsOnly(cStats.cardsDirty++); } break; case CARD_SENTINEL_BYTE: break; default: CVMassert(*card == CARD_CLEAN_BYTE); cardStatsOnly(cStats.cardsClean++); }}#define SENTINEL_WORD_VALUE \ ((CARD_SENTINEL_BYTE << 24ul) | \ (CARD_SENTINEL_BYTE << 16ul) | \ (CARD_SENTINEL_BYTE << 8ul) | \ (CARD_SENTINEL_BYTE << 0ul))#define SCAN_CHUNK_SIZE 500000#define FAST_SCAN_MINIMUM 8/* * Traverse all recorded pointers, and call 'callback' on each. */voidCVMgenBarrierPointersTraverse(CVMGeneration* gen, CVMExecEnv* ee, CVMGCOptions* gcOpts, CVMRefCallbackFunc callback, void* callbackData){ CVMUint8* lowerCardLimit; /* Card to begin scanning */ CVMUint8* higherCardLimit; /* Card to end scanning */ CVMUint32* cardPtrWord; /* Used for batch card scanning */ CVMJavaVal32* heapPtr; /* Track card boundaries in heap */ CVMAddr remainder; /* Batch scanning spillover */ CVMJavaVal32* genLower; /* Lower limit of live objects in gen */ CVMJavaVal32* genHigher; /* Higher limit of live objects in gen */ /* * Scan cards between lowerCardLimit and higherCardLimit * * Iterate only over those pointers that belong to the old * generation. Stores may have been recorded for the young one * as well, but we can ignore those. */ CVMtraceGcCollect(("GC[SS,%d,full]: " "Scanning barrier records for range [%x,%x)\n", gen->generationNo, gen->allocBase, gen->allocPtr)); /* We have to cover all pointers in [genLower,genHigher) */ genLower = (CVMJavaVal32*)gen->allocBase; genHigher = (CVMJavaVal32*)gen->allocPtr; /* ... and look at all the cards in [lowerCardLimit,higherCardLimit) */ lowerCardLimit = (CVMUint8*)CARD_TABLE_SLOT_ADDRESS_FOR(genLower); higherCardLimit = (CVMUint8*)CARD_TABLE_SLOT_ADDRESS_FOR(genHigher); if (gen->allocMark != gen->allocPtr) { /* If we get here, then we may have allocated some large objects directly from the old generation. While the card table is up to date, the object header table is not. So, we need to update that before we proceed with scanning the barrier for this region as well. */ CVMgenBarrierObjectHeadersUpdate(gen, ee, gcOpts, gen->allocMark, gen->allocPtr); } /* This is the heap boundary corresponding to the next card */ heapPtr = NEXT_CARD_BOUNDARY_FOR(genLower); /* * Scan the first card in range, which may be partial. */ /* Check whether the amount of data is really small or not */ if (genHigher < heapPtr) { /* This is really rare. So we might as well check for the condition that genLower == genHigher, i.e. an empty old generation! */ if (genLower == genHigher) { return; } callbackIfNeeded(ee, gcOpts, lowerCardLimit, genLower, genHigher, (CVMUint32*)genLower, (CVMUint32*)genHigher, callback, callbackData); return; /* Done, only one partial card! */ } else { callbackIfNeeded(ee, gcOpts, lowerCardLimit, genLower, heapPtr, (CVMUint32*)genLower, (CVMUint32*)genHigher, callback, callbackData); lowerCardLimit++; } /* * Have we already reached the end? */ if (lowerCardLimit == higherCardLimit) { if (heapPtr == genHigher) { return; /* nothing to do */ } /* * Make sure this is really the last card. */ CVMassert(genHigher - heapPtr < NUM_WORDS_PER_CARD); callbackIfNeeded(ee, gcOpts, lowerCardLimit, heapPtr, genHigher, (CVMUint32*)genLower, (CVMUint32*)genHigher, callback, callbackData); return; /* Done, only one partial card! */ } /* * How many individual card bytes are we going to look at until * we get to an integer boundary? */ remainder = CVMalignWordUp(lowerCardLimit) - (CVMAddr)lowerCardLimit; CVMassert(CARD_BOUNDARY_FOR(genLower) == genLower); /* * Get lowerCardLimit to a word boundary */ while ((remainder-- > 0) && (lowerCardLimit < higherCardLimit)) { callbackIfNeeded(ee, gcOpts, lowerCardLimit, heapPtr, heapPtr + NUM_WORDS_PER_CARD, (CVMUint32*)genLower, (CVMUint32*)genHigher, callback, callbackData); lowerCardLimit++; heapPtr += NUM_WORDS_PER_CARD; } /* * Nothing else to do */ if (lowerCardLimit == higherCardLimit) { if (heapPtr == genHigher) { return; /* nothing to do */ } /* Make sure that we are "on the same page", literally! */ CVMassert(HEAP_ADDRESS_FOR_CARD(higherCardLimit) == heapPtr); CVMassert(genHigher - heapPtr < NUM_WORDS_PER_CARD); callbackIfNeeded(ee, gcOpts, higherCardLimit, heapPtr, genHigher, (CVMUint32*)genLower, (CVMUint32*)genHigher, callback, callbackData); return; } /* * lowerCardLimit had better be at a word boundary */ CVMassert(CVMalignWordDown(lowerCardLimit) == (CVMAddr)lowerCardLimit); /* * Now adjust the higher card limit to a word boundary for batch * scanning. */ remainder = (CVMAddr)higherCardLimit - CVMalignWordDown(higherCardLimit); higherCardLimit -= remainder; CVMassert(CVMalignWordDown(higherCardLimit) == (CVMAddr)higherCardLimit); /* Need one word for sentinel, but don't bother with chunks for small sizes */ if (higherCardLimit - lowerCardLimit >= 4 + FAST_SCAN_MINIMUM) { remainder += 4; higherCardLimit -= 4; } else { remainder += higherCardLimit - lowerCardLimit; higherCardLimit = lowerCardLimit; goto scan_remainder; } /* * Now go through the card table in blocks of four for faster * zero checks. */ for (cardPtrWord = (CVMUint32*)lowerCardLimit; cardPtrWord < (CVMUint32*)higherCardLimit; ) { CVMUint32 *hl = cardPtrWord + SCAN_CHUNK_SIZE; CVMUint32 savedWord; if (hl > (CVMUint32*)higherCardLimit) { hl = (CVMUint32*)higherCardLimit; } savedWord = hl[0]; hl[0] = SENTINEL_WORD_VALUE; while (cardPtrWord < hl) { CVMUint32 word = *cardPtrWord; if (word == FOUR_CLEAN_CARDS) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?