mirror of
https://github.com/ProgramSnail/Lama.git
synced 2025-12-06 06:48:48 +00:00
Fixed unit tests + fixed different compilation flags' combinations so that code compiles and works properly + added unit tests execution into a github actions workflow
This commit is contained in:
parent
ec9beed470
commit
8b073cbd48
8 changed files with 116 additions and 61 deletions
1
.github/workflows/blank.yml
vendored
1
.github/workflows/blank.yml
vendored
|
|
@ -38,3 +38,4 @@ jobs:
|
|||
- run: eval $(opam env)
|
||||
- run: opam exec -- make
|
||||
- run: opam exec -- make regression-all
|
||||
- run: opam exec -- make unit_tests
|
||||
|
|
|
|||
8
Makefile
8
Makefile
|
|
@ -9,6 +9,9 @@ all:
|
|||
$(MAKE) -C runtime
|
||||
$(MAKE) -C byterun
|
||||
$(MAKE) -C stdlib
|
||||
$(MAKE) -C runtime unit_tests.o
|
||||
$(MAKE) -C runtime invariants_check.o
|
||||
$(MAKE) -C runtime invariants_check_debug_print.o
|
||||
|
||||
STD_FILES=$(shell ls stdlib/*.[oi] stdlib/*.lama runtime/runtime.a runtime/Std.i)
|
||||
|
||||
|
|
@ -38,6 +41,11 @@ regression-lama-in-lama: all
|
|||
cp -R stdlib/* tmp-lama
|
||||
$(MAKE) -C lama-compiler
|
||||
|
||||
unit_tests:
|
||||
./runtime/unit_tests.o
|
||||
./runtime/invariants_check.o
|
||||
./runtime/invariants_check_debug_print.o
|
||||
|
||||
clean:
|
||||
$(MAKE) clean -C src
|
||||
$(MAKE) clean -C runtime
|
||||
|
|
|
|||
|
|
@ -1,23 +1,38 @@
|
|||
CC=gcc
|
||||
FLAGS=-no-pie -m32 -g2 -fstack-protector-all -DLAMA_ENV
|
||||
COMMON_FLAGS=-no-pie -m32 -g2 -fstack-protector-all
|
||||
PROD_FLAGS=$(COMMON_FLAGS) -DLAMA_ENV
|
||||
TEST_FLAGS=$(COMMON_FLAGS) -DDEBUG_VERSION
|
||||
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
|
||||
|
||||
test.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 test.o -DDEBUG_VERSION $(FLAGS) gc.c gc_runtime.s virt_stack.c ext_arr.c runtime.c test_main.c test_util.s
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
|
||||
virt_stack.o: virt_stack.h virt_stack.c
|
||||
$(CC) $(FLAGS) -c virt_stack.c
|
||||
$(CC) $(PROD_FLAGS) -c virt_stack.c
|
||||
|
||||
gc.o: gc.c gc.h
|
||||
$(CC) -rdynamic $(FLAGS) -c gc.c
|
||||
$(CC) -rdynamic $(PROD_FLAGS) -c gc.c
|
||||
|
||||
gc_runtime.o: gc_runtime.s
|
||||
$(CC) $(FLAGS) -c gc_runtime.s
|
||||
$(CC) $(PROD_FLAGS) -c gc_runtime.s
|
||||
|
||||
runtime.o: runtime.c runtime.h
|
||||
$(CC) $(FLAGS) -c runtime.c
|
||||
$(CC) $(PROD_FLAGS) -c runtime.c
|
||||
|
||||
clean:
|
||||
$(RM) *.a *.o *~
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
- [x] Fix warnings in ML code
|
||||
- [x] TODO: debug flag doesn't compile
|
||||
- [x] Sexp: move the tag to be `contents[0]` instead of the word in sexp header; i.e. get rid of sexp as separate data structure
|
||||
- [ ] Run Lama compiler on Lama
|
||||
- [x] Run Lama compiler on Lama
|
||||
- [ ] Add more stress tests (for graph-like structures) to `stdlib/regression` and unit tests
|
||||
- [ ] Magic constants
|
||||
- [ ] Normal documentation: a-la doxygen
|
||||
|
|
|
|||
99
runtime/gc.c
99
runtime/gc.c
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
static const size_t INIT_HEAP_SIZE = MINIMUM_HEAP_CAPACITY;
|
||||
|
||||
#ifdef FULL_INVARIANT_CHECKS
|
||||
#ifdef DEBUG_VERSION
|
||||
size_t cur_id = 0;
|
||||
#endif
|
||||
|
||||
|
|
@ -49,12 +49,12 @@ void handler (int sig) {
|
|||
}
|
||||
|
||||
void *alloc (size_t size) {
|
||||
#ifdef FULL_INVARIANT_CHECKS
|
||||
#ifdef DEBUG_VERSION
|
||||
++cur_id;
|
||||
#endif
|
||||
size_t bytes_sz = size;
|
||||
size = BYTES_TO_WORDS(size);
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "allocation of size %zu words (%zu bytes): ", size, bytes_sz);
|
||||
#endif
|
||||
void *p = gc_alloc_on_existing_heap(size);
|
||||
|
|
@ -184,7 +184,7 @@ void *gc_alloc_on_existing_heap (size_t size) {
|
|||
}
|
||||
|
||||
void *gc_alloc (size_t size) {
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "===============================GC cycle has started\n");
|
||||
#endif
|
||||
#ifdef FULL_INVARIANT_CHECKS
|
||||
|
|
@ -217,32 +217,34 @@ void *gc_alloc (size_t size) {
|
|||
fclose(heap_before_compaction);
|
||||
fclose(heap_after_compaction);
|
||||
#endif
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "===============================GC cycle has finished\n");
|
||||
#endif
|
||||
return gc_alloc_on_existing_heap(size);
|
||||
}
|
||||
|
||||
void mark_phase (void) {
|
||||
#ifdef DEBUG_VERSION
|
||||
#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_stack_top,
|
||||
__gc_stack_bottom);
|
||||
(void *)__gc_stack_top,
|
||||
(void *)__gc_stack_bottom);
|
||||
#endif
|
||||
__gc_root_scan_stack();
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "__gc_root_scan_stack has finished\n");
|
||||
fprintf(stderr, "scan_extra_roots has started\n");
|
||||
#endif
|
||||
scan_extra_roots();
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "scan_extra_roots has finished\n");
|
||||
fprintf(stderr, "scan_global_area has started\n");
|
||||
#endif
|
||||
#ifdef LAMA_ENV
|
||||
scan_global_area();
|
||||
#ifdef DEBUG_VERSION
|
||||
#endif
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "scan_global_area has finished\n");
|
||||
fprintf(stderr, "marking has finished\n");
|
||||
#endif
|
||||
|
|
@ -254,8 +256,7 @@ void compact_phase (size_t additional_size) {
|
|||
// all in words
|
||||
size_t next_heap_size =
|
||||
MAX(live_size * EXTRA_ROOM_HEAP_COEFFICIENT + additional_size, MINIMUM_HEAP_CAPACITY);
|
||||
size_t next_heap_pseudo_size =
|
||||
MAX(next_heap_size, heap.size); // this is weird but here is why it happens:
|
||||
size_t next_heap_pseudo_size = MAX(next_heap_size, heap.size);
|
||||
|
||||
memory_chunk old_heap = heap;
|
||||
heap.begin = mremap(
|
||||
|
|
@ -275,7 +276,7 @@ void compact_phase (size_t additional_size) {
|
|||
}
|
||||
|
||||
size_t compute_locations () {
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "GC compute_locations started\n");
|
||||
#endif
|
||||
size_t *free_ptr = heap.begin;
|
||||
|
|
@ -292,7 +293,7 @@ size_t compute_locations () {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "GC compute_locations finished\n");
|
||||
#endif
|
||||
// it will return number of words
|
||||
|
|
@ -300,7 +301,7 @@ size_t compute_locations () {
|
|||
}
|
||||
|
||||
void scan_and_fix_region (memory_chunk *old_heap, void *start, void *end) {
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "GC scan_and_fix_region started\n");
|
||||
#endif
|
||||
for (size_t *ptr = (size_t *)start; ptr < (size_t *)end; ++ptr) {
|
||||
|
|
@ -316,14 +317,14 @@ void scan_and_fix_region (memory_chunk *old_heap, void *start, void *end) {
|
|||
*(void **)ptr = new_addr + content_offset;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "GC scan_and_fix_region finished\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void scan_and_fix_region_roots (memory_chunk *old_heap) {
|
||||
#ifdef DEBUG_VERSION
|
||||
fprintf(stderr, "extra roots started: number os extra roots %i\n", extra_roots.current_free);
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "extra roots started: number of extra roots %i\n", extra_roots.current_free);
|
||||
#endif
|
||||
for (int i = 0; i < extra_roots.current_free; i++) {
|
||||
size_t *ptr = (size_t *)extra_roots.roots[i];
|
||||
|
|
@ -339,12 +340,14 @@ void scan_and_fix_region_roots (memory_chunk *old_heap) {
|
|||
) {
|
||||
#ifdef DEBUG_VERSION
|
||||
if (is_valid_heap_pointer((size_t *)ptr_value)) {
|
||||
# ifdef DEBUG_PRINT
|
||||
fprintf(stderr,
|
||||
"|\tskip extra root: %p (%p), since it points to Lama's stack top=%p bot=%p\n",
|
||||
extra_roots.roots[i],
|
||||
ptr_value,
|
||||
__gc_stack_top,
|
||||
__gc_stack_bottom);
|
||||
(void *)ptr_value,
|
||||
(void *)__gc_stack_top,
|
||||
(void *)__gc_stack_bottom);
|
||||
# endif
|
||||
}
|
||||
# ifdef LAMA_ENV
|
||||
else if ((extra_roots.roots[i] <= (void *)&__stop_custom_data
|
||||
|
|
@ -353,17 +356,19 @@ void scan_and_fix_region_roots (memory_chunk *old_heap) {
|
|||
stderr,
|
||||
"|\tskip extra root: %p (%p), since it points to Lama's static area stop=%p start=%p\n",
|
||||
extra_roots.roots[i],
|
||||
ptr_value,
|
||||
(void *)ptr_value,
|
||||
(void *)&__stop_custom_data,
|
||||
(void *)&__start_custom_data);
|
||||
exit(1);
|
||||
}
|
||||
# endif
|
||||
else {
|
||||
# ifdef DEBUG_PRINT
|
||||
fprintf(stderr,
|
||||
"|\tskip extra root: %p (%p): not a valid Lama pointer \n",
|
||||
extra_roots.roots[i],
|
||||
ptr_value);
|
||||
(void *)ptr_value);
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
continue;
|
||||
|
|
@ -374,18 +379,22 @@ void scan_and_fix_region_roots (memory_chunk *old_heap) {
|
|||
(void *)heap.begin + ((void *)get_forward_address(obj_ptr) - (void *)old_heap->begin);
|
||||
size_t content_offset = get_header_size(get_type_row_ptr(obj_ptr));
|
||||
*(void **)ptr = new_addr + content_offset;
|
||||
#ifdef DEBUG_VERSION
|
||||
fprintf(stderr, "|\textra root (%p) %p -> %p\n", extra_roots.roots[i], ptr_value, *ptr);
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr,
|
||||
"|\textra root (%p) %p -> %p\n",
|
||||
extra_roots.roots[i],
|
||||
(void *)ptr_value,
|
||||
(void *)*ptr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "|\textra roots finished\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void update_references (memory_chunk *old_heap) {
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "GC update_references started\n");
|
||||
#endif
|
||||
heap_iterator it = heap_begin_iterator();
|
||||
|
|
@ -410,9 +419,11 @@ void update_references (memory_chunk *old_heap) {
|
|||
size_t content_offset = get_header_size(get_type_row_ptr(field_obj_content_addr));
|
||||
#ifdef DEBUG_VERSION
|
||||
if (!is_valid_heap_pointer((void *)(new_addr + content_offset))) {
|
||||
# ifdef DEBUG_PRINT
|
||||
fprintf(stderr,
|
||||
"ur: incorrect pointer assignment: on object with id %d",
|
||||
TO_DATA(get_object_content_ptr(it.current))->id);
|
||||
# endif
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -431,13 +442,13 @@ void update_references (memory_chunk *old_heap) {
|
|||
assert((void *)&__stop_custom_data >= (void *)&__start_custom_data);
|
||||
scan_and_fix_region(old_heap, (void *)&__start_custom_data, (void *)&__stop_custom_data);
|
||||
#endif
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "GC update_references finished\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void physically_relocate (memory_chunk *old_heap) {
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "GC physically_relocate started\n");
|
||||
#endif
|
||||
heap_iterator from_iter = heap_begin_iterator();
|
||||
|
|
@ -455,7 +466,7 @@ void physically_relocate (memory_chunk *old_heap) {
|
|||
}
|
||||
from_iter = next_iter;
|
||||
}
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "GC physically_relocate finished\n");
|
||||
#endif
|
||||
}
|
||||
|
|
@ -532,7 +543,7 @@ void scan_global_area (void) {
|
|||
#endif
|
||||
|
||||
extern void gc_test_and_mark_root (size_t **root) {
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr,
|
||||
"\troot = %p (%p), stack addresses: [%p, %p)\n",
|
||||
root,
|
||||
|
|
@ -563,7 +574,7 @@ extern void __init (void) {
|
|||
|
||||
extern void __shutdown (void) {
|
||||
munmap(heap.begin, heap.size);
|
||||
#ifdef FULL_INVARIANT_CHECKS
|
||||
#ifdef DEBUG_VERSION
|
||||
cur_id = 0;
|
||||
#endif
|
||||
heap.begin = NULL;
|
||||
|
|
@ -600,7 +611,7 @@ void pop_extra_root (void **p) {
|
|||
|
||||
/* Functions for tests */
|
||||
|
||||
#if defined(FULL_INVARIANT_CHECKS) && defined(DEBUG_VERSION)
|
||||
#if defined(DEBUG_VERSION)
|
||||
size_t objects_snapshot (int *object_ids_buf, size_t object_ids_buf_size) {
|
||||
size_t *ids_ptr = (size_t *)object_ids_buf;
|
||||
size_t i = 0;
|
||||
|
|
@ -720,11 +731,12 @@ lama_type get_type_header_ptr (void *ptr) {
|
|||
case CLOSURE_TAG: return CLOSURE;
|
||||
case SEXP_TAG: return SEXP;
|
||||
default: {
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "ERROR: get_type_header_ptr: unknown object header, cur_id=%d", cur_id);
|
||||
raise(SIGINT); // only for debug purposes
|
||||
#else
|
||||
# ifdef FULL_INVARIANT_CHECKS
|
||||
# ifdef DEBUG_PRINT
|
||||
fprintf(stderr,
|
||||
"ERROR: get_type_header_ptr: unknown object header, ptr is %p, tag %i, heap size is "
|
||||
"%d cur_id=%d stack_top=%p stack_bot=%p ",
|
||||
|
|
@ -734,6 +746,7 @@ lama_type get_type_header_ptr (void *ptr) {
|
|||
cur_id,
|
||||
(void *)__gc_stack_top,
|
||||
(void *)__gc_stack_bottom);
|
||||
# endif
|
||||
FILE *heap_before_compaction = print_objects_traversal("dump_kill", 1);
|
||||
fclose(heap_before_compaction);
|
||||
# endif
|
||||
|
|
@ -847,10 +860,10 @@ size_t get_header_size (lama_type type) {
|
|||
void *alloc_string (int len) {
|
||||
data *obj = alloc(string_size(len));
|
||||
obj->data_header = STRING_TAG | (len << 3);
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "%p, [STRING] tag=%zu\n", obj, TAG(obj->data_header));
|
||||
#endif
|
||||
#ifdef FULL_INVARIANT_CHECKS
|
||||
#ifdef DEBUG_VERSION
|
||||
obj->id = cur_id;
|
||||
#endif
|
||||
obj->forward_address = 0;
|
||||
|
|
@ -860,10 +873,10 @@ void *alloc_string (int len) {
|
|||
void *alloc_array (int len) {
|
||||
data *obj = alloc(array_size(len));
|
||||
obj->data_header = ARRAY_TAG | (len << 3);
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "%p, [ARRAY] tag=%zu\n", obj, TAG(obj->data_header));
|
||||
#endif
|
||||
#ifdef FULL_INVARIANT_CHECKS
|
||||
#ifdef DEBUG_VERSION
|
||||
obj->id = cur_id;
|
||||
#endif
|
||||
obj->forward_address = 0;
|
||||
|
|
@ -873,10 +886,10 @@ void *alloc_array (int len) {
|
|||
void *alloc_sexp (int members) {
|
||||
sexp *obj = alloc(sexp_size(members));
|
||||
obj->data_header = SEXP_TAG | (members << 3);
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "%p, SEXP tag=%zu\n", obj, TAG(obj->data_header));
|
||||
#endif
|
||||
#ifdef FULL_INVARIANT_CHECKS
|
||||
#ifdef DEBUG_VERSION
|
||||
obj->id = cur_id;
|
||||
#endif
|
||||
obj->forward_address = 0;
|
||||
|
|
@ -888,10 +901,10 @@ void *alloc_closure (int captured) {
|
|||
|
||||
data *obj = alloc(closure_size(captured));
|
||||
obj->data_header = CLOSURE_TAG | (captured << 3);
|
||||
#ifdef DEBUG_VERSION
|
||||
#if defined(DEBUG_VERSION) && defined(DEBUG_PRINT)
|
||||
fprintf(stderr, "%p, [CLOSURE] tag=%zu\n", obj, TAG(obj->data_header));
|
||||
#endif
|
||||
#ifdef FULL_INVARIANT_CHECKS
|
||||
#ifdef DEBUG_VERSION
|
||||
obj->id = cur_id;
|
||||
#endif
|
||||
obj->forward_address = 0;
|
||||
|
|
|
|||
24
runtime/gc.h
24
runtime/gc.h
|
|
@ -46,6 +46,7 @@ typedef struct {
|
|||
size_t size;
|
||||
} memory_chunk;
|
||||
|
||||
|
||||
// the only GC-related function that should be exposed, others are useful for tests and internal implementation
|
||||
// allocates object of the given size on the heap
|
||||
void *alloc(size_t);
|
||||
|
|
@ -72,6 +73,7 @@ size_t compute_locations ();
|
|||
void update_references (memory_chunk *);
|
||||
void physically_relocate (memory_chunk *);
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// GC extra roots
|
||||
// ============================================================================
|
||||
|
|
@ -92,26 +94,31 @@ void clear_extra_roots (void);
|
|||
void push_extra_root (void **p);
|
||||
void pop_extra_root (void **p);
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Implemented in GASM: see gc_runtime.s
|
||||
// ============================================================================
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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 called `__prec_gc`
|
||||
// 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
|
||||
// ============================================================================
|
||||
|
|
@ -119,10 +126,11 @@ extern void gc_test_and_mark_root (size_t **root);
|
|||
bool is_valid_heap_pointer (const size_t *);
|
||||
static inline bool is_valid_pointer (const size_t *);
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Auxiliary functions for tests
|
||||
// ============================================================================
|
||||
#if defined(FULL_INVARIANT_CHECKS) && defined(DEBUG_VERSION)
|
||||
#if defined(DEBUG_VERSION)
|
||||
// makes a snapshot of current objects in heap (both alive and dead), writes these ids to object_ids_buf,
|
||||
// returns number of ids dumped
|
||||
// object_ids_buf is pointer to area preallocated by user for dumping ids of objects in heap
|
||||
|
|
@ -130,6 +138,7 @@ static inline bool is_valid_pointer (const size_t *);
|
|||
size_t objects_snapshot (int *object_ids_buf, size_t object_ids_buf_size);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef DEBUG_VERSION
|
||||
// essential function to mock program stack
|
||||
void set_stack (size_t stack_top, size_t stack_bottom);
|
||||
|
|
@ -138,6 +147,7 @@ void set_stack (size_t stack_top, size_t stack_bottom);
|
|||
void set_extra_roots (size_t extra_roots_size, void **extra_roots_ptr);
|
||||
#endif
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Utility functions
|
||||
// ============================================================================
|
||||
|
|
@ -186,13 +196,16 @@ size_t obj_size_header_ptr (void *ptr);
|
|||
|
||||
// returns total padding size that we need to store given object type
|
||||
size_t get_header_size (lama_type type);
|
||||
|
||||
// returns number of bytes that are required to allocate array with 'sz' elements (header included)
|
||||
size_t array_size (size_t sz);
|
||||
|
||||
// returns number of bytes that are required to allocate string of length 'l' (header included)
|
||||
size_t string_size (size_t len);
|
||||
// TODO: ask if it is actually so? number of captured elements is actually sz-1 and 1 extra word is code ptr?
|
||||
|
||||
// returns number of bytes that are required to allocate closure with 'sz-1' captured values (header included)
|
||||
size_t closure_size (size_t sz);
|
||||
|
||||
// returns number of bytes that are required to allocate s-expression with 'members' fields (header included)
|
||||
size_t sexp_size (size_t members);
|
||||
|
||||
|
|
@ -200,16 +213,21 @@ size_t sexp_size (size_t members);
|
|||
// (in case of s-exp, it is mandatory that obj ptr is very beginning of the object,
|
||||
// considering that now we store two versions of header in there)
|
||||
obj_field_iterator field_begin_iterator (void *obj);
|
||||
|
||||
// returns an iterator over object fields which are actual pointers, obj is ptr to object header
|
||||
// (in case of s-exp, it is mandatory that obj ptr is very beginning of the object,
|
||||
// considering that now we store two versions of header in there)
|
||||
obj_field_iterator ptr_field_begin_iterator (void *obj);
|
||||
|
||||
// moves the iterator to next object field
|
||||
void obj_next_field_iterator (obj_field_iterator *it);
|
||||
|
||||
// moves the iterator to the next object field which is an actual pointer
|
||||
void obj_next_ptr_field_iterator (obj_field_iterator *it);
|
||||
|
||||
// returns if we are done iterating over fields of the object
|
||||
bool field_is_done_iterator (obj_field_iterator *it);
|
||||
|
||||
// ptr is pointer to the actual object content, returns pointer to the very beginning of the object (header)
|
||||
void *get_obj_header_ptr (void *ptr);
|
||||
void *get_object_content_ptr (void *header_ptr);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#define SEXP_ONLY_HEADER_SZ (sizeof(int))
|
||||
|
||||
#ifndef FULL_INVARIANT_CHECKS
|
||||
#ifndef DEBUG_VERSION
|
||||
# define DATA_HEADER_SZ (sizeof(size_t) + sizeof(int))
|
||||
#else
|
||||
# define DATA_HEADER_SZ (sizeof(size_t) + sizeof(size_t) + sizeof(int))
|
||||
|
|
@ -44,7 +44,7 @@ typedef struct {
|
|||
// other utility info (i.e., size for array, number of fields for s-expression)
|
||||
int data_header;
|
||||
|
||||
#ifdef FULL_INVARIANT_CHECKS
|
||||
#ifdef DEBUG_VERSION
|
||||
size_t id;
|
||||
#endif
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ typedef struct {
|
|||
// other utility info (i.e., size for array, number of fields for s-expression)
|
||||
int data_header;
|
||||
|
||||
#ifdef FULL_INVARIANT_CHECKS
|
||||
#ifdef DEBUG_VERSION
|
||||
size_t id;
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -22,15 +22,15 @@ void test_correct_structure_sizes (void) {
|
|||
// something like induction base
|
||||
assert((array_size(0) == get_header_size(ARRAY)));
|
||||
assert((string_size(0) == get_header_size(STRING) + 1)); // +1 is because of '\0'
|
||||
assert((sexp_size(0) == get_header_size(SEXP)));
|
||||
assert((sexp_size(0) == get_header_size(SEXP) + MEMBER_SIZE));
|
||||
assert((closure_size(0) == get_header_size(CLOSURE)));
|
||||
|
||||
// just check correctness for some small sizes
|
||||
for (int k = 1; k < 20; ++k) {
|
||||
assert((array_size(k) == get_header_size(ARRAY) + sizeof(int) * k));
|
||||
assert((array_size(k) == get_header_size(ARRAY) + MEMBER_SIZE * k));
|
||||
assert((string_size(k) == get_header_size(STRING) + k + 1));
|
||||
assert((sexp_size(k) == get_header_size(SEXP) + sizeof(int) * k));
|
||||
assert((closure_size(k) == get_header_size(CLOSURE) + sizeof(int) * k));
|
||||
assert((sexp_size(k) == get_header_size(SEXP) + MEMBER_SIZE * (k + 1)));
|
||||
assert((closure_size(k) == get_header_size(CLOSURE) + MEMBER_SIZE * k));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue