Cosmos/source/Playgrounds/Ralf/EsxTest/Heap.cs
ralfkronemeyer_cp def59164b3 modified Ptr
2008-08-14 16:22:28 +00:00

1463 lines
50 KiB
C#

//#define NOCOSMOS
using System;
using System.IO;
using System.Text;
using Cosmos.Kernel;
namespace EsxTest
{
//RalfHeap
public struct FragmentHeader
{
internal const UInt32 HeaderSize = 4; //to avoid the usage of sizeof(FragmentHeader)
internal const UInt32 MaxSizeIndex = 31; //Max value for SizeIndex (31 on 32Bit Systems) (255 on 256Bit Systems ;-)
private const UInt32 HasChild1Bit = 0x100;
private const UInt32 HasChild2Bit = 0x200;
private const UInt32 HasDataBit = 0x400;
private const UInt32 IsChild2OfParentBit = 0x800;
private UInt32 _Header;
//00000000 00000000 00000000 00000000
//|||||||| |||||||| |||||||| ||||||||
//|||||||| |||||||| |||||||| -------- SizeIndex
//|||||||| |||||||| ||||||||
//|||||||| |||||||| |||||||+--------- HasChild1
//|||||||| |||||||| ||||||+---------- HasChild2
//|||||||| |||||||| |||||+----------- HasData -> 1 if Fragment contains Data (in this case HasChild1 and HasChild2 must be 0)
//|||||||| |||||||| ||||+------------ IsChild2OfParent -> 1 if Child2 of the parent, 0 if Child1 of parent
//|||||||| |||||||| |||+------------- Not used
//|||||||| |||||||| ||+-------------- Not used
//|||||||| |||||||| |+--------------- Not used
//|||||||| |||||||| +---------------- Not used
//|||||||| ||||||||
//|||||||| -------------------------- Not used
//||||||||
//----------------------------------- Not used
internal void Initialize(int sizeIndex)
{
_Header = 0;
SizeIndex = sizeIndex;
#if NOCOSMOS
if (SizeIndex!=sizeIndex)
{
Heap.CallException("Initialize failed");
}
#endif
}
internal int SizeIndex
{
get
{
return (int)(_Header &0xFF);
}
private set
{
#region validation
//general heap logic problem, if one these exceptions occurs
if (value > MaxSizeIndex)
{
Heap.CallException("FragmentHeader.SizeIndex overflow");
}
#endregion
_Header = _Header & 0xFF;
_Header = _Header | (UInt32)(value);
}
}
internal bool HasChild1
{
get { return (_Header & HasChild1Bit) != 0; }
set
{
if (value)
{
#region validation
//general heap logic problem, if one these exceptions occurs
if (HasData)
{
Heap.CallException("Set HasChild1 true failed! Data exists");
}
#endregion
_Header = (_Header | HasChild1Bit);
}
else
{
_Header = _Header & ~HasChild1Bit;
}
}
}
internal bool HasChild2
{
get { return (_Header & HasChild2Bit) != 0; }
set
{
if (value)
{
#region validation
//general heap logic problem, if one these exceptions occurs
if (HasData)
{
Heap.CallException("Set HasChild2 true failed! Data exits");
}
#endregion
_Header = (_Header | HasChild2Bit);
}
else
{
_Header = _Header & ~HasChild2Bit;
}
}
}
internal bool HasChild { get { return HasChild1 || HasChild2; } }
internal bool HasData
{
get { return (_Header & HasDataBit) != 0; }
set
{
if (value)
{
#region validation
//general heap logic problem, if one these exceptions occurs
if (HasChild)
{
Heap.CallException("Set HasData true failed! Child exits");
}
#endregion
_Header = _Header | HasDataBit;
}
else
{
_Header = _Header & ~HasDataBit;
}
}
}
internal bool IsEmpty { get { return !(HasData || HasChild); } }
internal bool IsChild2OfParent
{
get { return (_Header & IsChild2OfParentBit) != 0; }
set
{
if (value)
{
_Header = (_Header | IsChild2OfParentBit);
}
else
{
_Header = (_Header & ~IsChild2OfParentBit);
}
}
}
internal unsafe UInt32 FragmentAddress
{
get
{
fixed (UInt32* address = &_Header)
{
return (UInt32) address;
}
}
}
internal UInt32 Child1Address
{
get
{
return FragmentAddress + HeaderSize;
}
}
internal UInt32 Child2Address
{
get
{
return FragmentAddress + Heap.GetFragmentSize(SizeIndex - 1) + HeaderSize;
}
}
internal UInt32 DataAddress
{
get
{
return FragmentAddress + HeaderSize;
}
}
internal bool HasParent
{
get
{
if (FragmentAddress > Heap.StartAddress)
{
return true;
}
return false;
}
}
internal UInt32 ParentAddress
{
get
{
#region validation
//general heap logic problem, if one these exceptions occurs
if (FragmentAddress == Heap.StartAddress)
{
Heap.CallException("No Parent available");
}
#endregion
if (IsChild2OfParent)
{
return FragmentAddress - Heap.GetFragmentSize(SizeIndex) - HeaderSize;
}
return FragmentAddress - HeaderSize;
}
}
internal unsafe void AllocateInParent()
{
var parentHeaderPtr = (FragmentHeader*) ParentAddress;
#region validation
//general heap logic problem, if one these exceptions occurs
if (parentHeaderPtr->HasData)
{
Heap.CallException("AllocateInParent failed: Data already exits", FragmentAddress);
}
if (IsChild2OfParent)
{
if (parentHeaderPtr->HasChild2)
{
Heap.CallException("AllocateInParent failed: Child2 already exits", FragmentAddress);
}
}
else
{
if (parentHeaderPtr->HasChild1)
{
Heap.CallException("AllocateInParent failed: Child1 already exits", FragmentAddress);
}
}
#endregion
if (IsChild2OfParent)
{
parentHeaderPtr->HasChild2 = true;
}
else
{
parentHeaderPtr->HasChild1 = true;
}
}
internal unsafe void FreeInParent()
{
var parentHeaderPtr = (FragmentHeader*) ParentAddress;
#region validation
//general heap logic problem, if one these exceptions occurs
if (parentHeaderPtr->HasData)
{
Heap.CallException("FreeInParent failed: Parent HasData ", FragmentAddress);
}
if (IsChild2OfParent)
{
if (!parentHeaderPtr->HasChild2)
{
Heap.CallException("FreeInParent failed: Child2 doesnt exits", FragmentAddress);
}
}
else
{
if (!parentHeaderPtr->HasChild1)
{
Heap.CallException("FreeInParent failed: Child1 doesnt exits", FragmentAddress);
}
}
#endregion
if (IsChild2OfParent)
{
parentHeaderPtr->HasChild2 = false;
}
else
{
parentHeaderPtr->HasChild1 = false;
}
}
internal static unsafe void Debug(UInt32 address)
{
#if NOCOSMOS
if (address == 0)
{
Heap.Debug("[]");
return;
}
var header = (FragmentHeader*)address;
Heap.Debug("[" + Convert.ToString(address - Heap.StartAddress, 10) + "] si=" + (*header).SizeIndex + " header=" +
Convert.ToString((*header)._Header, 16));
// StringBuilder sb = new StringBuilder();
//
// for (int i = 0; i < Heap.GetFragmentDataSize((*header).SizeIndex); i++)
// {
// var b = (byte*) ((*header).DataAddress+i);
// sb.Append(Convert.ToString(*b,16));
// sb.Append(" ");
// }
// Heap.Debug(sb.ToString());
#else
Heap.WriteNumber(address);
// Heap.Debug("");
// Heap.DebugAppendAddress(address);
// Heap.DebugAppend("si=");
// Heap.DebugAppend((UInt32)(*header).SizeIndex);
// if ((*header).IsChild2OfParent)
// {
// Heap.DebugAppend(" PC2");
// }
// else
// {
// Heap.DebugAppend(" PC1");
// }
// if ((*header).HasData)
// {
// Heap.DebugAppend(" D=1");
// }
// else
// {
// Heap.DebugAppend(" D=0");
// }
// if ((*header).HasChild1)
// {
// Heap.DebugAppend(" C1=1");
// }
// else
// {
// Heap.DebugAppend(" C1=0");
// }
// if ((*header).HasChild2)
// {
// Heap.DebugAppend(" C2=1");
// }
// else
// {
// Heap.DebugAppend(" C2=0");
// }
//
#endif
}
}
public static class HeapCounter
{
public static UInt32 Count { get; internal set; }
public static UInt32 DataSize { get; internal set; } //should be UInt64
public static UInt32 MemAlloc { get; internal set; } //should be UInt64
public static UInt32 MemFree { get; internal set; } //should be UInt64
public static UInt32 CachePush { get; internal set; } //should be UInt64
public static UInt32 CachePop { get; internal set; } //should be UInt64
public static UInt32 Create { get; internal set; } //should be UInt64
public static UInt32 Search { get; internal set; } //should be UInt64
public static UInt32 SearchSuccess { get; internal set; } //should be UInt64
public static UInt32 SearchTotal { get; internal set; } //should be UInt64 includes recursive calls
public static void Print()
{
Console.Write("Count........ =");
Heap.WriteNumber(Count);
Console.WriteLine();
Console.Write("DataSize..... =");
Heap.WriteNumber(DataSize);
Console.WriteLine();
Console.Write("MemAlloc..... =");
Heap.WriteNumber(MemAlloc);
Console.WriteLine();
Console.Write("MemFree...... =");
Heap.WriteNumber(MemFree);
Console.WriteLine();
Console.Write("CachePush.... =");
Heap.WriteNumber(CachePush);
Console.WriteLine();
Console.Write("CachePop..... =");
Heap.WriteNumber(CachePop);
Console.WriteLine();
Console.Write("Create....... =");
Heap.WriteNumber(Create);
Console.WriteLine();
Console.Write("Search....... =");
Heap.WriteNumber(Search);
Console.WriteLine();
Console.Write("SearchSuccess =");
Heap.WriteNumber(SearchSuccess);
Console.WriteLine();
Console.Write("SearchTotal.. =");
Heap.WriteNumber(SearchTotal);
Console.WriteLine();
}
}
public static class Heap
{
private const byte PointerSize = 4; //4 Byte on 32Bit Systems
internal static UInt32 StartAddress { get; private set; }
private static UInt32 EndAddress { get; set; }
private static UInt32 Size { get; set; }
internal static UInt32 MaxFragmentDataSize { get; private set; }
internal static int MaxFragmentSizeIndex { get; private set; }
private static bool Initiated { get; set; }
public static unsafe void Init(UInt32 startAddress,UInt32 size, UInt32 cacheSize)
{
Debug("Begin Init");
if (Initiated)
return;
DebugActive = false;
#if NOCOSMOS
DebugActive = true;
#endif
if (cacheSize>=size)
{
CallException("Init: cachesize>=size");
}
CacheSize = cacheSize;
MaxStackValue = CacheSize / CacheStackPointerMemorySize;
if (MaxStackValue == 0)
{
CallException("Init: cacheSize too small");
}
if (CacheSize % CacheStackPointerMemorySize!=0)
{
CallException("Init: wrong cacheSize");
}
CacheStackPointerAddress = startAddress;
ZeroFill(CacheStackPointerAddress, CacheStackPointerMemorySize);
CacheAddress = CacheStackPointerAddress + CacheStackPointerMemorySize;
ZeroFill(CacheAddress, CacheSize);
StartAddress = CacheAddress + CacheSize;
EndAddress = StartAddress
+ (size - CacheSize - CacheStackPointerMemorySize)
- (PointerSize - ((size - CacheSize - CacheStackPointerMemorySize) % PointerSize)) - PointerSize;
Size = EndAddress - StartAddress;
MaxFragmentDataSize = Size - FragmentHeader.HeaderSize;
CalculateFragmentSizes(Size);
var rootHeaderPtr = (FragmentHeader*)StartAddress;
rootHeaderPtr->Initialize(MaxFragmentSizeIndex);
//ClearFragment(StartAddress, GetFragmentDataSize((*RootHeader).SizeIndex)); //this is bad for ESX Server
#if NOCOSMOS
Debug("CacheStackPointerAddress=" + CacheStackPointerAddress);
Debug("CacheAddress=" + CacheAddress);
Debug("StartAddress=" + StartAddress);
Debug("EndAddress=" + EndAddress);
Debug("");
#endif
PushFreeFragmentAddress(MaxFragmentSizeIndex, StartAddress);
if (MaxFragmentDataSize == 0)
{
CallException("Heap Init failed!");
}
Initiated = true;
Debug("End Init");
}
public static unsafe UInt32 MemAlloc(UInt32 size)
{
#if NOCOSMOS
Debug("Begin Malloc HeaderSize=" + size);
#else
Debug("Begin Malloc");
#endif
if (!Initiated)
{
CallException("MemAlloc: not Initiated"); //Todo: eliminate this behaviour, we need a centralized point for Heap.Init
}
if (size == 0)
{
CallException("MemAlloc: size==0");
}
int sizeIndex = GetSizeIndex(size);
if (GetFragmentDataSize(sizeIndex) > MaxFragmentDataSize)
{
CallException("MemAlloc: Too large memory block allocated!");
}
var fragmentAddress = GetFreeFragmentAddress(sizeIndex);
if (fragmentAddress == 0)
{
fragmentAddress = CreateFragment(sizeIndex);
}
if (fragmentAddress==0)
{
CallException("MemAlloc: Out of memory");
}
var fragmentHeaderPtr = (FragmentHeader*)fragmentAddress;
fragmentHeaderPtr->HasData = true;
#region validation
//general heap logic problem, if one these exceptions occurs
if (fragmentHeaderPtr->SizeIndex != sizeIndex)
{
CallException("MemAlloc: SizeIndex wrong", fragmentAddress);
}
if (GetFragmentDataSize(fragmentHeaderPtr->SizeIndex) < size)
{
CallException("MemAlloc: HeaderSize mismatch", fragmentAddress);
}
#endregion
ClearFragment(fragmentAddress,size);
++HeapCounter.MemAlloc;
++HeapCounter.Count;
HeapCounter.DataSize += GetFragmentSize(fragmentHeaderPtr->SizeIndex);
Debug(fragmentAddress);
#if NOCOSMOS
Debug("End Malloc HeaderSize=" + size);
Debug("");
Debug(StartAddress);
Debug("");
#else
Debug("End Malloc");
#endif
return fragmentAddress + FragmentHeader.HeaderSize;
}
public static unsafe void MemFree(UInt32 pointer)
{
Debug("Begin MemFree");
if (pointer == 0)
{
CallException("MemFree: pointer==0");
}
var fragmentAddress = pointer - FragmentHeader.HeaderSize;
var fragmentHeaderPtr = (FragmentHeader*)fragmentAddress;
Debug(fragmentAddress);
fragmentHeaderPtr->HasData = false;
fragmentHeaderPtr->FreeInParent();
PushFreeFragmentAddress(fragmentHeaderPtr->SizeIndex, fragmentAddress);
++HeapCounter.MemFree;
--HeapCounter.Count;
HeapCounter.DataSize -= GetFragmentSize(fragmentHeaderPtr->SizeIndex);
Debug("End MemFree");
}
private static unsafe void ClearFragment(UInt32 fragmentAddress, UInt32 size)
{
#if NOCOSMOS
Debug("Begin ClearFragment HeaderSize=" + size);
#else
Debug("Begin ClearFragment");
#endif
Debug(fragmentAddress);
#region validation
//general heap logic problem, if one these exceptions occurs
var headerPtr = (FragmentHeader*) fragmentAddress;
if (size>GetFragmentDataSize(headerPtr->SizeIndex))
{
CallException("ClearFragment: size mismatch", fragmentAddress);
}
#endregion
ZeroFill(fragmentAddress + FragmentHeader.HeaderSize, size);
Debug("After Clear:");
Debug(fragmentAddress);
#if NOCOSMOS
Debug("End ClearFragment HeaderSize=" + size);
#else
Debug("End ClearFragment");
#endif
}
private static unsafe void ZeroFill(UInt32 address, UInt32 size)
{
#if NOCOSMOS
int* ptr = (int*) address;
for (UInt32 i = 0; i < size /4 ; i++)
{
*ptr = 0;
ptr++;
}
#else
CPU.ZeroFill(address, size);
#endif
}
private static int GetSizeIndex(UInt32 size)
{
for (int i = 0; i < 32; i++)
{
if (GetFragmentDataSize(i) >= size)
{
#if NOCOSMOS
Debug("GetSizeIndex for size=" + size + " result=" + i);
#endif
return i;
}
}
CallException("GetSizeIndex failed");
return -1;
}
private static unsafe UInt32 GetFreeFragmentAddress(int sizeIndex)
{
#if NOCOSMOS
Debug("Begin GetFreeFragmentAddress si=" + sizeIndex);
#else
Debug("Begin GetFreeFragmentAddress");
#endif
var address = PopFreeFragmentAddress(sizeIndex);
if (address != 0)
{
if (address != StartAddress)
{
var headerPtr = (FragmentHeader*) address;
headerPtr->AllocateInParent();
}
}
else
{
//Starting at the root of the heap
++HeapCounter.Search;
address = SearchFreeFragmentAddress(sizeIndex, StartAddress);
if (address != 0)
{
Debug("Search success");
Debug(address);
}
}
Debug(address);
#if NOCOSMOS
Debug("End GetFreeFragmentAddress si=" + sizeIndex);
#else
Debug("End GetFreeFragmentAddress");
#endif
return address;
}
private static unsafe UInt32 SearchFreeFragmentAddress(int sizeIndex, UInt32 address)
{
#if NOCOSMOS
Debug("Begin SearchFreeFragmentAddress for sizeIndex=" + sizeIndex + "in Fragment:");
#else
Debug("Begin SearchFreeFragmentAddress");
#endif
Debug(address);
++DebugTab;
++HeapCounter.SearchTotal;
UInt32 freeAddress = 0;
var headerPtr = (FragmentHeader*)address;
if (sizeIndex+1 <= headerPtr->SizeIndex)
{
if (sizeIndex+1 == headerPtr->SizeIndex)
{
if (headerPtr->IsEmpty)
{
freeAddress = headerPtr->Child1Address;
var child1HeaderPtr = (FragmentHeader*) freeAddress;
child1HeaderPtr->Initialize(sizeIndex);
headerPtr->HasChild1 = true;
var child2HeaderPtr = (FragmentHeader*)headerPtr->Child2Address;
child2HeaderPtr->Initialize(sizeIndex);
child2HeaderPtr->IsChild2OfParent = true;
PushFreeFragmentAddress(sizeIndex, headerPtr->Child2Address);
++HeapCounter.SearchSuccess;
}
}
if (freeAddress == 0)
{
if (headerPtr->HasChild1)
{
freeAddress = SearchFreeFragmentAddress(sizeIndex, headerPtr->Child1Address);
}
if (freeAddress == 0)
{
if (headerPtr->HasChild2)
{
freeAddress = SearchFreeFragmentAddress(sizeIndex , headerPtr->Child2Address);
}
}
}
}
if (freeAddress != 0)
{
var freeHeaderPtr = (FragmentHeader*) freeAddress;
if (freeHeaderPtr->SizeIndex!=sizeIndex)
{
CallException("SearchFreeFragmentAddress: SizeIndex mismatch", freeAddress);
}
}
--DebugTab;
if (freeAddress != 0)
{
Debug("Found:");
Debug(freeAddress);
}
#if NOCOSMOS
Debug("End SearchFreeFragmentAddress for sizeIndex=" + sizeIndex);
#else
Debug("End SearchFreeFragmentAddress");
#endif
return freeAddress;
}
private static unsafe UInt32 CreateFragment(int sizeIndex)
{
#if NOCOSMOS
Debug("Begin CreateFragment si=" + sizeIndex);
#else
Debug("Begin CreateFragment");
#endif
++DebugTab;
if (sizeIndex>=MaxFragmentSizeIndex)
{
CallException("CreateFragment: sizeIndex overflow");
}
if (sizeIndex > MaxFragmentSizeIndex)
{
CallException("CreateFragment failed (sizeIndex)");
}
UInt32 fragmentAddress = 0;
UInt32 parentFragmentAddress = GetFreeFragmentAddress(sizeIndex + 1);
if ((parentFragmentAddress == 0))
{
parentFragmentAddress = CreateFragment(sizeIndex + 1);
}
if (parentFragmentAddress == 0)
{
//Out of memory
//CallException("CreateFragment failed parentFragmentAddress=0");
}
else
{
var parentHeaderPtr = (FragmentHeader*) parentFragmentAddress;
if (parentHeaderPtr->HasChild1 && parentHeaderPtr->HasChild2)
{
//Out of memory
return 0;
}
parentHeaderPtr->HasChild1 = true;
fragmentAddress = parentHeaderPtr->Child1Address;
var child2Address = parentHeaderPtr->Child2Address;
var child2HeaderPtr = (FragmentHeader*) child2Address;
child2HeaderPtr->Initialize(sizeIndex);
child2HeaderPtr->IsChild2OfParent = true;
PushFreeFragmentAddress(sizeIndex, child2Address);
if (fragmentAddress == 0)
{
CallException("CreateFragment failed");
}
++HeapCounter.Create;
var fragmentHeaderPtr = (FragmentHeader*) fragmentAddress;
fragmentHeaderPtr->Initialize(sizeIndex);
--DebugTab;
Debug("Created:");
Debug(fragmentAddress);
#if NOCOSMOS
Debug("End CreateFragment si=" + sizeIndex);
#else
Debug("End CreateFragment");
#endif
}
return fragmentAddress;
}
#region FragmentSize
internal static UInt32 FragmentSize00 { get; set; }
internal static UInt32 FragmentSize01 { get; set; }
internal static UInt32 FragmentSize02 { get; set; }
internal static UInt32 FragmentSize03 { get; set; }
internal static UInt32 FragmentSize04 { get; set; }
internal static UInt32 FragmentSize05 { get; set; }
internal static UInt32 FragmentSize06 { get; set; }
internal static UInt32 FragmentSize07 { get; set; }
internal static UInt32 FragmentSize08 { get; set; }
internal static UInt32 FragmentSize09 { get; set; }
internal static UInt32 FragmentSize10 { get; set; }
internal static UInt32 FragmentSize11 { get; set; }
internal static UInt32 FragmentSize12 { get; set; }
internal static UInt32 FragmentSize13 { get; set; }
internal static UInt32 FragmentSize14 { get; set; }
internal static UInt32 FragmentSize15 { get; set; }
internal static UInt32 FragmentSize16 { get; set; }
internal static UInt32 FragmentSize17 { get; set; }
internal static UInt32 FragmentSize18 { get; set; }
internal static UInt32 FragmentSize19 { get; set; }
internal static UInt32 FragmentSize20 { get; set; }
internal static UInt32 FragmentSize21 { get; set; }
internal static UInt32 FragmentSize22 { get; set; }
internal static UInt32 FragmentSize23 { get; set; }
internal static UInt32 FragmentSize24 { get; set; }
internal static UInt32 FragmentSize25 { get; set; }
internal static UInt32 FragmentSize26 { get; set; }
internal static UInt32 FragmentSize27 { get; set; }
internal static UInt32 FragmentSize28 { get; set; }
internal static UInt32 FragmentSize29 { get; set; }
internal static UInt32 FragmentSize30 { get; set; }
internal static UInt32 FragmentSize31 { get; set; }
private static void SetFragmentSize(int sizeIndex, UInt32 size)
{
switch (sizeIndex)
{
case 0:
FragmentSize00 = size;
break;
case 1:
FragmentSize01 = size;
break;
case 2:
FragmentSize02 = size;
break;
case 3:
FragmentSize03 = size;
break;
case 4:
FragmentSize04 = size;
break;
case 5:
FragmentSize05 = size;
break;
case 6:
FragmentSize06 = size;
break;
case 7:
FragmentSize07 = size;
break;
case 8:
FragmentSize08 = size;
break;
case 9:
FragmentSize09 = size;
break;
case 10:
FragmentSize10 = size;
break;
case 11:
FragmentSize11 = size;
break;
case 12:
FragmentSize12 = size;
break;
case 13:
FragmentSize13 = size;
break;
case 14:
FragmentSize14 = size;
break;
case 15:
FragmentSize15 = size;
break;
case 16:
FragmentSize16 = size;
break;
case 17:
FragmentSize17 = size;
break;
case 18:
FragmentSize18 = size;
break;
case 19:
FragmentSize19 = size;
break;
case 20:
FragmentSize20 = size;
break;
case 21:
FragmentSize21 = size;
break;
case 22:
FragmentSize22 = size;
break;
case 23:
FragmentSize23 = size;
break;
case 24:
FragmentSize24 = size;
break;
case 25:
FragmentSize25 = size;
break;
case 26:
FragmentSize26 = size;
break;
case 27:
FragmentSize27 = size;
break;
case 28:
FragmentSize28 = size;
break;
case 29:
FragmentSize29 = size;
break;
case 30:
FragmentSize30 = size;
break;
case 31:
FragmentSize31 = size;
break;
default:
CallException("SetFragmentAddress");
break;
}
}
internal static UInt32 GetFragmentSize(int sizeIndex)
{
switch (sizeIndex)
{
case 0:
return FragmentSize00;
case 1:
return FragmentSize01;
case 2:
return FragmentSize02;
case 3:
return FragmentSize03;
case 4:
return FragmentSize04;
case 5:
return FragmentSize05;
case 6:
return FragmentSize06;
case 7:
return FragmentSize07;
case 8:
return FragmentSize08;
case 9:
return FragmentSize09;
case 10:
return FragmentSize10;
case 11:
return FragmentSize11;
case 12:
return FragmentSize12;
case 13:
return FragmentSize13;
case 14:
return FragmentSize14;
case 15:
return FragmentSize15;
case 16:
return FragmentSize16;
case 17:
return FragmentSize17;
case 18:
return FragmentSize18;
case 19:
return FragmentSize19;
case 20:
return FragmentSize20;
case 21:
return FragmentSize21;
case 22:
return FragmentSize22;
case 23:
return FragmentSize23;
case 24:
return FragmentSize24;
case 25:
return FragmentSize25;
case 26:
return FragmentSize26;
case 27:
return FragmentSize27;
case 28:
return FragmentSize28;
case 29:
return FragmentSize29;
case 30:
return FragmentSize30;
case 31:
return FragmentSize31;
default:
CallException("GetFragmentSize");
return 0;
}
}
internal static UInt32 GetFragmentDataSize(int sizeIndex)
{
return GetFragmentSize(sizeIndex) - FragmentHeader.HeaderSize;
}
private static void CalculateFragmentSizes(UInt32 maxSize)
{
int startSizeIndex = 31;
bool success=false;
while (startSizeIndex>=0)
{
success = true;
SetFragmentSize(startSizeIndex, maxSize);
for (int sizeIndex = startSizeIndex - 1; sizeIndex >= 0; sizeIndex--)
{
var childFragmentSize = GetFragmentSize(sizeIndex + 1) / 2 - FragmentHeader.HeaderSize;
childFragmentSize -= (PointerSize - (childFragmentSize % PointerSize)); //ensure alignment
if ((childFragmentSize==0) ||(childFragmentSize>GetFragmentSize(sizeIndex + 1)))
{
success = false;
break;
}
SetFragmentSize(sizeIndex, childFragmentSize);
}
if (success)
{
MaxFragmentSizeIndex = startSizeIndex;
break;
}
--startSizeIndex;
}
if (!success)
{
CallException("CalculateFragmentSizes: no success");
}
for (int sizeIndex = MaxFragmentSizeIndex + 1; sizeIndex < 32; sizeIndex++)
{
SetFragmentSize(sizeIndex, 0);
}
#if NOCOSMOS
var a = DebugActive;
DebugActive = true;
Debug("Calculate FragmentSizes");
for (int sizeIndex = 0; sizeIndex < 32; sizeIndex++)
{
Debug(sizeIndex + "=" + GetFragmentSize(sizeIndex));
// if (GetFragmentSize(sizeIndex) == 0)
// break;
}
Debug("MaxFragmentSizeIndex="+MaxFragmentSizeIndex);
DebugActive = a;
#endif
}
#endregion
#region FragmentCache
private static UInt32 MaxStackValue { get; set; }
private static UInt32 CacheStackPointerAddress { get; set; }
private static UInt32 CacheStackPointerMemorySize { get { return PointerSize * (FragmentHeader.MaxSizeIndex + 1); } }
private static UInt32 CacheSize { get; set; }
private static UInt32 CacheSizePerIndex { get { return CacheSize / (FragmentHeader.MaxSizeIndex + 1); } }
private static UInt32 CacheAddress { get; set; }
private static unsafe void PushFreeFragmentAddress(int sizeIndex, UInt32 address)
{
if (address != 0)
{
#if NOCOSMOS
Debug("Push si=" + sizeIndex);
#else
Debug("Push");
#endif
Debug(address);
++HeapCounter.CachePush;
#region validation
//general heap logic problem, if one these exceptions occurs
var headerPtr = (FragmentHeader*)address;
if (headerPtr->SizeIndex != sizeIndex)
{
CallException("PushFreeFragmentAddress: sizeIndex mismatch", address);
}
if (!headerPtr->IsEmpty)
{
CallException("PushFreeFragmentAddress: not empty", address);
}
if (headerPtr->HasParent)
{
var parentHeaderPtr = (FragmentHeader*) headerPtr->ParentAddress;
if (parentHeaderPtr->HasData)
{
CallException("PushFreeFragmentAddress: Parent HasData");
}
if (headerPtr->IsChild2OfParent)
{
if (parentHeaderPtr->HasChild2)
{
CallException("PushFreeFragmentAddress: ChildBit2 in Parent");
}
}
else
{
if (parentHeaderPtr->HasChild1)
{
CallException("PushFreeFragmentAddress: ChildBit1 in Parent");
}
}
}
if (sizeIndex > MaxFragmentSizeIndex)
{
CallException("PushFreeFragmentAddress: Worng sizeIndex", address);
}
#endregion
var stackPtr = (UInt32*)(CacheStackPointerAddress + sizeIndex * PointerSize);
if ((*stackPtr) < MaxStackValue )
{
var cacheValuePtr =
(UInt32*)
(CacheAddress + CacheSizePerIndex * sizeIndex + (*stackPtr) * PointerSize);
if ((UInt32)cacheValuePtr > StartAddress)
{
#if NOCOSMOS
Debug("cacheValuePtr=" + (UInt32)cacheValuePtr);
Debug("StartAddress=" + StartAddress);
#endif
CallException("PushFreeFragmentAddress: cacheValuePtr out of range");
}
if ((UInt32)cacheValuePtr < CacheAddress)
{
CallException("PushFreeFragmentAddress: cacheValuePtr out of range");
}
(*cacheValuePtr) = address;
#if NOCOSMOS
Debug("Push SizeIndex= " + sizeIndex + " cachePtr=" + (UInt32) cacheValuePtr + " <- " + address);
#endif
++(*stackPtr);
}
}
}
private unsafe static UInt32 PopFreeFragmentAddress(int sizeIndex)
{
UInt32 address=0;
if (sizeIndex > MaxFragmentSizeIndex)
{
CallException("PopFreeFragmentAddress: Worng sizeIndex");
}
var stackPtr = (UInt32*)(CacheStackPointerAddress + sizeIndex * PointerSize);
if ((*stackPtr)>MaxStackValue)
{
#if NOCOSMOS
DebugActive = true;
Debug("(*stackPtr)=" + (*stackPtr));
Debug("sizeIndex=" + sizeIndex);
#endif
CallException("PopFreeFragmentAddress: Wrong stackValue detetced");
}
while ((*stackPtr) > 0)
{
--(*stackPtr);
var cacheValuePtr = (UInt32*)(CacheAddress + CacheSizePerIndex * sizeIndex + (*stackPtr) * PointerSize);
#region validation
//general heap logic problem, if one these exceptions occurs
if ((UInt32)cacheValuePtr>StartAddress)
{
#if NOCOSMOS
Debug("cacheValuePtr="+(UInt32)cacheValuePtr);
Debug("StartAddress="+StartAddress);
#endif
CallException("PopFreeFragmentAddress: cacheValuePtr out of range");
}
if ((UInt32)cacheValuePtr < CacheAddress)
{
CallException("PopFreeFragmentAddress: cacheValuePtr out of range");
}
#endregion
address =(*cacheValuePtr);
#if NOCOSMOS
Debug("Pop SizeIndex=" + sizeIndex + " cachePtr=" + (UInt32)cacheValuePtr + " <- " + address);
#endif
if (address != 0)
{
var headerPtr = (FragmentHeader*) address;
if (headerPtr->IsEmpty)
{
++HeapCounter.CachePop;
#if NOCOSMOS
Debug("Pop si=" + sizeIndex);
#else
Debug("Pop");
#endif
return address;
}
address = 0;//Cached fragment is already used by Child or Parent - this can happen
}
}
return address;
}
#endregion
#region Debug
public static bool DebugActive { get; set; }
private static int DebugTab { get; set; }//Hack
#if NOCOSMOS
internal static StringBuilder sb;
internal static void Debug(string message)
{
if (!DebugActive)
return;
Console.WriteLine(message);
if (sb==null)
sb = new StringBuilder();
for (int i = 0; i < DebugTab; i++)
{
sb.Append(" ");
}
sb.AppendLine(message);
}
#else
internal static void Debug(string message)//Hack
{
if (!DebugActive)
return;
Console.WriteLine();
for (int i = 0; i < DebugTab; i++)
{
Console.Write(" ");
}
Console.Write(message);
// int j = 0;
// for (int i = 0; i < 1000000; i++)
// {
// ++j;
// --j;
// }
}
#endif
internal static void Debug(UInt32 address)
{
if (!DebugActive)
return;
FragmentHeader.Debug(address);
}
// internal static void Debug(string message)//Hack
// {
// if (!DebugActive)
// return;
// Console.WriteLine();
// for (int i = 0; i < DebugTab; i++)
// {
// Console.Write(" ");
//
// }
// Console.Write(message);
// int j = 0;
// for (int i = 0; i < 1000000; i++)
// {
// ++j;
// --j;
// }
// }
//
// internal static void Debug(string message, UInt32 number)//Hack
// {
// if (!DebugActive)
// return;
// Console.WriteLine();
// for (int i = 0; i < DebugTab; i++)
// {
// Console.Write(" ");
//
// }
// Console.Write(message);
// Console.Write(" ");
// WriteNumber(number);
// int j = 0;
// for (int i = 0; i < 1000000; i++)
// {
// ++j;
// --j;
// }
// }
//
// internal static void DebugAppend(string message)//Hack
// {
// if (!DebugActive)
// return;
// Console.Write(" ");
// Console.Write(message);
// }
//
//
// internal static void DebugAppend(UInt32 number)//Hack
// {
// if (!DebugActive)
// return;
// Console.Write(" ");
// WriteNumber(number);
// }
//
// internal static void DebugAppendAddress(UInt32 number)//Hack
// {
// if (!DebugActive)
// return;
// if (number == 0)
// {
// Console.Write(" 0");
// }
// else
// {
// DebugAppend(number - StartAddress);
// }
// }
//
public static void WriteNumber(UInt32 aNumber)//Hack
{
byte aBits = 32;
uint xValue = aNumber;
byte xCurrentBits = aBits;
Console.Write("0x");
while (xCurrentBits >= 4)
{
xCurrentBits -= 4;
byte xCurrentDigit = (byte)((xValue >> xCurrentBits) & 0xF);
string xDigitString = null;
switch (xCurrentDigit)
{
case 0:
xDigitString = "0";
goto default;
case 1:
xDigitString = "1";
goto default;
case 2:
xDigitString = "2";
goto default;
case 3:
xDigitString = "3";
goto default;
case 4:
xDigitString = "4";
goto default;
case 5:
xDigitString = "5";
goto default;
case 6:
xDigitString = "6";
goto default;
case 7:
xDigitString = "7";
goto default;
case 8:
xDigitString = "8";
goto default;
case 9:
xDigitString = "9";
goto default;
case 10:
xDigitString = "A";
goto default;
case 11:
xDigitString = "B";
goto default;
case 12:
xDigitString = "C";
goto default;
case 13:
xDigitString = "D";
goto default;
case 14:
xDigitString = "E";
goto default;
case 15:
xDigitString = "F";
goto default;
default:
Console.Write(xDigitString);
break;
}
}
}
#endregion
private static bool InException;
internal static void CallException(string message)//Hack: Exception not allowed because Heap usages
{
if (!InException)
{
InException = true;
//Console.WriteLine(sb.ToString());
Console.WriteLine();
Console.WriteLine("Heap.cs: Exception:");
Console.WriteLine(message);
#if NOCOSMOS
Debug("Exception:");
Debug(message);
Debug("StartAddress");
Debug(StartAddress);
if (sb != null)
{
File.WriteAllText("Heap.txt", sb.ToString());
}
#endif
while (true)
{
#if NOCOSMOS
#else
//CPU.Halt();
#endif
}
}
}
internal static void CallException(string message, UInt32 address)//Hack: Exception not allowed because Heap usages
{
if (!InException)
{
InException = true;
//Console.WriteLine(sb.ToString());
Console.WriteLine();
Console.WriteLine("Heap.cs: Exception:");
Console.WriteLine(message);
Console.WriteLine("Fragment:");
#if NOCOSMOS
DebugActive = true;
Debug("Exception:");
Debug(message);
Debug(address);
Debug("StartAddress");
Debug(StartAddress);
if (sb != null)
{
File.WriteAllText("Heap.txt", sb.ToString());
}
#endif
while (true)
{
#if NOCOSMOS
#else
//CPU.Halt();
#endif
}
}
}
}
}