public static tMD_MethodDef *GetMethodDefFromSpec(tMD_MethodSpec *pMethodSpec, tMD_TypeDef **ppCallingClassTypeArgs, tMD_TypeDef **ppCallingMethodTypeArgs) { tMD_MethodDef *pCoreMethod; tMD_MethodDef *pMethod; /*SIG*/ byte * sig; uint argCount, i; tMD_TypeDef ** ppTypeArgs; Mem.heapcheck(); pCoreMethod = MetaData.GetMethodDefFromDefRefOrSpec(pMethodSpec->pMetaData, pMethodSpec->method, null, null);//ppCallingClassTypeArgs, ppCallingMethodTypeArgs); //ppClassTypeArgs = pCoreMethod->pParentType->ppClassTypeArgs; sig = MetaData.GetBlob(pMethodSpec->instantiation, null); MetaData.DecodeSigEntry(&sig); // always 0x0a argCount = MetaData.DecodeSigEntry(&sig); ppTypeArgs = (tMD_TypeDef **)Mem.malloc((SIZE_T)(argCount * sizeof(tMD_TypeDef *))); for (i = 0; i < argCount; i++) { tMD_TypeDef *pArgType; pArgType = Type.GetTypeFromSig(pMethodSpec->pMetaData, &sig, ppCallingClassTypeArgs, ppCallingMethodTypeArgs, null); ppTypeArgs[i] = pArgType; } pMethod = Generics.GetMethodDefFromCoreMethod(pCoreMethod, pCoreMethod->pParentType, argCount, ppTypeArgs); Mem.free(ppTypeArgs); Mem.heapcheck(); return(pMethod); }
public static tMD_TypeDef *GetGenericTypeFromSig(tMetaData *pMetaData, /*SIG*/ byte **pSig, tMD_TypeDef **ppCallingClassTypeArgs, tMD_TypeDef **ppCallingMethodTypeArgs) { tMD_TypeDef * pCoreType; tMD_TypeDef * pRet; uint numTypeArgs, i; tMD_TypeDef **ppTypeArgs; Mem.heapcheck(); pCoreType = Type.GetTypeFromSig(pMetaData, pSig, ppCallingClassTypeArgs, ppCallingMethodTypeArgs, null); MetaData.Fill_TypeDef(pCoreType, ppCallingClassTypeArgs, ppCallingMethodTypeArgs, Type.TYPE_FILL_PARENTS); //null, null); numTypeArgs = MetaData.DecodeSigEntry(pSig); ppTypeArgs = (tMD_TypeDef **)Mem.malloc((SIZE_T)(numTypeArgs * sizeof(tMD_TypeDef *))); for (i = 0; i < numTypeArgs; i++) { ppTypeArgs[i] = Type.GetTypeFromSig(pMetaData, pSig, ppCallingClassTypeArgs, ppCallingMethodTypeArgs); if (ppTypeArgs[i] != null) { MetaData.Fill_TypeDef(ppTypeArgs[i], null, null, Type.TYPE_FILL_PARENTS); } } pRet = GetGenericTypeFromCoreType(pCoreType, numTypeArgs, ppTypeArgs); Mem.free(ppTypeArgs); Mem.heapcheck(); return(pRet); }
public static void Delete(tThread *pThread, ref tMethodState *pMethodState) { tMethodState *pThis = pMethodState; #if DIAG_METHOD_CALLS pThis->pMethod->totalTime += microTime() - pThis->startTime; #endif // If this MethodState is a Finalizer, then let the heap know this Finalizer has been run if (pThis->finalizerThis != null) { Heap.UnmarkFinalizer(pThis->finalizerThis); } if (pThis->pDelegateParams != null) { Mem.free(pThis->pDelegateParams); } // Note that the way the stack Mem.free funtion works means that only the 1st allocated chunk // needs to be Mem.free'd, as this function just sets the current allocation offset to the address given. Thread.StackFree(pThread, pThis); pMethodState = null; }
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 void Delete(tThread *pThis) { tThreadStack *pStack = pThis->pThreadStack; while (pStack != null) { tThreadStack *pNextStack = pStack->pNext; Mem.free(pStack); pStack = pNextStack; } Heap.MakeDeletable((/*HEAP_PTR*/ byte *)pThis); }
public static uint Update(uint maxInstr, int *pReturnCode) { tThread *pThread; tThread *pPrevThread; uint status; pThread = pAllThreads; // Set the initial thread to the RUNNING state. pThread->state = THREADSTATE_RUNNING; // Set the initial CurrentThread pCurrentThread = pThread; for (;;) { uint minSleepTime = 0xffffffff; int threadExitValue; status = JIT_Execute.Execute(pThread, maxInstr); switch (status) { case Thread.THREAD_STATUS_EXIT: threadExitValue = pThread->threadExitValue; Sys.log_f(1, "Thread ID#%d exited. Return value: %d\n", (int)pThread->threadID, (int)threadExitValue); // Remove the current thread from the running threads list. // Note that this list may have changed since before the call to JitOps.JIT_Execute(). { if (pAllThreads == pThread) { pAllThreads = pAllThreads->pNextThread; } else { tThread *pThread1 = pAllThreads; while (pThread1->pNextThread != pThread) { pThread1 = pThread1->pNextThread; } pThread1->pNextThread = pThread1->pNextThread->pNextThread; } } // Delete the current thread Thread.Delete(pThread); // If there are no more threads left running, then exit application (by returning) // Threads that are unstarted or background do not stop the exit // [Steve edit] Threads that are suspended also do not stop the exit. This is because you'd just // wait forever for them if they did. Note that 'exit' doesn't mean tearing down the process // like in a regular .NET runtime case. The application state is still there and we can make // further calls into it to create new threads. { tThread *pThread2 = pAllThreads; uint canExit = 1; while (pThread2 != null) { if ( ((pThread2->state & THREADSTATE_BACKGROUND) == 0) && ((pThread2->state & (~THREADSTATE_BACKGROUND)) != THREADSTATE_UNSTARTED) && ((pThread2->state & (~THREADSTATE_BACKGROUND)) != THREADSTATE_SUSPENDED)) { canExit = 0; break; } pThread2 = pThread2->pNextThread; } if (canExit != 0) { if (pReturnCode != null) { *pReturnCode = threadExitValue; } return(THREADSTATE_STOPPED); } } pThread = pAllThreads; // This is not really correct, but it'll work for the time being break; case THREAD_STATUS_RUNNING: case THREAD_STATUS_LOCK_EXIT: // Nothing to do break; case THREAD_STATUS_ASYNC: pThread->pAsync->startTime = Sys.msTime(); break; } // Move on to the next thread. // Find the next thread that isn't sleeping or blocked on IO pPrevThread = pThread; for (;;) { pThread = pThread->pNextThread; if (pThread == null) { // That was the thread -- return! return(THREADSTATE_RUNNING); } // Set the CurrentThread correctly pCurrentThread = pThread; if ((pThread->state & (~THREADSTATE_BACKGROUND)) != 0) { // Thread is not running continue; } if (pThread->pAsync != null) { // Discover if whatever is being waited for is finished tAsyncCall *pAsync = pThread->pAsync; if (pAsync->sleepTime >= 0) { // This is a sleep ulong nowTime = Sys.msTime(); int msSleepRemaining = pAsync->sleepTime - (int)(nowTime - pAsync->startTime); if (msSleepRemaining <= 0) { // Sleep is finished break; } // Sleep is not finished, so continue to next thread if ((uint)msSleepRemaining < minSleepTime) { minSleepTime = (uint)msSleepRemaining; } } else { // This is blocking IO, or a lock tMethodState *pMethodState = pThread->pCurrentMethodState; byte * pThis; uint thisOfs; uint unblocked; if (MetaData.METHOD_ISSTATIC(pMethodState->pMethod)) { pThis = null; thisOfs = 0; } else { pThis = *(byte **)pMethodState->pParamsLocals; thisOfs = 4; } unblocked = ((fnInternalCallCheck)H.ToObj(pAsync->checkFn))(null, pThis, pMethodState->pParamsLocals + thisOfs, pMethodState->pEvalStack, pAsync); if (unblocked != 0) { // The IO has unblocked, and the return value is ready. // So delete the async object. // TODO: The async->state object needs to be deleted somehow (maybe) Mem.free(pAsync); // And remove it from the thread pThread->pAsync = null; break; } minSleepTime = 5; } } else { // Thread is ready to run break; } if (pThread == pPrevThread) { // When it gets here, it means that all threads are currently blocked. //printf("All blocked; sleep(%d)\n", minSleepTime); Sys.SleepMS(minSleepTime); } } } }
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 }