/* Mark all objects referred to by the ClassObject. */ static void scanClassObject(const ClassObject *clazz, GcMarkContext *ctx) { LOGV_SCAN("---------> %s\n", clazz->name); if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) { /* We're an array; mark the class object of the contents * of the array. * * Note that we won't necessarily reach the array's element * class by scanning the array contents; the array may be * zero-length, or may only contain null objects. */ markObjectNonNull((Object *)clazz->elementClass, ctx); } /* We scan these explicitly in case the only remaining * reference to a particular class object is via a data * object; we may not be guaranteed to reach all * live class objects via a classloader. */ markObject((Object *)clazz->super, ctx); // may be NULL (java.lang.Object) markObject(clazz->classLoader, ctx); // may be NULL scanStaticFields(clazz, ctx); markInterfaces(clazz, ctx); }
/* Mark all objects referred to by a DataObject's instance fields. */ static void scanInstanceFields(const DataObject *obj, ClassObject *clazz, GcMarkContext *ctx) { //TODO: Optimize this by avoiding walking the superclass chain while (clazz != NULL) { InstField *f; int i; /* All of the fields that contain object references * are guaranteed to be at the beginning of the ifields list. */ f = clazz->ifields; for (i = 0; i < clazz->ifieldRefCount; i++) { /* Mark the array or object reference. * May be NULL. * * Note that, per the comment on struct InstField, * f->byteOffset is the offset from the beginning of * obj, not the offset into obj->instanceData. */ markObject(dvmGetFieldObject((Object*)obj, f->byteOffset), ctx); f++; } /* This will be NULL when we hit java.lang.Object */ clazz = clazz->super; } }
void GarbageCollector::mark() { // Mark from the root objects. onRootsDo([this](Oop root) { markObject(root); }); }
template <MWORD ImageNullTerms> HRESULT ObjectMemory::LoadPointers(ibinstream& imageFile, const ImageHeader* pHeader, size_t& cbRead) { ASSERT(pHeader->nGlobalPointers == NumPointers); ::ZeroMemory(m_pConstObjs, CONSTSPACESIZE); size_t cbPerm = 0; BYTE* pNextConst = reinterpret_cast<BYTE*>(m_pConstObjs); int i; for (i = 0; i < NumPermanent; i++) { VariantObject* pConstObj = reinterpret_cast<VariantObject*>(pNextConst); OTE* ote = m_pOT + i; MWORD bytesToRead; MWORD allocSize; if (ote->isNullTerminated()) { MWORD byteSize = ote->getSize(); allocSize = byteSize + NULLTERMSIZE; bytesToRead = byteSize + ImageNullTerms; } else { allocSize = bytesToRead = ote->getSize(); } if (bytesToRead > 0) { // Now load the rest of the object (size includes itself) if (!imageFile.read(&(pConstObj->m_fields), bytesToRead)) return ImageReadError(imageFile); } else { if (allocSize == 0) pConstObj = NULL; } cbPerm += bytesToRead; pNextConst += _ROUND2(allocSize, 4); markObject(ote); Oop* oldLocation = reinterpret_cast<Oop*>(ote->m_location); ote->m_location = pConstObj; ote->beSticky(); // Repair the object FixupObject(ote, oldLocation, pHeader); } #ifdef _DEBUG TRACESTREAM << i<< L" permanent objects loaded totalling " << cbPerm<< L" bytes" << std::endl; #endif memcpy(const_cast<VMPointers*>(&Pointers), &_Pointers, sizeof(Pointers)); cbRead += cbPerm; return S_OK; }
void GarbageCollector::markObject(Oop objectPointer) { // TODO: Use the schorr-waite algorithm. // mark pointer objects. if(!objectPointer.isPointer()) return; // Get the object header. auto header = objectPointer.header; if(header->gcColor) return; // Mark gray header->gcColor = Gray; // Mark recursively the children auto format = header->objectFormat; if(format == OF_FIXED_SIZE || format == OF_VARIABLE_SIZE_NO_IVARS || format == OF_VARIABLE_SIZE_IVARS) { auto slotCount = header->slotCount; auto headerSize = sizeof(ObjectHeader); if(slotCount == 255) slotCount = reinterpret_cast<uint64_t*> (header)[-1]; // Traverse the slots. auto slots = reinterpret_cast<Oop*> (objectPointer.pointer + headerSize); for(size_t i = 0; i < slotCount; ++i) markObject(slots[i]); } // Special handilng of compiled method literals if(format >= OF_COMPILED_METHOD) { auto compiledMethod = reinterpret_cast<CompiledMethod*> (objectPointer.pointer); auto literalCount = compiledMethod->getLiteralCount(); auto literals = compiledMethod->getFirstLiteralPointer(); for(size_t i = 0; i < literalCount; ++i) markObject(literals[i]); } // Mark as black before ending. header->gcColor = Black; }
/* Mark all objects referred to by a DataObject's instance fields. */ static void scanInstanceFields(const DataObject *obj, ClassObject *clazz, GcMarkContext *ctx) { if (clazz->refOffsets != CLASS_WALK_SUPER) { unsigned int refOffsets = clazz->refOffsets; while (refOffsets != 0) { const int rshift = CLZ(refOffsets); refOffsets &= ~(CLASS_HIGH_BIT >> rshift); markObject(dvmGetFieldObject((Object*)obj, CLASS_OFFSET_FROM_CLZ(rshift)), ctx); } } else {
/* Mark all objects referred to by the array's contents. */ static void scanObjectArray(const ArrayObject *array, GcMarkContext *ctx) { Object **contents; u4 length; u4 i; contents = (Object **)array->contents; length = array->length; for (i = 0; i < length; i++) { markObject(*contents, ctx); // may be NULL contents++; } }
/* * Scans instance fields. */ static void scanInstanceFields(const Object *obj, GcMarkContext *ctx) { assert(obj != NULL); assert(obj->clazz != NULL); assert(ctx != NULL); if (obj->clazz->refOffsets != CLASS_WALK_SUPER) { unsigned int refOffsets = obj->clazz->refOffsets; while (refOffsets != 0) { const int rshift = CLZ(refOffsets); refOffsets &= ~(CLASS_HIGH_BIT >> rshift); markObject(dvmGetFieldObject((Object*)obj, CLASS_OFFSET_FROM_CLZ(rshift)), ctx); } } else {
/* Mark all objects referred to by a ClassObject's static fields. */ static void scanStaticFields(const ClassObject *clazz, GcMarkContext *ctx) { StaticField *f; int i; //TODO: Optimize this with a bit vector or something f = clazz->sfields; for (i = 0; i < clazz->sfieldCount; i++) { char c = f->field.signature[0]; if (c == '[' || c == 'L') { /* It's an array or class reference. */ markObject((Object *)f->value.l, ctx); } f++; } }
template <MWORD ImageNullTerms> HRESULT ObjectMemory::LoadObjects(ibinstream & imageFile, const ImageHeader * pHeader, size_t & cbRead) { // Other free OTEs will be threaded in front of the first OTE off the end // of the currently committed table space. We set the free list pointer // to that OTE rather than NULL to distinguish attemps to access off the // end of the current table, which then allows us to dynamically grow it // on demand OTE* pEnd = m_pOT + pHeader->nTableSize; m_pFreePointerList = reinterpret_cast<OTE*>(pEnd); #ifdef _DEBUG unsigned numObjects = NumPermanent; // Allow for VM registry, etc! m_nFreeOTEs = m_nOTSize - pHeader->nTableSize; #endif size_t nDataSize = 0; for (OTE* ote = m_pOT + NumPermanent; ote < pEnd; ote++) { if (!ote->isFree()) { MWORD byteSize = ote->getSize(); MWORD* oldLocation = reinterpret_cast<MWORD*>(ote->m_location); Object* pBody; // Allocate space for the object, and copy into that space if (ote->heapSpace() == OTEFlags::VirtualSpace) { MWORD dwMaxAlloc; if (!imageFile.read(&dwMaxAlloc, sizeof(MWORD))) return ImageReadError(imageFile); cbRead += sizeof(MWORD); pBody = reinterpret_cast<Object*>(AllocateVirtualSpace(dwMaxAlloc, byteSize)); ote->m_location = pBody; } else { if (ote->isNullTerminated()) { ASSERT(!ote->isPointers()); pBody = AllocObj(ote, byteSize + NULLTERMSIZE); if (NULLTERMSIZE > ImageNullTerms) { // Ensure we have a full null-terminator *reinterpret_cast<NULLTERMTYPE*>(static_cast<VariantByteObject*>(pBody)->m_fields+byteSize) = 0; } byteSize += ImageNullTerms; } else { pBody = AllocObj(ote, byteSize); } } markObject(ote); if (!imageFile.read(pBody, byteSize)) return ImageReadError(imageFile); cbRead += byteSize; FixupObject(ote, oldLocation, pHeader); #ifdef _DEBUG numObjects++; #endif } else { // Thread onto the free list ote->m_location = (reinterpret_cast<POBJECT>(m_pFreePointerList)); m_pFreePointerList = ote; #ifdef _DEBUG m_nFreeOTEs++; #endif } } // Note that we don't terminate the free list with a null, because // it must point off into space in order to get a GPF when it // needs to be expanded (at which point we commit more pages) #ifdef _DEBUG ASSERT(numObjects + m_nFreeOTEs == m_nOTSize); ASSERT(m_nFreeOTEs = CountFreeOTEs()); TRACESTREAM << std::dec << numObjects<< L", " << m_nFreeOTEs<< L" free" << std::endl; #endif cbRead += nDataSize; return S_OK; }