memory stuff
This commit is contained in:
parent
5f27b720ea
commit
d409969867
11 changed files with 257 additions and 126 deletions
|
|
@ -77,7 +77,7 @@ ArenaToAllocator :: (arena: *Arena) -> Allocator {
|
|||
return .{ proc = JaiAllocatorProc, data = arena };
|
||||
}
|
||||
|
||||
|
||||
/// PanicArena is an Arena that panics when used.
|
||||
PanicArena :: () -> Arena {
|
||||
return .{ proc = PanicArenaProc };
|
||||
}
|
||||
|
|
@ -119,12 +119,12 @@ PanicArenaProc :: (
|
|||
if event == {
|
||||
case .Acquire;
|
||||
if new_size > 0
|
||||
{ Panic("jc: cannot acquire memory using the PanicArena", loc = caller); }
|
||||
{ Panic("jc: PanicArena, acquiring memory is not allowed", loc = caller); }
|
||||
|
||||
case .Save;
|
||||
Panic("jc: cannot save using the PanicArean", loc = caller);
|
||||
Panic("jc: PanicArena, saving is not allowed", loc = caller);
|
||||
case .Restore;
|
||||
Panic("jc: cannot restore using the PanicArean", loc = caller);
|
||||
Panic("jc: PanicArena, restoring is not allowed", loc = caller);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
@ -143,7 +143,7 @@ BumpArenaProc :: (
|
|||
if event == {
|
||||
case .Setup;
|
||||
if bump.memory.data == null
|
||||
{ Panic("jc: BumpArena has no memory", loc = caller); }
|
||||
{ Panic("jc: BumpArena, no backing memory", loc = caller); }
|
||||
return arena_data;
|
||||
|
||||
case .Teardown;
|
||||
|
|
@ -157,7 +157,7 @@ BumpArenaProc :: (
|
|||
ptr := MemAlignForward(end, align);
|
||||
size := new_size + (ptr - end);
|
||||
if bump.offset + size > bump.memory.count
|
||||
{ Panic("jc: BumpArena out of memory", loc = caller); }
|
||||
{ Panic("jc: BumpArena, out of memory", loc = caller); }
|
||||
|
||||
bump.offset += size;
|
||||
return ptr;
|
||||
|
|
@ -169,7 +169,7 @@ BumpArenaProc :: (
|
|||
case .Restore;
|
||||
wm := old_ptr.(int);
|
||||
if wm < 0 || wm >= bump.memory.count
|
||||
{ Panic("jc: BumpArena restored invalid savepoint", loc = caller); }
|
||||
{ Panic("jc: BumpArena, restored invalid savepoint", loc = caller); }
|
||||
bump.offset = wm;
|
||||
}
|
||||
|
||||
|
|
@ -185,7 +185,128 @@ PagingArenaProc :: (
|
|||
|
||||
caller: Source_Code_Location
|
||||
) -> *void {
|
||||
Panic("not implemented for PagingArena", loc = caller);
|
||||
MaxPages :: 64;
|
||||
|
||||
PageArenaData :: struct {
|
||||
pages: [MaxPages]Page;
|
||||
count: int;
|
||||
in_use: int;
|
||||
|
||||
Page :: struct {
|
||||
base: *u8;
|
||||
offset: int;
|
||||
}
|
||||
}
|
||||
|
||||
// @note(judah): page 0 has a special offset because it stores the header
|
||||
Page0Offset :: #run AlignForward(size_of(PageArenaData), align_of(PageArenaData));
|
||||
|
||||
NewPage :: inline (previous_base: *void) -> PageArenaData.Page {
|
||||
p: PageArenaData.Page = ---;
|
||||
p.base = MemAcquirePage(.CommitImmediately);
|
||||
p.offset = 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
data := arena_data.(*PageArenaData);
|
||||
if event == {
|
||||
case .Setup;
|
||||
page := NewPage(null);
|
||||
data = page.base.(*PageArenaData);
|
||||
|
||||
page.offset = Page0Offset;
|
||||
data.pages[0] = page;
|
||||
|
||||
data.in_use = 1;
|
||||
data.count = 1;
|
||||
|
||||
return data;
|
||||
|
||||
case .Teardown;
|
||||
// @note(judah): release in reverse oreder so we don't release the memory
|
||||
// containing the header until we don't need it anymore.
|
||||
i := data.count - 1;
|
||||
while i >= 0 {
|
||||
page := data.pages[i];
|
||||
if page.base != null
|
||||
{ MemReleasePage(page.base, PageSize); }
|
||||
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
case .Acquire;
|
||||
Assert(data.count != 0, "jc: PageArena, no pages exist");
|
||||
|
||||
last := *data.pages[data.in_use - 1];
|
||||
end := last.base + last.offset;
|
||||
if new_size == 0
|
||||
{ return end; }
|
||||
|
||||
ptr := MemAlignForward(end, align);
|
||||
size := new_size + (ptr - end);
|
||||
|
||||
// create or reuse page
|
||||
if last.offset + size > PageSize {
|
||||
if data.in_use >= MaxPages
|
||||
{ Panic("jc: PageArena, max page count"); }
|
||||
|
||||
page: *PageArenaData.Page;
|
||||
if data.in_use < data.count {
|
||||
page = *data.pages[data.in_use];
|
||||
}
|
||||
else {
|
||||
p := NewPage(data.pages[data.count - 1].base);
|
||||
data.pages[data.count] = p;
|
||||
page = *data.pages[data.count];
|
||||
|
||||
data.count += 1;
|
||||
}
|
||||
|
||||
data.in_use += 1;
|
||||
|
||||
ptr = page.base;
|
||||
size = new_size;
|
||||
last = page;
|
||||
}
|
||||
|
||||
last.offset += size;
|
||||
return ptr;
|
||||
|
||||
case .Reset;
|
||||
for 0..data.count - 1 {
|
||||
page := *data.pages[it];
|
||||
|
||||
if it == 0 {
|
||||
page.offset = Page0Offset;
|
||||
}
|
||||
else {
|
||||
page.offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
data.in_use = 1;
|
||||
|
||||
case .Save;
|
||||
return data.in_use.(*void);
|
||||
|
||||
case .Restore;
|
||||
in_use_at_save := old_ptr.(int);
|
||||
|
||||
// @note(judah): We need to restore from the savepoint to count
|
||||
// because we could've created more pages inbetween save/restore
|
||||
for in_use_at_save..data.count - 1 {
|
||||
p := *data.pages[it];
|
||||
if it == 0 {
|
||||
p.offset = Page0Offset;
|
||||
}
|
||||
else {
|
||||
p.offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
data.in_use = in_use_at_save;
|
||||
}
|
||||
|
||||
return null;
|
||||
} @jc.nodocs
|
||||
|
||||
|
|
|
|||
|
|
@ -6,9 +6,8 @@
|
|||
ArrayAppend :: inline (arr: *[..]$T, values: ..T) -> *T {
|
||||
TrySetAllocator(arr,, allocator = ArenaToAllocator(*context.arena));
|
||||
|
||||
if values.count == 0 {
|
||||
return basic.array_add(arr);
|
||||
}
|
||||
if values.count == 0
|
||||
{ return basic.array_add(arr); }
|
||||
|
||||
count := arr.count;
|
||||
basic.array_add(arr, ..values);
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ WriteStderrNumber :: #bake_arguments write_number(to_standard_error = true); //
|
|||
|
||||
#scope_file
|
||||
|
||||
// @todo(judah): this probably needs to be exposed...
|
||||
DebugBuild :: #run -> bool {
|
||||
// @note(judah): there's not really a good way to detect opt level/build type,
|
||||
// so just check if debug info is being emitted.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
Kilobyte :: 1024;
|
||||
Megabyte :: 1024 * Kilobyte;
|
||||
Gigabyte :: 1024 * Megabyte;
|
||||
Terabyte :: 1024 * Gigabyte;
|
||||
|
||||
DefaultAlign :: size_of(*void);
|
||||
|
||||
|
|
@ -106,6 +107,63 @@ NextPowerOfTwo :: (x: int) -> int #no_aoc {
|
|||
return x + 1;
|
||||
}
|
||||
|
||||
MemAcquirePageFlags :: enum_flags {
|
||||
CommitImmediately;
|
||||
}
|
||||
|
||||
MemAcquirePage :: (flags: MemAcquirePageFlags = 0, previous: *void = null) -> *void {
|
||||
BaseAddress :: 1 * Terabyte;
|
||||
|
||||
#if OS == .MACOS {
|
||||
addr: darwin.mach_vm_address_t = BaseAddress;
|
||||
if previous != null {
|
||||
addr = previous.(darwin.mach_vm_address_t) + PageSize;
|
||||
}
|
||||
|
||||
res := darwin.mach_vm_allocate(darwin.mach_task_self(), *addr, PageSize, darwin.VM_FLAGS_ANYWHERE);
|
||||
if res != 0
|
||||
{ Panic("jc: MemAcquirePage, failed to request page"); }
|
||||
|
||||
ptr := addr.(*void);
|
||||
if flags & .CommitImmediately
|
||||
{ MemZero(ptr, PageSize); }
|
||||
|
||||
return ptr;
|
||||
}
|
||||
else {
|
||||
Panic("todo: MemAcquirePage not implemented on this OS");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
MemReleasePage :: (page: *void, size: int) {
|
||||
#if OS == .MACOS {
|
||||
res := darwin.mach_vm_deallocate(darwin.mach_task_self(), page.(darwin.mach_vm_address_t), size.(darwin.mach_vm_size_t));
|
||||
if res != 0
|
||||
{ Panic("jc: MemReleasePage failed to deallocate page"); }
|
||||
}
|
||||
else {
|
||||
Panic("todo: MemReleasePage not implemented on this OS");
|
||||
}
|
||||
}
|
||||
|
||||
PageSize :: #run -> uint {
|
||||
#if OS == .MACOS {
|
||||
page_size: darwin.mach_vm_size_t;
|
||||
res := darwin.host_page_size(darwin.host_self(), *page_size);
|
||||
if res != 0
|
||||
{ CompileError("failed to get host page size"); }
|
||||
|
||||
return page_size.(uint);
|
||||
}
|
||||
else {
|
||||
CompileError("todo: PageSize not implemented on OS");
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
#scope_module
|
||||
|
||||
|
|
@ -133,3 +191,11 @@ TrySetAllocator :: (array: *[..]$T) #expand {
|
|||
array.allocator = context.allocator;
|
||||
}
|
||||
} @jc.nodocs
|
||||
|
||||
|
||||
#scope_file
|
||||
|
||||
#if OS == {
|
||||
case .MACOS;
|
||||
darwin :: #import "jc/ext/darwin";
|
||||
}
|
||||
|
|
|
|||
14
PLAN.Judah
14
PLAN.Judah
|
|
@ -9,6 +9,19 @@ This is what I'm doing day-to-day.
|
|||
: notes, todos, etc.
|
||||
|
||||
|
||||
/ 09.08.25
|
||||
|
||||
+ implemented PagingArena on mac
|
||||
+ implemented MemAcquirePage/MemReleasePage/PageSize on mac
|
||||
+ panics have more information now
|
||||
+ added Terabyte constant
|
||||
+ deleted old ext/darwin
|
||||
|
||||
: u32, s64 -> uint4, sint8?
|
||||
: ext/darwin needs to just bind frameworks
|
||||
: ext/darwin needs easy objc interop
|
||||
|
||||
|
||||
/ 09.07.25
|
||||
|
||||
+ replaced allocators with custom arenas
|
||||
|
|
@ -17,6 +30,7 @@ This is what I'm doing day-to-day.
|
|||
+ fixed +internal's weird behavior in the test runner
|
||||
+ ArrayAppend/ArrayGrow now wrap the current arena as the attached Allocator
|
||||
+ ArenaMode -> ArenaEvent
|
||||
+ added pointer alignment procs
|
||||
|
||||
/ 09.06.25
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
NSObject :: struct {};
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
NSString :: struct {
|
||||
// #as super: NSObject;
|
||||
}
|
||||
|
||||
init :: (path: ) -> NSString {
|
||||
}
|
||||
|
||||
|
||||
sel: struct {
|
||||
init_withBytes_length_encoding: objc.Sel;
|
||||
init_contentsOfFile_encoding: objc.Sel;
|
||||
UTF8String: objc.Sel;
|
||||
};
|
||||
|
||||
init_everything :: () {
|
||||
sel.init_withBytes_length_encoding = objc.sel_register_name("init:withBytes:length:encoding");
|
||||
sel.init_contentsOfFile_encoding = objc.sel_register_name("init:contentsOfFile:encoding");
|
||||
sel.UTF8String = objc.sel_register_name("UTF8String");
|
||||
}
|
||||
|
||||
// #import "jc/meta/init"(init_everything);
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
NSObject :: struct {
|
||||
id: u64;
|
||||
}
|
||||
|
||||
NSString :: struct {
|
||||
#as using isa: NSObject;
|
||||
}
|
||||
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
|
||||
NSNumber :: struct {
|
||||
// #as using isa: NSObject;
|
||||
}
|
||||
|
||||
#scope_file;
|
||||
|
||||
Sel :: uptr;
|
||||
|
||||
sel: struct {
|
||||
boolValue: Sel; @boolValue
|
||||
intValue: Sel; @intValue
|
||||
unsignedIntValue: Sel; @unsignedIntValue
|
||||
floatValue: Sel; @floatValue
|
||||
doubleValue: Sel; @doubleValue
|
||||
}
|
||||
|
||||
#add_context InitFoundation :: () {
|
||||
#import "Basic";
|
||||
|
||||
tmp: [512]u8;
|
||||
|
||||
base := (*sel).(*u8);
|
||||
info := type_info(type_of(sel));
|
||||
for info.members if it.notes.count != 0 {
|
||||
name := it.notes[0];
|
||||
memcpy(tmp.data, name.data, name.count);
|
||||
tmp.data[name.count] = 0;
|
||||
|
||||
ptr := base + it.offset_in_bytes;
|
||||
ptr.* = sel_register_name(tmp.data);
|
||||
assert(ptr.* != 0, "failed to register selector: %", name);
|
||||
}
|
||||
|
||||
print("%\n", info.*);
|
||||
}
|
||||
|
||||
Foundation :: #library,system,no_dll,link_always "Foundation";
|
||||
44
ext/darwin/kernel.jai
Normal file
44
ext/darwin/kernel.jai
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
kern_return_t :: s32;
|
||||
|
||||
natural_t :: u32;
|
||||
boolean_t :: s32;
|
||||
|
||||
vm_prot_t :: s32;
|
||||
vm_map_t :: mach_port_t;
|
||||
|
||||
mach_port_t :: natural_t;
|
||||
mach_vm_address_t :: u64;
|
||||
mach_vm_size_t :: u64;
|
||||
|
||||
host_t :: *void;
|
||||
|
||||
VM_FLAGS_FIXED :: 0x0000;
|
||||
VM_FLAGS_ANYWHERE :: 0x0001;
|
||||
VM_FLAGS_PURGABLE :: 0x0002;
|
||||
VM_FLAGS_4GB_CHUNK :: 0x0004;
|
||||
VM_FLAGS_RANDOM_ADDR :: 0x0008;
|
||||
VM_FLAGS_NO_CACHE :: 0x0010;
|
||||
VM_FLAGS_RESILIENT_CODESIGN :: 0x0020;
|
||||
VM_FLAGS_RESILIENT_MEDIA :: 0x0040;
|
||||
VM_FLAGS_OVERWRITE :: 0x4000;
|
||||
|
||||
VM_PROT_READ :: 0x1;
|
||||
VM_PROT_WRITE :: 0x2;
|
||||
VM_PROT_EXECUTE :: 0x4;
|
||||
|
||||
|
||||
host_self :: () -> host_t #foreign Kernel;
|
||||
|
||||
host_page_size :: (host: host_t, page_size: *mach_vm_size_t) -> kern_return_t #foreign Kernel;
|
||||
|
||||
mach_task_self :: () -> mach_port_t #foreign Kernel;
|
||||
|
||||
mach_vm_allocate :: (target: vm_map_t, address: *mach_vm_address_t, size:mach_vm_size_t , flags: s32) -> kern_return_t #foreign Kernel;
|
||||
|
||||
mach_vm_deallocate :: (target: vm_map_t, address: mach_vm_address_t, size:mach_vm_size_t) -> kern_return_t #foreign Kernel;
|
||||
|
||||
mach_vm_protect :: (target_task: vm_map_t, address: mach_vm_address_t, size: mach_vm_size_t, set_maximum: boolean_t, new_protection: vm_prot_t) -> kern_return_t #foreign Kernel;
|
||||
|
||||
#scope_module
|
||||
|
||||
Kernel :: #library,system "libc";
|
||||
|
|
@ -1,47 +1 @@
|
|||
#scope_export;
|
||||
|
||||
UInt :: u64;
|
||||
|
||||
Id :: *object;
|
||||
Class :: *class;
|
||||
Sel :: *selector;
|
||||
|
||||
Bool :: u8;
|
||||
|
||||
True : Bool : 1;
|
||||
False : Bool : 0;
|
||||
|
||||
msg_send :: () #foreign objc "objc_msgSend";
|
||||
msg_send_super :: () #foreign objc "objc_msgSend_super";
|
||||
msg_send_fpret :: () #foreign objc "objc_msgSend_fpret";
|
||||
msg_send_stret :: () #foreign objc "objc_msgSend_stret";
|
||||
|
||||
get_class :: (name: *u8) -> Class #foreign objc "objc_getClass";
|
||||
|
||||
sel_get_name :: (sel: Sel) -> *u8 #foreign objc "sel_getName";
|
||||
sel_register_name :: (str: *u8) -> Sel #foreign objc "sel_registerName";
|
||||
sel_get_uid :: (str: *u8) -> Sel #foreign objc "sel_getUid";
|
||||
|
||||
obj_get_class :: (obj: Id) -> Class #foreign objc "object_getClass";
|
||||
obj_set_class :: (obj: Id, cls: Class) -> Class #foreign objc "object_setClass";
|
||||
obj_is_class :: (obj: Id) -> Bool #foreign objc "object_isClass";
|
||||
obj_get_class_name :: (obj: Id) -> *u8 #foreign objc "object_getClassName";
|
||||
obj_copy :: (obj: Id, size: u64) -> Id #foreign objc "object_copy";
|
||||
obj_dispose :: (obj: Id) -> Id #foreign objc "object_dispose";
|
||||
|
||||
class_get_name :: (cls: Class) -> *u8 #foreign objc "class_getName";
|
||||
class_get_super :: (cls: Class) -> Class #foreign objc "class_getSuperclass";
|
||||
|
||||
#scope_module;
|
||||
|
||||
class :: struct {};
|
||||
object :: struct {};
|
||||
method :: struct {};
|
||||
ivar :: struct {};
|
||||
category :: struct {};
|
||||
protocol :: struct {};
|
||||
selector :: struct {};
|
||||
|
||||
objc :: #library,system,link_always,no_dll "libobjc";
|
||||
|
||||
#import "jc";
|
||||
#load "kernel.jai";
|
||||
|
|
|
|||
Loading…
Reference in a new issue