diff options
Diffstat (limited to 'src/lib/memory.c')
| -rw-r--r-- | src/lib/memory.c | 271 |
1 files changed, 168 insertions, 103 deletions
diff --git a/src/lib/memory.c b/src/lib/memory.c index fb143ec..0ff4784 100644 --- a/src/lib/memory.c +++ b/src/lib/memory.c @@ -73,7 +73,6 @@ data(struct chunk *c) struct chunk * next(struct chunk *c) { - static struct chunk *prev; uint8_t *p; if(c->last) @@ -84,94 +83,135 @@ next(struct chunk *c) p += c->size; assert((((uintptr_t)p) % ALIGNMENT) == 0); - prev = c; - UNUSED_PARAMETER(prev); - return (struct chunk *)p; } -#define VISIT_FIELD(X, tag, ptr) X(((struct tag *)data(c))->ptr) -#define VISIT_CHUNK_PTRS(X, c) switch(c->tag){ \ - case CHUNK_TAG_APLWC_LINE: \ - VISIT_FIELD(X, aplwc_line, text); \ - VISIT_FIELD(X, aplwc_line, tokens); \ - break; \ - case CHUNK_TAG_STRING: \ - break; \ - case CHUNK_TAG_TOKEN_LIST: \ - VISIT_FIELD(X, token_list, text); \ - break; \ - case CHUNK_TAG_APLWC_VALUE: \ - break; \ - case CHUNK_TAG_APLWC_MODULE: \ - VISIT_FIELD(X, aplwc_module, name); \ - VISIT_FIELD(X, aplwc_module, tokens); \ - VISIT_FIELD(X, aplwc_module, imports); \ - VISIT_FIELD(X, aplwc_module, members); \ - VISIT_FIELD(X, aplwc_module, link); \ - break; \ - case CHUNK_TAG_MODULE_MEMBER: \ - VISIT_FIELD(X, module_member, module); \ - VISIT_FIELD(X, module_member, real_member); \ - VISIT_FIELD(X, module_member, link); \ - break; \ - case CHUNK_TAG_SYMBOL: \ - VISIT_FIELD(X, symbol, text); \ - VISIT_FIELD(X, symbol, link); \ - break; \ - case CHUNK_TAG_FREE: \ - break; \ - } -#define VISIT_ROOT_PTRS(X) do{ \ - X(aplwc->modules); \ - X(aplwc->symtab); \ - for(frame = aplwc->memptrs; frame; frame = frame->link) \ - for(i = 0; i < frame->count; i++) \ - if(frame->ptrs[i]) \ - X(*frame->ptrs[i]); \ - for(ref = aplwc->refs; ref; ref = ref->link) \ - if(ref->ptr) \ - X(ref->ptr); \ -}while(0) - -#define VISIT_ALL_PTRS(X, data) do{ \ - VISIT_ROOT_PTRS(X); \ - for(c = (struct chunk *)(data); c; c = next(c)) \ - VISIT_CHUNK_PTRS(X, c); \ -}while(0) +#define VISIT(ptr) (ptr) = fn(ptr, aux) static void -fixrefs(struct aplwc *aplwc, uint8_t *new, uint8_t *old) +visit_chunk_ptrs(struct chunk *c, void *(*fn)(void *, void *), void *aux) { + union { + void *vp; + struct aplwc_line *line; + struct token_list *tokens; + struct aplwc_module *module; + struct module_member *module_member; + struct symbol *symbol; + } d; + + assert(c != NULL); + + d.vp = data(c); + switch(c->tag){ + case CHUNK_TAG_FREE: + break; + case CHUNK_TAG_APLWC_LINE: + VISIT(d.line->text); + VISIT(d.line->text); + VISIT(d.line->tokens); + break; + case CHUNK_TAG_STRING: + break; + case CHUNK_TAG_TOKEN_LIST: + VISIT(d.tokens->text); + break; + case CHUNK_TAG_APLWC_VALUE: + break; + case CHUNK_TAG_APLWC_MODULE: + VISIT(d.module->name); + VISIT(d.module->tokens); + VISIT(d.module->imports); + VISIT(d.module->members); + VISIT(d.module->link); + break; + case CHUNK_TAG_MODULE_MEMBER: + VISIT(d.module_member->module); + VISIT(d.module_member->real_member); + VISIT(d.module_member->link); + break; + case CHUNK_TAG_SYMBOL: + VISIT(d.symbol->text); + VISIT(d.symbol->link); + break; + } +} - struct chunk *c; +static void +visit_root_ptrs(struct aplwc *aplwc, void *(*fn)(void *, void *), void *aux) +{ struct memory_ptr_frame *frame; struct aplwc_ref *ref; - size_t add, sub, i; + size_t i; + + VISIT(aplwc->modules); + VISIT(aplwc->symtab); + + for(frame = aplwc->memptrs; frame; frame = frame->link) + for(i = 0; i < frame->count; i++) + if(frame->ptrs[i]) + VISIT(*frame->ptrs[i]); + + for(ref = aplwc->refs; ref; ref = ref->link) + if(ref->ptr) + VISIT(ref->ptr); +} + +static void +visit_all_ptrs(struct aplwc *aplwc, void *(*fn)(void *, void *), void *aux) +{ + struct chunk *c; + + visit_root_ptrs(aplwc, fn, aux); + for(c = (struct chunk *)aplwc->data; c; c = next(c)) + visit_chunk_ptrs(c, fn, aux); +} + +#undef VISIT + +struct fixref_args { + size_t add; + size_t sub; +}; + +static void * +fixref(void *p, void *aux) +{ + struct fixref_args *args = aux; + uint8_t *r; + + if(p == NULL) + return p; + + r = p; + + r += args->add; + r -= args->sub; + return r; +} + +static void +fixrefs(struct aplwc *aplwc, uint8_t *old) +{ + uint8_t *new = aplwc->data; + struct fixref_args args; if(new > old){ - add = new-old; - sub = 0; + args.add = new-old; + args.sub = 0; }else{ - add = 0; - sub = old-new; + args.add = 0; + args.sub = old-new; } -#define FIX(ptr) do{ \ - if(ptr){ \ - (ptr) = (void*)(((uint8_t*)(ptr))+add); \ - (ptr) = (void*)(((uint8_t*)(ptr))-sub); \ - } \ -}while(0) - VISIT_ALL_PTRS(FIX, new); -#undef FIX + visit_all_ptrs(aplwc, fixref, &args); } static enum aplwc_rc grow(struct aplwc *aplwc, size_t extra) { - uint8_t *unaligned_data, *aligned_data; - size_t unaligned_newsize, aligned_newsize, adjust; + uint8_t *unaligned_data, *aligned_data, *old_data; + size_t unaligned_newsize, aligned_newsize, adjust, old_size; struct chunk *free, *head, *last; if(aplwc->fns.alloc == NULL) @@ -193,9 +233,15 @@ grow(struct aplwc *aplwc, size_t extra) head = (struct chunk *)aligned_data; last = NULL; - if(aplwc->data){ - memmove(aligned_data, aplwc->data, aplwc->size); - fixrefs(aplwc, aligned_data, aplwc->data); + old_data = aplwc->data; + old_size = aplwc->size; + + aplwc->data = aligned_data; + aplwc->size = aligned_newsize; + + if(old_data){ + memmove(aplwc->data, old_data, old_size); + fixrefs(aplwc, old_data); memory_destroy(aplwc); for(free = head; free; free = next(free)) if(next(free)) @@ -203,10 +249,11 @@ grow(struct aplwc *aplwc, size_t extra) else last = free; } + aplwc->unaligned_data = unaligned_data; /* must be after memory_destroy */ - free = (struct chunk *)(aligned_data + aplwc->size); + free = (struct chunk *)(aligned_data + old_size); free->tag = CHUNK_TAG_FREE; - free->size = aligned_newsize - aplwc->size; + free->size = aligned_newsize - old_size; free->stack = NULL; free->last = 1; @@ -217,9 +264,6 @@ grow(struct aplwc *aplwc, size_t extra) last->last = 0; } - aplwc->unaligned_data = unaligned_data; - aplwc->data = aligned_data; - aplwc->size = aligned_newsize; return 1; error: @@ -245,23 +289,34 @@ find_free(struct aplwc *aplwc, size_t min) return c; } -static void -push(struct aplwc *aplwc, struct chunk **stack, void *p) +struct push_args { + struct aplwc *aplwc; + struct chunk **stack; +}; + +static void * +push(void *p, void *aux) { struct chunk *c; + struct push_args *args; if(p == NULL) - return; + return p; + + args = aux; + c = (struct chunk *)(((uint8_t*)p)-HEADER_SIZE); assert(c->tag != CHUNK_TAG_FREE); - if(c->reachable == aplwc->reachable_bit) - return; + if(c->reachable == args->aplwc->reachable_bit) + return p; assert(c->stack == NULL); - c->reachable = aplwc->reachable_bit; - c->stack = *stack; - *stack = c; + c->reachable = args->aplwc->reachable_bit; + c->stack = *args->stack; + *args->stack = c; + + return p; } static struct chunk * @@ -284,22 +339,20 @@ collect(struct aplwc *aplwc) { struct chunk *c, *prev; struct chunk *stack; - struct memory_ptr_frame *frame; - struct aplwc_ref *ref; - size_t i; + struct push_args args; aplwc->reachable_bit = ~aplwc->reachable_bit; /* Mark reachable chunks */ stack = NULL; + args.aplwc = aplwc; + args.stack = &stack; -#define PUSH(ptr) push(aplwc, &stack, ptr) - VISIT_ROOT_PTRS(PUSH); + visit_root_ptrs(aplwc, push, &args); while(stack){ c = pop(&stack); - VISIT_CHUNK_PTRS(PUSH, c); -#undef PUSH + visit_chunk_ptrs(c, push, &args); } /* Free chunks not marked */ @@ -317,20 +370,32 @@ collect(struct aplwc *aplwc) } } +struct swap_args { + void *old; + void *new; +}; + +static void * +swap(void *p, void *aux) +{ + struct swap_args *args; + + args = aux; + if(p == args->old) + return args->new; + else + return p; +} + static void swapptr(struct aplwc *aplwc, void *old, void *new) { - struct chunk *c; - struct memory_ptr_frame *frame; - struct aplwc_ref *ref; - size_t i; + struct swap_args args; + + args.old = old; + args.new = new; -#define SWAP(ptr) do{ \ - if((ptr) == old) \ - (ptr) = new; \ -}while(0) - VISIT_ALL_PTRS(SWAP, aplwc->data); -#undef SWAP + visit_all_ptrs(aplwc, swap, &args); } static void |