diff --git a/rt/aso.fn b/rt/aso.fn index d470266..db8a579 100644 --- a/rt/aso.fn +++ b/rt/aso.fn @@ -6,7 +6,7 @@ module rt.aso; * Open addressing, with tuple key value bucket array, * a void string means no key and thus no value may exist there. * - * Will prod 5 times until deciding that a key doesn't exist or there is no space, + * Will probe 5 times until deciding that a key doesn't exist or there is no space, * will resize to double the current bucket size if there is no space available. */ public struct AsoArray(K, V) @@ -54,8 +54,8 @@ public struct AsoArray(K, V) nuint head; while (buckets[index][0] != key) { - if (head++ > 5) - rehash(buffer.length * 2); + if (++head > 5) + rehash(buckets.length * 2); index = index.__hash(); } return = buckets[index][1]; @@ -67,8 +67,8 @@ public struct AsoArray(K, V) nuint head; while (buckets[index][0] != key) { - if (head++ > 5) - rehash(buffer.length * 2); + if (++head > 5) + rehash(buckets.length * 2); index = index.__hash(); } buckets[index] = [key, val]; @@ -79,7 +79,7 @@ public struct AsoArray(K, V) if (op == "in") { nuint index = key.__hash() % buckets.length; - foreach (i; 0..6) + foreach (i; 0..5) { if (buckets[index][0] == key) return => true; @@ -89,17 +89,15 @@ public struct AsoArray(K, V) } } -nuint __hash(uint SEED, T)(const T val) +nuint __hash(T)(const T val) { ubyte[nuint->size] buffer; ubyte* ptr = &val |> ubyte*; - foreach (i; 0..buffer.length) + foreach (i; 0..nuint->size) + foreach (j; 0..val->size) { - foreach (j; 0..val->size) - { - buffer[i] ^= buffer[j] += ptr[j] ^ SEED; - buffer[(j + i) % 8] += buffer[i] ^= ptr[i] ^ SEED; - } + buffer[i] ^= buffer[j] += ptr[j]; + buffer[(j + i) % nuint->size] += buffer[i] ^= ptr[i]; } return = buffer |> nuint; } \ No newline at end of file diff --git a/rt/gc.fn b/rt/gc.fn index 22cc824..1dfda81 100644 --- a/rt/gc.fn +++ b/rt/gc.fn @@ -1 +1,113 @@ -module rt.gc; \ No newline at end of file +module rt.gc; + +import rt.sys; + +private struct Object +{ + void* ptr; + nuint size; + Object* prev; + atomic bool free; + // byte[size] data follows this. +} + +public struct Root +{ + // TODO: Definitely need some atomics here. + void* base; + void* tail; + nuint size; + nuint free; +} + +/** + * The Fern garbage collector and allocator. + * + * Stores a root of the current allocation and a tree of all allocated objects. + * The tree is stored in reverse with bytes directly following the object struct with allocation info. + */ +public struct GC +{ + // 4MB per sector page. + alias pageSize = 1024 * 1024 * 4; + + // This will store a count of all living, GC-owned objects. + atomic uint living; + // Only one root exists at a time but many root allocations may have happened, + // we simply don't care about those previous allocations and keep track of all of the + // objects that were allocated in them instead. + // + // An object should NEVER be completely freed or have its prev pointer invalidated, + // as this would lead to potentially all memory being leaked. + Root root; + Object* tail; + + void bump(Object* obj) + { + obj.prev = tail; + tail = obj; + } + + void create(size_t size = pageSize) + { + // TODO: Not cross platform! + void* ptr = __syscall!(void*)(mmap, void, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + root.base = ptr; + root.size = size; + } + + // TODO: Alignment + void* alloc(nuint size) trusted; + { + // A freed object is available for allocation. + while (true) + { + Object* obj; + if (obj.free && obj.size >= size) + { + obj.free = false; + bump(obj); + return => obj.ptr; + } + obj = tail.prev; + } + + // The root currently has enough space to allocate anew. + if (root.free >= size) + { + Object* ptr = root.tail |> Object*; + return = ptr + 1; + + *ptr = Object(return, size); + bump(ptr); + + root.free -= size; + root.tail = return + size; + } + + // The root neither has space nor available objects but is not completely full, + // by doing this allocation we avoid potentially leaking a stupidly large amount of memory, + // or at least preserve bytes that might end up being useful later. + if (root.free != 0) + { + Object* ptr = root.tail |> Object*; + *ptr = Object(ptr, root.free); + bump(ptr); + } + + // The root neither has space nor available objects, we need to allocate a new root. + if (size > pageSize) + create(size); + else + create(); + + Object* ptr = root.base |> Object*; + return = ptr + 1; + + *ptr = Object(return, size); + bump(ptr); + + root.free -= size; + root.tail = return + size; + } +} \ No newline at end of file diff --git a/rt/sys.fn b/rt/sys.fn index c0feabf..c7e1389 100644 --- a/rt/sys.fn +++ b/rt/sys.fn @@ -341,10 +341,59 @@ public const tagged SCID pkey_mprotect2; } -void __syscall(ARGS...)(SCID id, ARGS args) trusted; +public: +alias PMUTEX_INIT = 0; +alias PMUTEX_LOCK = 1; +alias PMUTEX_UNLOCK = 2; +alias PMUTEX_DESTROY = 3; + +alias MAP_SHARED = 0x01; +alias MAP_PRIVATE = 0x02; +alias MAP_SHARED_VALIDATE = 0x03; +alias MAP_TYPE = 0x0f; +alias MAP_FIXED = 0x10; +alias MAP_ANONYMOUS = 0x20; +alias MAP_NORESERVE = 0x4000; +alias MAP_GROWSDOWN = 0x0100; +alias MAP_DENYWRITE = 0x0800; +alias MAP_EXECUTABLE = 0x1000; +alias MAP_LOCKED = 0x2000; +alias MAP_POPULATE = 0x8000; +alias MAP_NONBLOCK = 0x10000; +alias MAP_STACK = 0x20000; +alias MAP_HUGETLB = 0x40000; +alias MAP_SYNC = 0x80000; +alias MAP_FIXED_NOREPLACE = 0x100000; +alias MAP_FILE = 0; +alias MAP_UNINITIALIZED = 0x4000000; + +alias MAP_HUGE_SHIFT = 26 +alias MAP_HUGE_MASK = 0x3f +alias MAP_HUGE_16KB = (14 << 26) +alias MAP_HUGE_64KB = (16 << 26) +alias MAP_HUGE_512KB = (19 << 26) +alias MAP_HUGE_1MB = (20 << 26) +alias MAP_HUGE_2MB = (21 << 26) +alias MAP_HUGE_8MB = (23 << 26) +alias MAP_HUGE_16MB = (24 << 26) +alias MAP_HUGE_32MB = (25 << 26) +alias MAP_HUGE_256MB = (28 << 26) +alias MAP_HUGE_512MB = (29 << 26) +alias MAP_HUGE_1GB = (30 << 26) +alias MAP_HUGE_2GB = (31 << 26) +alias MAP_HUGE_16GB = (34U << 26) + +alias PROT_NONE = 0; +alias PROT_READ = 1; +alias PROT_WRITE = 2; +alias PROT_EXEC = 4; +alias PROT_GROWSDOWN = 0x01000000; +alias PROT_GROWSUP = 0x02000000; + +R __syscall(R = void, ARGS...)(SCID id, ARGS args) trusted; { __asm( - syscall(none, id, unroll args); + syscall(return, id, unroll args) ); return; } \ No newline at end of file