private static void AddObjectToCleanup(GCHeader *objHeaderPtr, void *objPtr) { EnterCritical("AddObjectToCleanup"); try { ObjectToCleanup *newObjToCleanupPtr = (ObjectToCleanup *)Heap.AllocZeroed((uint)sizeof(ObjectToCleanup), "GC : AddObjectToCleanup"); newObjToCleanupPtr->objHeaderPtr = objHeaderPtr; newObjToCleanupPtr->objPtr = objPtr; if (CleanupList != null) { newObjToCleanupPtr->prevPtr = CleanupList; CleanupList->nextPtr = newObjToCleanupPtr; } else { newObjToCleanupPtr->prevPtr = null; newObjToCleanupPtr->nextPtr = null; } CleanupList = newObjToCleanupPtr; } finally { ExitCritical(); } }
public static unsafe bool CheckSignature(GCHeader* headerPtr) { bool OK = headerPtr->Sig1 == 0x5C0EADE2U; OK = OK && headerPtr->Sig2 == 0x5C0EADE2U; OK = OK && headerPtr->Checksum == 0xB81D5BC4U; return OK; }
public static void *NewObj(Testing2.Type theType) { if (!Enabled) { BasicConsole.SetTextColour(BasicConsole.warning_colour); BasicConsole.WriteLine("Warning! GC returning null pointer because GC not enabled."); BasicConsole.DelayOutput(10); BasicConsole.SetTextColour(BasicConsole.default_colour); return(null); } //try //{ InsideGC = true; //Alloc space for GC header that prefixes object data //Alloc space for new object uint totalSize = theType.Size; totalSize += (uint)sizeof(GCHeader); GCHeader *newObjPtr = (GCHeader *)Heap.AllocZeroed(totalSize, "GC : NewObject"); if ((UInt32)newObjPtr == 0) { InsideGC = false; BasicConsole.SetTextColour(BasicConsole.error_colour); BasicConsole.WriteLine("Error! GC can't create a new object because the heap returned a null pointer."); BasicConsole.DelayOutput(10); BasicConsole.SetTextColour(BasicConsole.default_colour); return(null); } NumObjs++; //Initialise the GCHeader SetSignature(newObjPtr); newObjPtr->RefCount = 1; //Initialise the object _Type field Testing2.ObjectWithType newObj = (Testing2.ObjectWithType)Utilities.ObjectUtilities.GetObject(newObjPtr + 1); newObj._Type = theType; //Move past GCHeader byte *newObjBytePtr = (byte *)(newObjPtr + 1); InsideGC = false; return(newObjBytePtr); //} //finally //{ //} }
public static void Cleanup() { if (!Enabled /*|| InsideGC*/) { return; } //try { InsideGC = true; #if GC_TRACE int startNumObjs = NumObjs; int startNumStrings = NumStrings; #endif ObjectToCleanup *currObjToCleanupPtr = CleanupList; ObjectToCleanup *prevObjToCleanupPtr = null; while (currObjToCleanupPtr != null) { GCHeader *objHeaderPtr = currObjToCleanupPtr->objHeaderPtr; void * objPtr = currObjToCleanupPtr->objPtr; if (objHeaderPtr->RefCount <= 0) { Testing2.Object obj = (Testing2.Object)Utilities.ObjectUtilities.GetObject(objPtr); if (obj is Testing2.String) { NumStrings--; } Heap.Free(objHeaderPtr); NumObjs--; } prevObjToCleanupPtr = currObjToCleanupPtr; currObjToCleanupPtr = currObjToCleanupPtr->prevPtr; RemoveObjectToCleanup(prevObjToCleanupPtr); } InsideGC = false; #if GC_TRACE PrintCleanupData(startNumObjs, startNumStrings); #endif } //finally { } }
private static void AddObjectToCleanup(GCHeader *objHeaderPtr, void *objPtr) { //try { ObjectToCleanup *newObjToCleanupPtr = (ObjectToCleanup *)Heap.Alloc((uint)sizeof(ObjectToCleanup), "GC : AddObjectToCleanup"); newObjToCleanupPtr->objHeaderPtr = objHeaderPtr; newObjToCleanupPtr->objPtr = objPtr; newObjToCleanupPtr->prevPtr = CleanupList; CleanupList->nextPtr = newObjToCleanupPtr; CleanupList = newObjToCleanupPtr; } //finally { } }
private static void RemoveObjectToCleanup(GCHeader *objHeaderPtr) { //try { ObjectToCleanup *currObjToCleanupPtr = CleanupList; while (currObjToCleanupPtr != null) { if (currObjToCleanupPtr->objHeaderPtr == objHeaderPtr) { RemoveObjectToCleanup(currObjToCleanupPtr); return; } currObjToCleanupPtr = currObjToCleanupPtr->prevPtr; } } //finally { } }
private static void RemoveObjectToCleanup(GCHeader *objHeaderPtr) { EnterCritical("RemoveObjectToCleanup"); try { ObjectToCleanup *currObjToCleanupPtr = CleanupList; while (currObjToCleanupPtr != null) { if (currObjToCleanupPtr->objHeaderPtr == objHeaderPtr) { RemoveObjectToCleanup(currObjToCleanupPtr); return; } currObjToCleanupPtr = currObjToCleanupPtr->prevPtr; } } finally { ExitCritical(); } }
public static void _IncrementRefCount(byte* objPtr) { if ((uint)objPtr < (uint)sizeof(GCHeader)) { BasicConsole.SetTextColour(BasicConsole.error_colour); BasicConsole.WriteLine("Error! GC can't increment ref count of an object in low memory."); uint* basePtr = (uint*)ExceptionMethods.BasePointer; // Go up the linked-list of stack frames to (hopefully) the outermost caller basePtr = (uint*)*(basePtr); // Frame of IncrementRefCount(x) uint retAddr = *(basePtr + 1); // Caller of IncrementRefCount(x) basePtr = (uint*)*(basePtr); // Frame of caller of IncrementRefCount(x) uint ret2Addr = *(basePtr + 1); // Caller of caller of IncrementRefCount(x) uint objAddr = (uint)objPtr; String msgStr = "Caller: 0x , Object: 0x , PCaller: 0x "; // Object: 37 // Caller: 17 // PCaller: 58 ExceptionMethods.FillString(retAddr, 17, msgStr); ExceptionMethods.FillString(objAddr, 37, msgStr); ExceptionMethods.FillString(ret2Addr, 58, msgStr); BasicConsole.WriteLine(msgStr); BasicConsole.DelayOutput(5); BasicConsole.SetTextColour(BasicConsole.default_colour); } objPtr -= sizeof(GCHeader); GCHeader* gcHeaderPtr = (GCHeader*)objPtr; if (CheckSignature(gcHeaderPtr)) { gcHeaderPtr->RefCount++; if (gcHeaderPtr->RefCount > 0) { RemoveObjectToCleanup(gcHeaderPtr); } } }
public static void _IncrementRefCount(byte *objPtr) { if ((uint)objPtr < (uint)sizeof(GCHeader)) { BasicConsole.SetTextColour(BasicConsole.error_colour); BasicConsole.WriteLine("Error! GC can't increment ref count of an object in low memory."); BasicConsole.DelayOutput(5); BasicConsole.SetTextColour(BasicConsole.default_colour); } objPtr -= sizeof(GCHeader); GCHeader *gcHeaderPtr = (GCHeader *)objPtr; if (CheckSignature(gcHeaderPtr)) { gcHeaderPtr->RefCount++; if (gcHeaderPtr->RefCount > 0) { RemoveObjectToCleanup(gcHeaderPtr); } } }
public static void SetSignature(GCHeader *headerPtr) { headerPtr->Sig1 = 0x5C0EADE2U; headerPtr->Sig2 = 0x5C0EADE2U; headerPtr->Checksum = 0xB81D5BC4U; }
public static void _DecrementRefCount(byte *objPtr) { if ((uint)objPtr < (uint)sizeof(GCHeader)) { BasicConsole.SetTextColour(BasicConsole.error_colour); BasicConsole.WriteLine("Error! GC can't decrement ref count of an object in low memory."); BasicConsole.DelayOutput(5); BasicConsole.SetTextColour(BasicConsole.default_colour); } GCHeader *gcHeaderPtr = (GCHeader *)(objPtr - sizeof(GCHeader)); if (CheckSignature(gcHeaderPtr)) { gcHeaderPtr->RefCount--; //If the ref count goes below 0 then there was a circular reference somewhere. // In actuality we don't care we can just only do cleanup when the ref count is // exactly 0. if (gcHeaderPtr->RefCount == 0) { #if GC_TRACE BasicConsole.WriteLine("Cleaned up object."); #endif Testing2.Object obj = (Testing2.Object)Utilities.ObjectUtilities.GetObject(objPtr); if (obj is Testing2.Array) { //Decrement ref count of elements Testing2.Array arr = (Testing2.Array)obj; if (!arr.elemType.IsValueType) { Testing2.Object[] objArr = (Testing2.Object[])Utilities.ObjectUtilities.GetObject(objPtr); for (int i = 0; i < arr.length; i++) { DecrementRefCount(objArr[i], true); } } } //Cleanup fields FieldInfo *FieldInfoPtr = obj._Type.FieldTablePtr; //Loop through all fields. The if-block at the end handles moving to parent // fields. while (FieldInfoPtr != null) { if (FieldInfoPtr->Size > 0) { Testing2.Type fieldType = (Testing2.Type)Utilities.ObjectUtilities.GetObject(FieldInfoPtr->FieldType); if (!fieldType.IsValueType && !fieldType.IsPointer) { byte * fieldPtr = objPtr + FieldInfoPtr->Offset; Testing2.Object theFieldObj = (Testing2.Object)Utilities.ObjectUtilities.GetObject(fieldPtr); DecrementRefCount(theFieldObj, true); #if GC_TRACE BasicConsole.WriteLine("Cleaned up field."); #endif } FieldInfoPtr++; } if (FieldInfoPtr->Size == 0) { FieldInfoPtr = (FieldInfo *)FieldInfoPtr->FieldType; } } AddObjectToCleanup(gcHeaderPtr, objPtr); } } }
public static void *NewString(int length) { if (!Enabled) { BasicConsole.SetTextColour(BasicConsole.warning_colour); BasicConsole.WriteLine("Warning! GC returning null pointer because GC not enabled."); BasicConsole.DelayOutput(10); BasicConsole.SetTextColour(BasicConsole.default_colour); return(null); } //try { if (length < 0) { BasicConsole.SetTextColour(BasicConsole.error_colour); BasicConsole.WriteLine("Error! GC can't create a new string because \"length\" is less than 0."); BasicConsole.DelayOutput(5); BasicConsole.SetTextColour(BasicConsole.default_colour); return(null); //ExceptionMethods.Throw_OverflowException(); } InsideGC = true; //Alloc space for GC header that prefixes object data //Alloc space for new string object //Alloc space for new string chars uint totalSize = ((Testing2.Type) typeof(Testing2.String)).Size; totalSize += /*char size in bytes*/ 2 * (uint)length; totalSize += (uint)sizeof(GCHeader); GCHeader *newObjPtr = (GCHeader *)Heap.AllocZeroed(totalSize, "GC : NewString"); if ((UInt32)newObjPtr == 0) { InsideGC = false; BasicConsole.SetTextColour(BasicConsole.error_colour); BasicConsole.WriteLine("Error! GC can't create a new string because the heap returned a null pointer."); BasicConsole.DelayOutput(10); BasicConsole.SetTextColour(BasicConsole.default_colour); return(null); } NumObjs++; NumStrings++; //Initialise the GCHeader SetSignature(newObjPtr); //RefCount to 0 initially because of Testing2.String.New should be used // - In theory, New should be called, creates new string and passes it back to caller // Caller is then required to store the string in a variable resulting in inc. // ref count so ref count = 1 in only stored location. // Caller is not allowed to just "discard" (i.e. use Pop IL op or C# that generates // Pop IL op) so ref count will always at some point be incremented and later // decremented by managed code. OR the variable will stay in a static var until // the OS exits... newObjPtr->RefCount = 0; Testing2.String newStr = (Testing2.String)Utilities.ObjectUtilities.GetObject(newObjPtr + 1); newStr._Type = (Testing2.Type) typeof(Testing2.String); newStr.length = length; //Move past GCHeader byte *newObjBytePtr = (byte *)(newObjPtr + 1); InsideGC = false; return(newObjBytePtr); } //finally { //ExitCritical(); } }
public static void *NewArr(int length, Testing2.Type elemType) { if (!Enabled) { BasicConsole.SetTextColour(BasicConsole.warning_colour); BasicConsole.WriteLine("Warning! GC returning null pointer because GC not enabled."); BasicConsole.DelayOutput(10); BasicConsole.SetTextColour(BasicConsole.default_colour); return(null); } //try { if (length < 0) { UART.Write("length < 0. Overflow exception."); return(null); //ExceptionMethods.Throw_OverflowException(); } InsideGC = true; //Alloc space for GC header that prefixes object data //Alloc space for new array object //Alloc space for new array elems uint totalSize = ((Testing2.Type) typeof(Testing2.Array)).Size; if (elemType.IsValueType) { totalSize += elemType.Size * (uint)length; } else { totalSize += elemType.StackSize * (uint)length; } totalSize += (uint)sizeof(GCHeader); GCHeader *newObjPtr = (GCHeader *)Heap.AllocZeroed(totalSize, "GC : NewArray"); if ((UInt32)newObjPtr == 0) { InsideGC = false; BasicConsole.SetTextColour(BasicConsole.error_colour); BasicConsole.WriteLine("Error! GC can't create a new array because the heap returned a null pointer."); BasicConsole.DelayOutput(10); BasicConsole.SetTextColour(BasicConsole.default_colour); return(null); } NumObjs++; //Initialise the GCHeader SetSignature(newObjPtr); newObjPtr->RefCount = 1; Testing2.Array newArr = (Testing2.Array)Utilities.ObjectUtilities.GetObject(newObjPtr + 1); newArr._Type = (Testing2.Type) typeof(Testing2.Array); newArr.length = length; newArr.elemType = elemType; //Move past GCHeader byte *newObjBytePtr = (byte *)(newObjPtr + 1); InsideGC = false; return(newObjBytePtr); } //finally { } }
public static void Cleanup() { if (!Enabled /*|| InsideGC*/) { return; } EnterCritical("Cleanup"); try { InsideGC = true; #if GC_TRACE int startNumObjs = NumObjs; int startNumStrings = NumStrings; #endif if (OutputTrace) { BasicConsole.WriteLine(" > Inside GC & Cleaning..."); } ObjectToCleanup *currObjToCleanupPtr = CleanupList; ObjectToCleanup *prevObjToCleanupPtr = null; if (OutputTrace) { BasicConsole.WriteLine(" > Got list..."); } while (currObjToCleanupPtr != null) { if (OutputTrace) { BasicConsole.WriteLine(" > Item not null."); FOS_System.String str1 = " > Item: 0x "; FOS_System.String str2 = " > Prev: 0x "; ExceptionMethods.FillString((uint)currObjToCleanupPtr, 18, str1); ExceptionMethods.FillString((uint)currObjToCleanupPtr->prevPtr, 18, str2); BasicConsole.WriteLine(str1); BasicConsole.WriteLine(str2); } GCHeader *objHeaderPtr = currObjToCleanupPtr->objHeaderPtr; void * objPtr = currObjToCleanupPtr->objPtr; if (OutputTrace) { BasicConsole.WriteLine(" > Got object handles."); } if (objHeaderPtr->RefCount <= 0) { if (OutputTrace) { BasicConsole.WriteLine(" > Ref count zero or lower."); } FOS_System.Object obj = (FOS_System.Object)Utilities.ObjectUtilities.GetObject(objPtr); if (OutputTrace) { BasicConsole.WriteLine(" > Got object."); } if (obj is FOS_System.String) { if (OutputTrace) { BasicConsole.WriteLine(" > (It's a string)."); } NumStrings--; } else { if (OutputTrace) { BasicConsole.WriteLine(" > (It's NOT a string)."); } NumObjs--; } if (OutputTrace) { BasicConsole.WriteLine(" > About to free object..."); } Heap.Free(objHeaderPtr); if (OutputTrace) { BasicConsole.WriteLine(" > Object freed."); } if (OutputTrace) { BasicConsole.WriteLine(" > Done."); } } if (OutputTrace) { BasicConsole.WriteLine(" > Shifting to next item..."); } prevObjToCleanupPtr = currObjToCleanupPtr; currObjToCleanupPtr = currObjToCleanupPtr->prevPtr; if (OutputTrace) { BasicConsole.WriteLine(" > Removing object to cleanup..."); } RemoveObjectToCleanup(prevObjToCleanupPtr); if (OutputTrace) { BasicConsole.WriteLine(" > Done."); BasicConsole.WriteLine(" > Loop back..."); } } InsideGC = false; #if GC_TRACE if (OutputTrace) { PrintCleanupData(startNumObjs, startNumStrings); } #endif } finally { ExitCritical(); } }
public static void _DecrementRefCount(byte* objPtr) { if ((uint)objPtr < (uint)sizeof(GCHeader)) { BasicConsole.SetTextColour(BasicConsole.error_colour); BasicConsole.WriteLine("Error! GC can't decrement ref count of an object in low memory."); uint* basePtr = (uint*)ExceptionMethods.BasePointer; // Go up the linked-list of stack frames to (hopefully) the outermost caller basePtr = (uint*)*(basePtr); // DecrementRefCount(x, y) basePtr = (uint*)*(basePtr); // DecrementRefCount(x) uint retAddr = *(basePtr + 1); uint objAddr = (uint)objPtr; String msgStr = "Caller: 0x , Object: 0x "; // Object: 37 // Caller: 17 ExceptionMethods.FillString(retAddr, 17, msgStr); ExceptionMethods.FillString(objAddr, 37, msgStr); BasicConsole.WriteLine(msgStr); BasicConsole.DelayOutput(5); BasicConsole.SetTextColour(BasicConsole.default_colour); } GCHeader* gcHeaderPtr = (GCHeader*)(objPtr - sizeof(GCHeader)); if (CheckSignature(gcHeaderPtr)) { gcHeaderPtr->RefCount--; //If the ref count goes below 0 then there was a circular reference somewhere. // In actuality we don't care we can just only do cleanup when the ref count is // exactly 0. if (gcHeaderPtr->RefCount == 0) { #if GC_TRACE if (OutputTrace) { BasicConsole.WriteLine("Cleaned up object."); } #endif FOS_System.Object obj = (FOS_System.Object)Utilities.ObjectUtilities.GetObject(objPtr); if (obj is FOS_System.Array) { //Decrement ref count of elements FOS_System.Array arr = (FOS_System.Array)obj; if (!arr.elemType.IsValueType) { FOS_System.Object[] objArr = (FOS_System.Object[])Utilities.ObjectUtilities.GetObject(objPtr); for (int i = 0; i < arr.length; i++) { DecrementRefCount(objArr[i], true); } } } //Cleanup fields FieldInfo* FieldInfoPtr = obj._Type.FieldTablePtr; //Loop through all fields. The if-block at the end handles moving to parent // fields. while (FieldInfoPtr != null) { if (FieldInfoPtr->Size > 0) { FOS_System.Type fieldType = (FOS_System.Type)Utilities.ObjectUtilities.GetObject(FieldInfoPtr->FieldType); if (!fieldType.IsValueType && !fieldType.IsPointer) { byte* fieldPtr = objPtr + FieldInfoPtr->Offset; FOS_System.Object theFieldObj = (FOS_System.Object)Utilities.ObjectUtilities.GetObject(fieldPtr); DecrementRefCount(theFieldObj, true); #if GC_TRACE if (OutputTrace) { BasicConsole.WriteLine("Cleaned up field."); } #endif } FieldInfoPtr++; } if (FieldInfoPtr->Size == 0) { FieldInfoPtr = (FieldInfo*)FieldInfoPtr->FieldType; } } AddObjectToCleanup(gcHeaderPtr, objPtr); } } }
public static void* NewObj(FOS_System.Type theType) { if (!Enabled) { BasicConsole.SetTextColour(BasicConsole.warning_colour); BasicConsole.WriteLine("Warning! GC returning null pointer because GC not enabled."); BasicConsole.Write("Last disabler: "); BasicConsole.WriteLine(lastDisabler); BasicConsole.DelayOutput(10); BasicConsole.SetTextColour(BasicConsole.default_colour); return null; } #if GC_TRACE if (OutputTrace) { BasicConsole.WriteLine("NewObj"); } #endif EnterCritical("NewObj"); try { InsideGC = true; //Alloc space for GC header that prefixes object data //Alloc space for new object uint totalSize = theType.Size; totalSize += (uint)sizeof(GCHeader); GCHeader* newObjPtr = (GCHeader*)Heap.AllocZeroed(totalSize, "GC : NewObject"); if ((UInt32)newObjPtr == 0) { InsideGC = false; BasicConsole.SetTextColour(BasicConsole.error_colour); BasicConsole.WriteLine("Error! GC can't create a new object because the heap returned a null pointer."); BasicConsole.DelayOutput(10); BasicConsole.SetTextColour(BasicConsole.default_colour); return null; } NumObjs++; //Initialise the GCHeader SetSignature(newObjPtr); newObjPtr->RefCount = 1; //Initialise the object _Type field FOS_System.ObjectWithType newObj = (FOS_System.ObjectWithType)Utilities.ObjectUtilities.GetObject(newObjPtr + 1); newObj._Type = theType; //Move past GCHeader byte* newObjBytePtr = (byte*)(newObjPtr + 1); InsideGC = false; return newObjBytePtr; } finally { ExitCritical(); } }