summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MetaAlloc.odsbin31148 -> 31520 bytes
-rw-r--r--doc/0/A-meta_alloc.md5
-rw-r--r--src/zisp/gc/meta_alloc.zig39
3 files changed, 34 insertions, 10 deletions
diff --git a/MetaAlloc.ods b/MetaAlloc.ods
index dcc1c02..4da4cab 100644
--- a/MetaAlloc.ods
+++ b/MetaAlloc.ods
Binary files differ
diff --git a/doc/0/A-meta_alloc.md b/doc/0/A-meta_alloc.md
index 577f066..e339db7 100644
--- a/doc/0/A-meta_alloc.md
+++ b/doc/0/A-meta_alloc.md
@@ -210,12 +210,11 @@ values used by the implementation are as follows:
* Maximum count: 16 indexes
-* Smallest size class: 256 bytes
+* Smallest size class: 128 bytes
The extra index array starts after 64 bytes, and requires 64 bytes,
since it stores up to 16 32-bit integers; that's a total size of 128,
-which fits within 256, and means we could decrease the smallest size
-to 128 as well if deemed more appropriate.
+which fits exactly into the smallest size.
The 64-byte padding is to allow for efficient bulk memory transfer
using up to 512-bit SIMD instructions on modern processors.
diff --git a/src/zisp/gc/meta_alloc.zig b/src/zisp/gc/meta_alloc.zig
index 28494ee..e8502df 100644
--- a/src/zisp/gc/meta_alloc.zig
+++ b/src/zisp/gc/meta_alloc.zig
@@ -18,9 +18,13 @@
// that this means the slabs are limited to 16 GiB each (2^31 units because i32;
// 8 bytes each) for a 256 GiB total, since we have 16 size classes.
//
-// Using 8-byte units means free conversion to byte-based addresses thanks to
-// instructions like LEA or the ARM barrel shifter. Using size class sized
-// units would require additional shift instructions and seems unnecessary.
+// Using 8-byte units means that many (but not all) of the conversions to byte
+// based addresses are effectively free thanks to instructions like LEA or the
+// ARM barrel shifter. Using size class sized units would only require a few
+// more shift instructions here and there, but seems unnecessary.
+//
+// Downsizing units to one byte would shave off an instruction here and there,
+// and decrease vmem to 32 GiB (2 per slab), but that may be too restrictive.
//
// The global slab watermark of a size class is bumped in chunks, reserving a
// number of slots for the thread that performed the bump. This way, threads
@@ -204,7 +208,7 @@ export fn alloc(size: usize) [*]u8 {
}
}
-/// Free memory that was returned by alloc().
+/// Free memory of a specific size that was returned by alloc().
export fn free(size: usize, ptr: [*]u8) void {
const sci = getSizeClassIndex(size);
if (sci < SIZES.len) {
@@ -215,6 +219,27 @@ export fn free(size: usize, ptr: [*]u8) void {
}
}
+/// Free memory that was returned by alloc(), calculating the size class from
+/// the pointer address, which is only possible if it lies within one of the
+/// managed slabs. If this pointer came from a call to alloc() with a size
+/// greater than the largest size class, this function will panic.
+export fn free_auto(ptr: [*]u8) void {
+ const paddr = @intFromPtr(ptr);
+ const saddr = @intFromPtr(slabs);
+ if (paddr < saddr) {
+ @panic("Invalid pointer passed to free_auto().");
+ }
+
+ const uaddr = paddr - saddr;
+ const uidx = uaddr / @sizeOf(Unit);
+ const sci = uidx / SLAB_LEN;
+ if (sci >= SIZES.len) {
+ @panic("Invalid pointer passed to free_auto().");
+ }
+
+ free_size_class(@intCast(sci), @ptrCast(@alignCast(ptr)));
+}
+
fn alloc_size_class(sci: u8, size: usize) SlotPtr {
std.debug.assert(sci < SIZES.len);
@@ -260,10 +285,10 @@ fn alloc_from_fl(
if (fl_head.idx >= SLAB_LEN) return null;
ptr = slab[fl_head.idx..].ptr;
- arr = @ptrCast(ptr);
+ arr = @ptrCast(@alignCast(ptr));
// Load this atomically since it's still globally accessible memory;
- // unordered is fine since we discard it if the following CAS fails.
+ // unordered is fine since we discard it if the cmpxchg below fails.
const next_head = @atomicLoad(UnitIdx, &arr[0], .unordered);
fl_head = @cmpxchgWeak(
@@ -342,7 +367,7 @@ fn free_into_fl(
// Note: n = 0 is valid and must work.
std.debug.assert(n <= FSC_MAX / 2);
- const arr: [*]UnitIdx = @ptrCast(ptr);
+ const arr: [*]UnitIdx = @ptrCast(@alignCast(ptr));
const split = tl.fsc_count - n;
tl.fsc_count = split;