public static void Clear() { pHeapTreeRoot = nil = null; trackHeapSize = 0; heapSizeMax = 0; numNodes = 0; numCollections = 0; }
static tSync *EnsureSync(tHeapEntry *pHeapEntry) { if (pHeapEntry->pSync == null) { tSync *pSync = ((tSync *)Mem.malloc((SIZE_T)sizeof(tSync))); Mem.memset(pSync, 0, (SIZE_T)sizeof(tSync)); pHeapEntry->pSync = pSync; } return(pHeapEntry->pSync); }
static void DeleteSync(tHeapEntry *pHeapEntry) { if (pHeapEntry->pSync != null) { if (pHeapEntry->pSync->count == 0 && pHeapEntry->pSync->weakRef == null) { Mem.free(pHeapEntry->pSync); pHeapEntry->pSync = null; } } }
static tHeapEntry *TreeSkew(tHeapEntry *pRoot) { if (((tHeapEntry *)pRoot->pLink[0])->level == pRoot->level && pRoot->level != 0) { tHeapEntry *pSave = (tHeapEntry *)pRoot->pLink[0]; pRoot->pLink[0] = pSave->pLink[1]; pSave->pLink[1] = (PTR)pRoot; pRoot = pSave; } return(pRoot); }
// Returns the previous first weak-ref in target targetted by weakref public static /*HEAP_PTR*/ byte *SetWeakRefTarget(/*HEAP_PTR*/ byte *target, /*HEAP_PTR*/ byte *weakRef) { tHeapEntry * pTarget = GET_HEAPENTRY(target); tSync * pSync; /*HEAP_PTR*/ byte *prevWeakRef; pSync = EnsureSync(pTarget); prevWeakRef = pSync->weakRef; pSync->weakRef = weakRef; return(prevWeakRef); }
// Get the size of a heap entry, NOT including the header // This works by returning the size of the type, unless the type is an array or a string, // which are the only two type that can have variable sizes static uint GetSize(tHeapEntry *pHeapEntry) { tMD_TypeDef *pType = pHeapEntry->pTypeDef; if (MetaData.TYPE_ISARRAY(pType)) { // If it's an array, return the array length * array element size return(System_Array.GetNumBytes(null /* This is ok */, (/*HEAP_PTR*/ byte *)(pHeapEntry + 1), pType->pArrayElementType)); } // If it's not array, just return the instance memory size return(pType->instanceMemSize); }
public static void Init() { // Initialise vars trackHeapSize = 0; heapSizeMax = MIN_HEAP_SIZE; // Create nil node - for leaf termination nil = ((tHeapEntry *)Mem.mallocForever((SIZE_T)sizeof(tHeapEntry))); Mem.memset(nil, 0, (SIZE_T)sizeof(tHeapEntry)); nil->pLink[0] = nil->pLink[1] = (PTR)nil; // Set the heap tree as empty pHeapTreeRoot = nil; }
public static /*HEAP_PTR*/ byte *AllocType(tMD_TypeDef *pTypeDef) { //printf("Heap.AllocType('%s')\n", pTypeDef->name); byte *pInst = Alloc(pTypeDef, pTypeDef->instanceMemSize); if (pTypeDef->hasMonoBase != 0) { tHeapEntry *pHeapEntry = (tHeapEntry *)((byte *)pInst - sizeof(tHeapEntry)); pHeapEntry->monoHandle = 1; } return(pInst); }
static tHeapEntry *TreeInsert(tHeapEntry *pRoot, tHeapEntry *pEntry) { if (pRoot == nil) { pRoot = pEntry; pRoot->level = 1; pRoot->pLink[0] = pRoot->pLink[1] = (PTR)nil; pRoot->marked = 0; } else { tHeapEntry * pNode = pHeapTreeRoot; tHeapEntry **pUp = stackalloc tHeapEntry *[MAX_TREE_DEPTH]; int top = 0, dir; // Find leaf position to insert into tree. This first step is unbalanced for (;;) { pUp[top++] = pNode; dir = ((PTR)pNode < (PTR)pEntry) ? 1 : 0; // 0 for left, 1 for right if (pNode->pLink[dir] == (PTR)nil) { break; } pNode = (tHeapEntry *)pNode->pLink[dir]; } // Create new node pNode->pLink[dir] = (PTR)pEntry; pEntry->level = 1; pEntry->pLink[0] = pEntry->pLink[1] = (PTR)nil; pEntry->marked = 0; // Balance the tree while (--top >= 0) { if (top != 0) { dir = (pUp[top - 1]->pLink[1] == (PTR)pUp[top]) ? 1 : 0; } pUp[top] = TreeSkew(pUp[top]); pUp[top] = TreeSplit(pUp[top]); if (top != 0) { pUp[top - 1]->pLink[dir] = (PTR)pUp[top]; } else { pRoot = pUp[0]; } } } return(pRoot); }
public static /*HEAP_PTR*/ byte *Clone(/*HEAP_PTR*/ byte *obj) { tHeapEntry * pObj = GET_HEAPENTRY(obj); /*HEAP_PTR*/ byte *clone; uint size = GetSize(pObj); byte *pMem; clone = Alloc(pObj->pTypeDef, size); pMem = (byte *)&pObj->pSync + sizeof(PTR); Mem.memcpy((void *)clone, pMem, size); return(clone); }
public static void Clear() { // This frees all references in the DNA heap to all mono objects if (pHeapTreeRoot != null) { FreeAllGCHandles(); } pHeapTreeRoot = nil = null; trackHeapSize = 0; heapSizeMax = 0; numNodes = 0; numCollections = 0; }
// Get the size of a heap entry, NOT including the header // This works by returning the size of the type, unless the type is an array or a string, // which are the only two type that can have variable sizes static uint GetSize(tHeapEntry *pHeapEntry) { tMD_TypeDef *pType = pHeapEntry->pTypeDef; if (pType == Type.types[Type.TYPE_SYSTEM_STRING]) { // If it's a string, return the string length in bytes return(System_String.GetNumBytes((/*HEAP_PTR*/ byte *)(pHeapEntry + 1))); } if (MetaData.TYPE_ISARRAY(pType)) { // If it's an array, return the array length * array element size return(System_Array.GetNumBytes(null /* This is ok */, (/*HEAP_PTR*/ byte *)(pHeapEntry + 1), pType->pArrayElementType)); } // If it's not string or array, just return the instance memory size return(pType->instanceMemSize); }
public static tMD_TypeDef *GetType(/*HEAP_PTR*/ byte *heapObj) { #if DEBUG_HEAP if (heapObj == null) { Sys.Crash("Null reference to heap obj"); } #endif tHeapEntry *pHeapEntry = GET_HEAPENTRY(heapObj); #if DEBUG_HEAP if (pHeapEntry->signature != VALID_HEAP_OBJ_SIG) { Sys.Crash("Invalid heap object in GetMonoObject()"); } #endif return(pHeapEntry->pTypeDef); }
public static /*HEAP_PTR*/ byte *Alloc(tMD_TypeDef *pTypeDef, uint size) { tHeapEntry *pHeapEntry; uint totalSize; byte * pMem; if (pTypeDef == null) { Sys.Crash("Invalid heap type!"); } totalSize = (uint)sizeof(tHeapEntry) + size; // Trigger garbage collection if required. if (trackHeapSize >= heapSizeMax) { GarbageCollect(); heapSizeMax = (trackHeapSize + totalSize) << 1; if (heapSizeMax < trackHeapSize + totalSize + MIN_HEAP_SIZE) { // Make sure there is always MIN_HEAP_SIZE available to allocate on the heap heapSizeMax = trackHeapSize + totalSize + MIN_HEAP_SIZE; } if (heapSizeMax > trackHeapSize + totalSize + MAX_HEAP_EXCESS) { // Make sure there is never more that MAX_HEAP_EXCESS space on the heap heapSizeMax = trackHeapSize + totalSize + MAX_HEAP_EXCESS; } } pHeapEntry = (tHeapEntry *)Mem.malloc(totalSize); pHeapEntry->pTypeDef = pTypeDef; pHeapEntry->signature = VALID_HEAP_OBJ_SIG; pHeapEntry->pSync = null; pHeapEntry->needToFinalize = (byte)((pTypeDef->pFinalizer != null) ? 1 : 0); pMem = (byte *)pHeapEntry + sizeof(tHeapEntry); Mem.memset(pMem, 0, size); trackHeapSize += totalSize; pHeapTreeRoot = TreeInsert(pHeapTreeRoot, pHeapEntry); numNodes++; return(pMem); }
// Returns 1 if all is OK // Returns 0 if the wrong thread is releasing the sync, or if no thread hold the sync public static uint SyncExit(/*HEAP_PTR*/ byte *obj) { tHeapEntry *pHeapEntry = GET_HEAPENTRY(obj); tThread * pThread = Thread.GetCurrent(); if (pHeapEntry->pSync == null) { return(0); } if (pHeapEntry->pSync->pThread != pThread) { return(0); } if (--pHeapEntry->pSync->count == 0) { DeleteSync(pHeapEntry); } return(1); }
// Return 1 if lock succesfully got // Return 0 if couldn't get the lock this time public static uint SyncTryEnter(/*HEAP_PTR*/ byte *obj) { tHeapEntry *pHeapEntry = GET_HEAPENTRY(obj); tThread * pThread = Thread.GetCurrent(); tSync * pSync; pSync = EnsureSync(pHeapEntry); if (pSync->pThread == null) { pSync->pThread = pThread; pSync->count = 1; return(1); } if (pSync->pThread == pThread) { pSync->count++; return(1); } return(0); }
public static object GetMonoObject(/*HEAP_PTR*/ byte *heapObj) { tHeapEntry *pHeapEntry = GET_HEAPENTRY(heapObj); #if DEBUG_HEAP if (pHeapEntry->signature != VALID_HEAP_OBJ_SIG) { Sys.Crash("Invalid heap object in GetMonoObject()"); } #endif if (pHeapEntry->monoHandle != 0) { void *p = *(void **)heapObj; if (p == null) { return(null); } return(H.ToObj(p)); } return(null); }
public static object GetMonoObject(/*HEAP_PTR*/ byte *heapObj) { tHeapEntry *pHeapEntry = GET_HEAPENTRY(heapObj); #if DEBUG_HEAP if (pHeapEntry->signature != VALID_HEAP_OBJ_SIG) { Sys.Crash("Invalid heap object in GetMonoObject()"); } #endif if (pHeapEntry->monoGCHandle != 0) { void *p = *(void **)heapObj; if (p == null) { return(null); } GCHandle handle = (GCHandle)(System.IntPtr)p; return(handle.Target); } return(null); }
public static void RemovedWeakRefTarget(/*HEAP_PTR*/ byte *target) { tHeapEntry *pTarget = GET_HEAPENTRY(target); DeleteSync(pTarget); }
public static /*HEAP_PTR*/ byte **GetWeakRefAddress(/*HEAP_PTR*/ byte *target) { tHeapEntry *pTarget = GET_HEAPENTRY(target); return(&pTarget->pSync->weakRef); }
static void RemoveWeakRefTarget(tHeapEntry *pTarget, uint removeLongRefs) { System_WeakReference.TargetGone(&pTarget->pSync->weakRef, removeLongRefs); }
static tHeapEntry *TreeRemove(tHeapEntry *pRoot, tHeapEntry *pDelete) { if (pRoot != nil) { if (pRoot == pDelete) { if (pRoot->pLink[0] != (PTR)nil && pRoot->pLink[1] != (PTR)nil) { tHeapEntry * pL0; byte l; tHeapEntry * pHeir = (tHeapEntry *)pRoot->pLink[0]; tHeapEntry **ppHeirLink = (tHeapEntry **)&pHeir->pLink[0]; while (pHeir->pLink[1] != (PTR)nil) { ppHeirLink = (tHeapEntry **)&pHeir->pLink[1]; pHeir = (tHeapEntry *)pHeir->pLink[1]; } // Swap the two nodes pL0 = (tHeapEntry *)pHeir->pLink[0]; l = pHeir->level; // Bring heir to replace root pHeir->pLink[0] = pRoot->pLink[0]; pHeir->pLink[1] = pRoot->pLink[1]; pHeir->level = pRoot->level; // Send root to replace heir *ppHeirLink = pRoot; pRoot->pLink[0] = (PTR)pL0; pRoot->pLink[1] = (PTR)nil; pRoot->level = l; // Set correct return value pL0 = pRoot; pRoot = pHeir; // Delete the node that's been sent down pRoot->pLink[0] = (PTR)TreeRemove((tHeapEntry *)pRoot->pLink[0], pL0); } else { pRoot = (tHeapEntry *)pRoot->pLink[pRoot->pLink[0] == (PTR)nil ? 1 : 0]; } } else { int dir = (PTR)pRoot < (PTR)pDelete ? 1 : 0; pRoot->pLink[dir] = (PTR)TreeRemove((tHeapEntry *)pRoot->pLink[dir], pDelete); } } if (((tHeapEntry *)pRoot->pLink[0])->level < pRoot->level - 1 || ((tHeapEntry *)pRoot->pLink[1])->level < pRoot->level - 1) { if (((tHeapEntry *)pRoot->pLink[1])->level > --pRoot->level) { ((tHeapEntry *)pRoot->pLink[1])->level = pRoot->level; } pRoot = TreeSkew(pRoot); pRoot->pLink[1] = (PTR)TreeSkew((tHeapEntry *)pRoot->pLink[1]); ((tHeapEntry *)pRoot->pLink[1])->pLink[1] = (PTR)TreeSkew((tHeapEntry *)((tHeapEntry *)pRoot->pLink[1])->pLink[1]); pRoot = TreeSplit(pRoot); pRoot->pLink[1] = (PTR)TreeSplit((tHeapEntry *)pRoot->pLink[1]); } return(pRoot); }
public static void GarbageCollect() { #if NO tHeapRoots heapRoots; tHeapEntry * pNode; tHeapEntry **pUp = stackalloc tHeapEntry *[MAX_TREE_DEPTH * 2]; int top; tHeapEntry * pToDelete = null; SIZE_T orgHeapSize = trackHeapSize; uint orgNumNodes = numNodes; #if DIAG_GC ulong startTime; #endif Mem.heapcheck(); numCollections++; #if DIAG_GC startTime = microTime(); #endif heapRoots.capacity = 64; heapRoots.num = 0; heapRoots.pHeapEntries = (tHeapRootEntry *)Mem.malloc(heapRoots.capacity * (SIZE_T)sizeof(tHeapRootEntry)); Thread.GetHeapRoots(&heapRoots); CLIFile.GetHeapRoots(&heapRoots); // Mark phase while (heapRoots.num > 0) { tHeapRootEntry *pRootsEntry; uint i; uint moreRootsAdded = 0; uint rootsEntryNumPointers; void ** pRootsEntryMem; // Get a piece of memory off the list of heap memory roots. pRootsEntry = &heapRoots.pHeapEntries[heapRoots.num - 1]; rootsEntryNumPointers = pRootsEntry->numPointers; pRootsEntryMem = pRootsEntry->pMem; // Mark this entry as done pRootsEntry->numPointers = 0; pRootsEntry->pMem = null; // Iterate through all pointers in it for (i = 0; i < rootsEntryNumPointers; i++) { void *pMemRef = pRootsEntryMem[i]; // Quick escape for known non-memory if (pMemRef == null) { continue; } // Find this piece of heap memory in the tracking tree. // Note that the 2nd memory address comparison MUST be >, not >= as might be expected, // to allow for a zero-sized memory to be detected (and not garbage collected) properly. // E.g. The object class has zero memory. pNode = pHeapTreeRoot; while (pNode != nil) { if (pMemRef < (void *)pNode) { pNode = (tHeapEntry *)pNode->pLink[0]; } else if ((byte *)pMemRef > ((byte *)pNode) + GetSize(pNode) + sizeof(tHeapEntry)) { pNode = (tHeapEntry *)pNode->pLink[1]; } else { // Found memory. See if it's already been marked. // If it's already marked, then don't do anything. // It it's not marked, then add all of its memory to the roots, and mark it. if (pNode->marked == 0) { tMD_TypeDef *pType = pNode->pTypeDef; // Not yet marked, so mark it, and add it to heap roots. pNode->marked = 1; // Don't look at the contents of strings, arrays of primitive Type.types, or WeakReferences if (pType->stackType == EvalStack.EVALSTACK_O || pType->stackType == EvalStack.EVALSTACK_VALUETYPE || pType->stackType == EvalStack.EVALSTACK_PTR) { if (pType != Type.types[Type.TYPE_SYSTEM_STRING] && (!MetaData.TYPE_ISARRAY(pType) || pType->pArrayElementType->stackType == EvalStack.EVALSTACK_O || pType->pArrayElementType->stackType == EvalStack.EVALSTACK_VALUETYPE || pType->pArrayElementType->stackType == EvalStack.EVALSTACK_PTR)) { if (pType != Type.types[Type.TYPE_SYSTEM_WEAKREFERENCE]) { Heap.SetRoots(&heapRoots, ((byte *)&pNode->pSync + sizeof(PTR)), GetSize(pNode)); moreRootsAdded = 1; } } } } break; } } } if (moreRootsAdded == 0) { heapRoots.num--; } } Mem.free(heapRoots.pHeapEntries); // Sweep phase // Traverse nodes pUp[0] = pHeapTreeRoot; top = 1; while (top != 0) { // Get this node pNode = pUp[--top]; // Act on this node if (pNode->marked != 0) { if (pNode->marked != 0xff) { // Still in use (but not marked undeletable), so unmark pNode->marked = 0; } } else { // Not in use any more, so put in deletion queue if it does not need Finalizing // If it does need Finalizing, then don't garbage collect, and put in Finalization queue. if (pNode->needToFinalize != 0) { if (pNode->needToFinalize == 1) { Finalizer.AddFinalizer((/*HEAP_PTR*/ byte *)pNode + sizeof(tHeapEntry)); // Mark it has having been placed in the finalization queue. // When it has been finalized, then this will be set to 0 pNode->needToFinalize = 2; // If this object is being targetted by weak-ref(s), handle it if (pNode->pSync != null) { RemoveWeakRefTarget(pNode, 0); Mem.free(pNode->pSync); } } } else { // If this object is being targetted by weak-ref(s), handle it if (pNode->pSync != null) { RemoveWeakRefTarget(pNode, 1); Mem.free(pNode->pSync); } // Use pSync to point to next entry in this linked-list. pNode->pSync = (tSync *)pToDelete; pToDelete = pNode; } } // Get next node(s) if (pNode->pLink[1] != (PTR)nil) { pUp[top++] = (tHeapEntry *)pNode->pLink[1]; } if (pNode->pLink[0] != (PTR)nil) { pUp[top++] = (tHeapEntry *)pNode->pLink[0]; } } // Delete all unused memory nodes. while (pToDelete != null) { tHeapEntry *pThis = pToDelete; pToDelete = (tHeapEntry *)(pToDelete->pSync); pHeapTreeRoot = TreeRemove(pHeapTreeRoot, pThis); if (pThis->monoHandle == 1) { void *hptr = *(void **)((byte *)pThis + sizeof(tHeapEntry)); if (hptr != null) { H.Free(hptr); } } numNodes--; trackHeapSize -= GetSize(pThis) + (uint)sizeof(tHeapEntry); Mem.free(pThis); } Mem.heapcheck(); #if DIAG_GC gcTotalTime += microTime() - startTime; #endif Sys.log_f(1, "--- GARBAGE --- [Size: %d -> %d] [Nodes: %d -> %d]\n", orgHeapSize, trackHeapSize, orgNumNodes, numNodes); #if DIAG_GC Sys.log_f(1, "GC time = %d ms\n", gcTotalTime / 1000); #endif #endif }
public static void MakeDeletable(/*HEAP_PTR*/ byte *heapObj) { tHeapEntry *pHeapEntry = GET_HEAPENTRY(heapObj); pHeapEntry->marked = 0; }