diff --git a/runtime/Makefile b/runtime/Makefile index 208355bc3..ebb090608 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -6,21 +6,21 @@ UNIT_TESTS_FLAGS=$(TEST_FLAGS) INVARIANTS_CHECK_FLAGS=$(TEST_FLAGS) -DFULL_INVARIANT_CHECKS # this target is the most important one, its' artefacts should be used as a runtime of Lama -all: gc_runtime.o gc.o runtime.o - ar rc runtime.a gc_runtime.o runtime.o gc.o +all: gc.o runtime.o + ar rc runtime.a runtime.o gc.o # this is a target that runs unit tests, scenarios are written in a single file `test_main.c` -unit_tests.o: gc.c gc.h gc_runtime.s runtime.c runtime.h runtime_common.h virt_stack.c virt_stack.h test_main.c test_util.s - $(CC) -o unit_tests.o $(UNIT_TESTS_FLAGS) gc.c gc_runtime.s virt_stack.c runtime.c test_main.c test_util.s +unit_tests.o: gc.c gc.h runtime.c runtime.h runtime_common.h virt_stack.c virt_stack.h test_main.c test_util.s + $(CC) -o unit_tests.o $(UNIT_TESTS_FLAGS) gc.c virt_stack.c runtime.c test_main.c test_util.s # this target also runs unit tests but with additional expensive checks of GC invariants which aren't used in production version -invariants_check.o: gc.c gc.h gc_runtime.s runtime.c runtime.h runtime_common.h virt_stack.c virt_stack.h test_main.c test_util.s - $(CC) -o invariants_check.o $(INVARIANTS_CHECK_FLAGS) gc.c gc_runtime.s virt_stack.c runtime.c test_main.c test_util.s +invariants_check.o: gc.c gc.h runtime.c runtime.h runtime_common.h virt_stack.c virt_stack.h test_main.c test_util.s + $(CC) -o invariants_check.o $(INVARIANTS_CHECK_FLAGS) gc.c virt_stack.c runtime.c test_main.c test_util.s # this target also runs unit tests but with additional expensive checks of GC invariants which aren't used in production version # additionally, it prints debug information -invariants_check_debug_print.o: gc.c gc.h gc_runtime.s runtime.c runtime.h runtime_common.h virt_stack.c virt_stack.h test_main.c test_util.s - $(CC) -o invariants_check_debug_print.o $(INVARIANTS_CHECK_FLAGS) -DDEBUG_PRINT gc.c gc_runtime.s virt_stack.c runtime.c test_main.c test_util.s +invariants_check_debug_print.o: gc.c gc.h runtime.c runtime.h runtime_common.h virt_stack.c virt_stack.h test_main.c test_util.s + $(CC) -o invariants_check_debug_print.o $(INVARIANTS_CHECK_FLAGS) -DDEBUG_PRINT gc.c virt_stack.c runtime.c test_main.c test_util.s virt_stack.o: virt_stack.h virt_stack.c $(CC) $(PROD_FLAGS) -c virt_stack.c @@ -28,9 +28,6 @@ virt_stack.o: virt_stack.h virt_stack.c gc.o: gc.c gc.h $(CC) -rdynamic $(PROD_FLAGS) -c gc.c -gc_runtime.o: gc_runtime.s - $(CC) $(PROD_FLAGS) -c gc_runtime.s - runtime.o: runtime.c runtime.h $(CC) $(PROD_FLAGS) -c runtime.c diff --git a/runtime/gc.c b/runtime/gc.c index 4c6c2fd63..829a82077 100644 --- a/runtime/gc.c +++ b/runtime/gc.c @@ -22,7 +22,7 @@ size_t cur_id = 0; static extra_roots_pool extra_roots; -extern size_t __gc_stack_top, __gc_stack_bottom; +size_t __gc_stack_top = 0, __gc_stack_bottom = 0; #ifdef LAMA_ENV extern const size_t __start_custom_data, __stop_custom_data; #endif @@ -38,8 +38,8 @@ void dump_heap (); #endif void handler (int sig) { - void *array[10]; - size_t size; + void *array[10]; + int size; // get void*'s for all entries on the stack size = backtrace(array, 10); @@ -59,9 +59,8 @@ void *alloc (size_t size) { #endif void *p = gc_alloc_on_existing_heap(size); if (!p) { - // not enough place in heap, need to perform GC cycle + // not enough place in the heap, need to perform GC cycle p = gc_alloc(size); - // return gc_alloc(size); } return p; } @@ -223,17 +222,23 @@ void *gc_alloc (size_t size) { return gc_alloc_on_existing_heap(size); } +static void gc_root_scan_stack () { + for (size_t *p = (size_t *)(__gc_stack_top + 4); p < (size_t *)__gc_stack_bottom; ++p) { + gc_test_and_mark_root((size_t **)p); + } +} + void mark_phase (void) { #if defined(DEBUG_VERSION) && defined(DEBUG_PRINT) fprintf(stderr, "marking has started\n"); fprintf(stderr, - "__gc_root_scan_stack has started: gc_top=%p bot=%p\n", + "gc_root_scan_stack has started: gc_top=%p bot=%p\n", (void *)__gc_stack_top, (void *)__gc_stack_bottom); #endif - __gc_root_scan_stack(); + gc_root_scan_stack(); #if defined(DEBUG_VERSION) && defined(DEBUG_PRINT) - fprintf(stderr, "__gc_root_scan_stack has finished\n"); + fprintf(stderr, "gc_root_scan_stack has finished\n"); fprintf(stderr, "scan_extra_roots has started\n"); #endif scan_extra_roots(); @@ -554,7 +559,12 @@ extern void gc_test_and_mark_root (size_t **root) { mark((void *)*root); } -extern void __init (void) { +void __gc_init (void) { + __gc_stack_bottom = (size_t)__builtin_frame_address(1) + 4; + __init(); +} + +void __init (void) { signal(SIGSEGV, handler); size_t space_size = INIT_HEAP_SIZE * sizeof(size_t); diff --git a/runtime/gc.h b/runtime/gc.h index 8dd5e2e98..0343f2152 100644 --- a/runtime/gc.h +++ b/runtime/gc.h @@ -58,8 +58,6 @@ void *gc_alloc_on_existing_heap(size_t); // specific for mark-and-compact_phase gc void mark (void *obj); void mark_phase (void); -// written in ASM, scans stack for pointers to the heap and starts marking process -extern void __gc_root_scan_stack (void); // marks each pointer from extra roots void scan_extra_roots (void); #ifdef LAMA_ENV @@ -100,24 +98,16 @@ void pop_extra_root (void **p); // ============================================================================ // MANDATORY TO CALL BEFORE ANY INTERACTION WITH GC (apart from cases where we // are working with virtual stack as happens in tests) -extern void __gc_init (void); +void __gc_init (void); // should be called before interaction with GC in case of using in tests with // virtual stack, otherwise it is automatically invoked by `__gc_init` -extern void __init (void); +void __init (void); // mostly useful for tests but basically you want to call this in case you want // to deallocate all object allocated via GC extern void __shutdown (void); -// Next two functions sets and unsets `__gc_stack_top` -// The first (`__pre_gc`) should be called in the very beginning of any runtime -// function during the execution of which garbage collection can be initiated. -// The last one is a `companion function` which has to be called at the very -// end of any function that previously called `__pre_gc` -extern void __pre_gc (void); -extern void __post_gc (void); - // ============================================================================ // invoked from GASM: see gc_runtime.s diff --git a/runtime/gc_runtime.s b/runtime/gc_runtime.s deleted file mode 100644 index 2186b013d..000000000 --- a/runtime/gc_runtime.s +++ /dev/null @@ -1,113 +0,0 @@ - .data -__gc_stack_bottom: .long 0 -__gc_stack_top: .long 0 - - .globl __pre_gc - .globl __post_gc - .globl __gc_init - .globl __gc_root_scan_stack - .globl __gc_stack_top - .globl __gc_stack_bottom - .extern __init - .extern gc_test_and_mark_root - - .text - -__gc_init: - movl %ebp, __gc_stack_bottom - addl $4, __gc_stack_bottom - call __init - ret - - // if __gc_stack_top is equal to 0 - // then set __gc_stack_top to %ebp - // else return -__pre_gc: - pushl %eax - movl __gc_stack_top, %eax - cmpl $0, %eax - jne __pre_gc_2 - movl %ebp, %eax - // addl $8, %eax - movl %eax, __gc_stack_top -__pre_gc_2: - popl %eax - ret - - // if __gc_stack_top has been set by the caller - // (i.e. it is equal to its %ebp) - // then set __gc_stack_top to 0 - // else return -__post_gc: - pushl %eax - movl __gc_stack_top, %eax - cmpl %eax, %ebp - jnz __post_gc2 - movl $0, __gc_stack_top -__post_gc2: - popl %eax - ret - - // Scan stack for roots - // strting from __gc_stack_top - // till __gc_stack_bottom -__gc_root_scan_stack: - pushl %ebp - movl %esp, %ebp - pushl %ebx - pushl %edx - movl __gc_stack_top, %eax - jmp next - -loop: - movl (%eax), %ebx - - // check that it is not a pointer to code section - // i.e. the following is not true: - // __executable_start <= (%eax) <= __etext -check11: - leal __executable_start, %edx - cmpl %ebx, %edx - jna check12 - jmp check21 - -check12: - leal __etext, %edx - cmpl %ebx, %edx - jnb next - - // check that it is not a pointer into the program stack - // i.e. the following is not true: - // __gc_stack_bottom <= (%eax) <= __gc_stack_top -check21: - cmpl %ebx, __gc_stack_top - jna check22 - jmp loop2 - -check22: - cmpl %ebx, __gc_stack_bottom - jnb next - - // check if it a valid pointer - // i.e. the lastest bit is set to zero -loop2: - andl $0x00000001, %ebx - jnz next -gc_run_t: - pushl %eax - pushl %eax - call gc_test_and_mark_root - addl $4, %esp - popl %eax - -next: - addl $4, %eax - cmpl %eax, __gc_stack_bottom - jne loop -returnn: - movl $0, %eax - popl %edx - popl %ebx - movl %ebp, %esp - popl %ebp - ret diff --git a/runtime/runtime.c b/runtime/runtime.c index 26160b86c..ef4e30936 100644 --- a/runtime/runtime.c +++ b/runtime/runtime.c @@ -30,23 +30,18 @@ void __post_gc_subst () { } #endif /* end */ +extern size_t __gc_stack_top, __gc_stack_bottom; + #define PRE_GC() \ - bool flag = true; \ - if (__gc_stack_top == 0) { flag = false; } \ - __pre_gc(); \ + bool flag = false; \ + flag = __gc_stack_top == 0; \ + if (flag) { __gc_stack_top = (size_t)__builtin_frame_address(0); } \ assert(__gc_stack_top != 0); \ assert(__builtin_frame_address(0) <= (void *)__gc_stack_top); #define POST_GC() \ assert(__builtin_frame_address(0) <= (void *)__gc_stack_top); \ - __post_gc(); \ - \ - if (!flag && __gc_stack_top != 0) { \ - fprintf(stderr, "Moving stack???\n"); \ - assert(false); \ - } - -extern size_t __gc_stack_top, __gc_stack_bottom; + if (flag) { __gc_stack_top = 0; } static void vfailure (char *s, va_list args) { fprintf(stderr, "*** FAILURE: ");