diff --git a/src/h.h b/src/h.h index 81e4c75c..a056bd52 100644 --- a/src/h.h +++ b/src/h.h @@ -21,6 +21,7 @@ #define SFNS_FILLS true // whether to insert fills for structural functions (∾, ≍, etc) #define FAKE_RUNTIME false // whether to disable the self-hosted runtime #define MM 1 // memory manager; 0 - malloc (no GC); 1 - buddy; 2 - 2buddy +#define HEAP_MAX 1ULL<<48 // default heap max size // #define LOG_GC // log GC stats // #define FORMATTER // use self-hosted formatter for output diff --git a/src/load.c b/src/load.c index 76a062c4..7ac26b36 100644 --- a/src/load.c +++ b/src/load.c @@ -241,6 +241,7 @@ static B def_m2_d(B m, B f, B g) { thrM("cannot derive this"); } static B def_slice(B x, usz s) { thrM("cannot slice non-array!"); } static inline void base_init() { // very first init function + mm_heapMax = HEAP_MAX; for (i32 i = 0; i < t_COUNT; i++) { ti[i].free = def_free; ti[i].visit = def_visit; diff --git a/src/main.c b/src/main.c index c579040b..10aef29f 100644 --- a/src/main.c +++ b/src/main.c @@ -53,6 +53,7 @@ int main(int argc, char* argv[]) { "-e code: execute the argument as BQN\n" "-p code: execute the argument as BQN and print its result pretty-printed\n" "-o code: execute the argument as BQN and print its raw result\n" + "-M num : set maximum heap size to num megabytes\n" "-r : start the REPL after all further arguments\n" , argv[0]); exit(0); @@ -72,17 +73,29 @@ int main(int argc, char* argv[]) { break; } case 'p': { REQARG(p); - B r = bqn_exec(fromUTF8l(argv[i++]), m_str32(U"-e"), inc(bi_emptyHVec)); + B r = bqn_exec(fromUTF8l(argv[i++]), m_str32(U"-p"), inc(bi_emptyHVec)); print(r); dec(r); printf("\n"); break; } case 'o': { REQARG(o); - B r = bqn_exec(fromUTF8l(argv[i++]), m_str32(U"-e"), inc(bi_emptyHVec)); + B r = bqn_exec(fromUTF8l(argv[i++]), m_str32(U"-o"), inc(bi_emptyHVec)); printRaw(r); dec(r); printf("\n"); break; } + case 'M': { REQARG(M); + char* str = argv[i++]; + u64 am = 0; + while (*str) { + char c = *str++; + if (c<'0' | c>'9') { printf("%s: -M: Argument not a number\n", argv[0]); exit(1); } + if (am>1ULL<<48) { printf("%s: -M: Too large\n", argv[0]); exit(1); } + am = am*10 + c-48; + } + mm_heapMax = am*1024*1024; + break; + } case 'r': { startREPL = true; break; diff --git a/src/opt/mm_2buddy.c b/src/opt/mm_2buddy.c index 9567d5cc..4df7b7ee 100644 --- a/src/opt/mm_2buddy.c +++ b/src/opt/mm_2buddy.c @@ -4,6 +4,9 @@ u64 currObjCounter; #endif +u64 mm_heapAlloc; +u64 mm_heapMax; + EmptyValue* b1_buckets[64]; b1_AllocInfo* b1_al; u64 b1_alCap; diff --git a/src/opt/mm_2buddy.h b/src/opt/mm_2buddy.h index 90a6aed5..3789510b 100644 --- a/src/opt/mm_2buddy.h +++ b/src/opt/mm_2buddy.h @@ -5,6 +5,8 @@ struct EmptyValue { // needs set: mmInfo; type=t_empty; next; everything else ca struct Value; EmptyValue* next; }; +extern u64 mm_heapAlloc; +extern u64 mm_heapMax; #define BSZ(X) (1ull<<(X)) #define BSZI(X) ((u8)(64-__builtin_clzl((X)-1ull))) @@ -64,6 +66,3 @@ static u64 mm_size(Value* x) { if (m&64) return 3ull<<(x->mmInfo&63); else return 1ull<<(x->mmInfo&63); } -static u64 mm_heapAllocated() { - return b1_heapAllocated() + b3_heapAllocated(); -} diff --git a/src/opt/mm_buddy.c b/src/opt/mm_buddy.c index d31e493f..e8e4dbbe 100644 --- a/src/opt/mm_buddy.c +++ b/src/opt/mm_buddy.c @@ -4,6 +4,9 @@ u64 currObjCounter; #endif +u64 mm_heapAlloc; +u64 mm_heapMax; + EmptyValue* buckets[64]; mm_AllocInfo* mm_al; u64 mm_alCap; diff --git a/src/opt/mm_buddy.h b/src/opt/mm_buddy.h index 990b9afc..9feef38f 100644 --- a/src/opt/mm_buddy.h +++ b/src/opt/mm_buddy.h @@ -5,6 +5,8 @@ struct EmptyValue { // needs set: mmInfo; type=t_empty; next; everything else ca struct Value; EmptyValue* next; }; +extern u64 mm_heapAlloc; +extern u64 mm_heapMax; #define BSZ(X) (1ull<<(X)) #define BSZI(X) ((u8)(64-__builtin_clzl((X)-1ull))) diff --git a/src/opt/mm_buddyTemplate.h b/src/opt/mm_buddyTemplate.h index 6a43a03e..65c988bd 100644 --- a/src/opt/mm_buddyTemplate.h +++ b/src/opt/mm_buddyTemplate.h @@ -25,6 +25,8 @@ static NOINLINE EmptyValue* BN(makeEmpty)(u8 bucket) { // result->next is garbag } if (cb >= 20) { u64 sz = BSZ(cb); + if (mm_heapAlloc+sz >= mm_heapMax) { printf("Heap size limit reached\n"); exit(1); } + mm_heapAlloc+= sz; // gc_maybeGC(); c = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_NORESERVE|MAP_PRIVATE|MAP_ANON, -1, 0); if (alSize+1>=alCap) { @@ -32,10 +34,7 @@ static NOINLINE EmptyValue* BN(makeEmpty)(u8 bucket) { // result->next is garbag al = realloc(al, sizeof(AllocInfo)*alCap); } al[BN(alSize)++] = (AllocInfo){.p = (Value*)c, .sz = sz}; - if (c==MAP_FAILED) { - printf("failed to allocate memory\n"); - exit(1); - } + if (c==MAP_FAILED) { printf("Failed to allocate memory\n"); exit(1); } c->type = t_empty; c->mmInfo = cb; c->next = 0; @@ -98,11 +97,6 @@ static void BN(forHeap)(V2v f) { } } } -static u64 BN(heapAllocated)() { - u64 res = 0; - for (u64 i = 0; i < alSize; i++) res+= al[i].sz; - return res; -} #undef MMI #undef AllocInfo