diff --git a/src/boot/boot.janet b/src/boot/boot.janet index 58c46cb5..cbbf06e4 100644 --- a/src/boot/boot.janet +++ b/src/boot/boot.janet @@ -390,6 +390,16 @@ ,;body (set ,i (,delta ,i ,step)))))) +(defn- for-var-template + [i start stop step comparison delta body] + (with-syms [s] + ~(do + (var ,i ,start) + (def ,s ,stop) + (while (,comparison ,i ,s) + ,;body + (set ,i (,delta ,i ,step)))))) + (defn- check-indexed [x] (if (indexed? x) x @@ -484,6 +494,12 @@ :generate (loop-fiber-template binding object [rest]) (error (string "unexpected loop verb " verb))))) +(defmacro forv + "Do a c style for loop for side effects. The iteration variable i + can be mutated in the loop, unlike normal for. Returns nil." + [i start stop & body] + (for-var-template i start stop 1 < + body)) + (defmacro for "Do a c style for loop for side effects. Returns nil." [i start stop & body] @@ -556,6 +572,7 @@ (put _env 'loop1 nil) (put _env 'check-indexed nil) (put _env 'for-template nil) +(put _env 'for-var-template nil) (put _env 'iterate-template nil) (put _env 'each-template nil) (put _env 'keys-template nil) diff --git a/src/core/gc.c b/src/core/gc.c index 36752b06..e534d9ed 100644 --- a/src/core/gc.c +++ b/src/core/gc.c @@ -39,6 +39,7 @@ struct JanetScratch { JANET_THREAD_LOCAL void *janet_vm_blocks; JANET_THREAD_LOCAL size_t janet_vm_gc_interval; JANET_THREAD_LOCAL size_t janet_vm_next_collection; +JANET_THREAD_LOCAL size_t janet_vm_block_count; JANET_THREAD_LOCAL int janet_vm_gc_suspend = 0; /* Roots */ @@ -327,6 +328,7 @@ void janet_sweep() { previous = current; current->flags &= ~JANET_MEM_REACHABLE; } else { + janet_vm_block_count--; janet_deinit_block(current); if (NULL != previous) { previous->next = next; @@ -359,6 +361,7 @@ void *janet_gcalloc(enum JanetMemoryType type, size_t size) { janet_vm_next_collection += size; mem->next = janet_vm_blocks; janet_vm_blocks = mem; + janet_vm_block_count++; return (void *)mem; } @@ -388,6 +391,14 @@ void janet_collect(void) { uint32_t i; if (janet_vm_gc_suspend) return; depth = JANET_RECURSION_GUARD; + /* Try and prevent many major collections back to back. + * A full collection will take O(janet_vm_block_count) time. + * If we have a large heap, make sure our interval is not too + * small so we won't make many collections over it. This is just a + * heuristic for automatically changing the gc interval */ + if (janet_vm_block_count * 8 > janet_vm_gc_interval) { + janet_vm_gc_interval = janet_vm_block_count * sizeof(JanetGCObject); + } orig_rootcount = janet_vm_root_count; #ifdef JANET_NET janet_net_markloop(); diff --git a/src/core/state.h b/src/core/state.h index 7ead6368..c36f1c63 100644 --- a/src/core/state.h +++ b/src/core/state.h @@ -71,6 +71,7 @@ extern JANET_THREAD_LOCAL uint32_t janet_vm_cache_deleted; extern JANET_THREAD_LOCAL void *janet_vm_blocks; extern JANET_THREAD_LOCAL size_t janet_vm_gc_interval; extern JANET_THREAD_LOCAL size_t janet_vm_next_collection; +extern JANET_THREAD_LOCAL size_t janet_vm_block_count; extern JANET_THREAD_LOCAL int janet_vm_gc_suspend; /* GC roots */ diff --git a/src/core/vm.c b/src/core/vm.c index 6e7a0c3d..f65cfa50 100644 --- a/src/core/vm.c +++ b/src/core/vm.c @@ -1395,11 +1395,8 @@ int janet_init(void) { /* Garbage collection */ janet_vm_blocks = NULL; janet_vm_next_collection = 0; - /* Setting memoryInterval to zero forces - * a collection pretty much every cycle, which is - * incredibly horrible for performance, but can help ensure - * there are no memory bugs during development */ janet_vm_gc_interval = 0x400000; + janet_vm_block_count = 0; janet_symcache_init(); /* Initialize gc roots */ janet_vm_roots = NULL;