1 // =================================
  2 // Copyright (c) 2022 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 namespace System
  7 {
  8     // Adapted from K&R C general purpose storage allocator example.
  9 
 10     private long pageSize = -1;
 11     private Block empty;
 12     private Block* free = null;
 13     
 14     public nothrow ulong FreeAddr()
 15     {
 16         return cast<ulong>(cast<void*>(free));
 17     }
 18     
 19     internal class Block
 20     {
 21         public nothrow Block() : next(null)size(0) {}
 22         public Block* next;
 23         public long size;
 24     }
 25     
 26     internal Block* MoreCore(long nb)
 27     {
 28         long bigBlock = Align(nbpageSize);
 29         int numPages = cast<int>(bigBlock / pageSize);
 30         long addr = heap_start() + heap_length();
 31         long sizeAllocated = allocate_memory_pages(numPages);
 32         if (sizeAllocated == -1)
 33         {
 34             exit(254);
 35         }
 36         long allocatedUnits = sizeAllocated / sizeof(Block);
 37         Block* a = cast<Block*>(cast<void*>(cast<ulong>(addr)));
 38         a->size = allocatedUnits;
 39         MemFree(a + 1);
 40         return free;
 41     }
 42 
 43     public nothrow void* MemAlloc(long numBytes)
 44     {
 45         Block* prev = free;
 46         if (free == null)
 47         {
 48             pageSize = memory_page_size();
 49             empty.next = &empty;
 50             prev = &empty;
 51             free = prev;
 52         }
 53         long nb = Align(numBytessizeof(Block)) + sizeof(Block);
 54         long numUnits = nb / sizeof(Block);
 55         Block* p = prev->next;
 56         while (true)
 57         {
 58             if (p->size >= numUnits)
 59             {
 60                 if (p->size == numUnits)
 61                 {
 62                     prev->next = p->next;
 63                 }
 64                 else
 65                 {
 66                     p->size = p->size - numUnits;
 67                     p = p + p->size;
 68                     p->size = numUnits;
 69                 }
 70                 free = prev;
 71                 return p + 1;
 72             }
 73             if (p == free)
 74             {
 75                 p = MoreCore(nb);
 76             }
 77             prev = p;
 78             p = p->next;
 79         }
 80     }
 81     
 82     public nothrow void MemFree(void* ptr)
 83     {
 84         Block* bp = cast<Block*>(ptr) - 1;
 85         Block* p;
 86         for (p = free; !(bp > p && bp < p->next); p = p->next;)
 87         {
 88             if (p >= p->next && (bp > p || bp < p->next))
 89             {
 90                 break;
 91             }
 92         }
 93         if (bp + bp->size == p->next)
 94         {
 95             bp->size = bp->size + p->next->size;
 96             bp->next = p->next->next;
 97         }
 98         else
 99         {
100             bp->next = p->next;
101         }
102         if (p + p->size == bp)
103         {
104             p->size = p->size + bp->size;
105             p->next = bp->next;
106         }
107         else
108         {
109             p->next = bp;
110         }
111         free = p;
112     }
113 }