diff --git a/include/picrin.h b/include/picrin.h index 2f2832e1..79995f24 100644 --- a/include/picrin.h +++ b/include/picrin.h @@ -17,11 +17,15 @@ struct pic_proc { } u; }; +#define PIC_HEAP_SIZE 1024 + typedef struct { pic_value *sp; pic_value *stbase, *stend; struct pic_env *global_env; + + struct heap_page *heap; } pic_state; void *pic_alloc(pic_state *, size_t); diff --git a/include/picrin/gc.h b/include/picrin/gc.h new file mode 100644 index 00000000..e66acc24 --- /dev/null +++ b/include/picrin/gc.h @@ -0,0 +1,16 @@ +#ifndef GC_H__ +#define GC_H__ + +struct header { + struct header *ptr; + size_t size; +}; + +struct heap_page { + struct header *base, *freep; + size_t heap_size; +}; + +void init_heap_page(struct heap_page *); + +#endif diff --git a/src/gc.c b/src/gc.c index a1dac877..cfab1ccc 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1,12 +1,80 @@ #include #include "picrin.h" +#include "picrin/gc.h" + +void +init_heap_page(struct heap_page *heap) +{ + struct header *base, *freep; + void *p; + + p = (struct header *)malloc(PIC_HEAP_SIZE); + + heap->base = base = (struct header *) + (((unsigned long)p + sizeof(struct header) -1) & ~(sizeof(struct header) - 1)); + base->ptr = base + 1; + base->size = 0; + + heap->freep = freep = base->ptr; + freep->ptr = base; + freep->size = ((char *)p + PIC_HEAP_SIZE - (char *)freep) / sizeof(struct header); +} void * pic_alloc(pic_state *pic, size_t size) { - /* mock */ - return malloc(size); + struct header *freep, *p, *prevp; + size_t nunits; + + nunits = (size + sizeof(struct header) - 1) / sizeof(struct header) + 1; + + freep = pic->heap->freep; + prevp = freep; + for (p = prevp->ptr; ; prevp = p, p = p->ptr) { + if (p->size >= nunits) + break; + if (p == freep) + return 0; + } + if (p->size == nunits) { + prevp->ptr = p->ptr; + } + else { + p->size -= nunits; + p += p->size; + p->size = nunits; + } + pic->heap->freep = prevp; + + return (void *)(p + 1); +} + +void +pic_free(pic_state *pic, void *ptr) +{ + struct header *bp, *p; + + bp = (struct header *)ptr - 1; + + for (p = pic->heap->freep; !(p < bp && bp < p->ptr); p = p->ptr) { + if (p >= p->ptr && (bp > p || bp < p->ptr)) + break; + } + if (bp + bp->size == p->ptr) { + bp->size += p->ptr->size; + bp->ptr = p->ptr->ptr; + } + else { + bp->ptr = p->ptr; + } + if (p + p->size == bp) { + p->size += bp->size; + p->ptr = bp->ptr; + } else { + p->ptr = bp; + } + pic->heap->freep = p; } struct pic_object * @@ -20,8 +88,3 @@ pic_gc_alloc(pic_state *pic, size_t size, enum pic_tt tt) return obj; } -void -pic_free(pic_state *pic, void *ptr) -{ - free(ptr); -} diff --git a/src/state.c b/src/state.c index 8666b8f8..812c0299 100644 --- a/src/state.c +++ b/src/state.c @@ -1,6 +1,7 @@ #include #include "picrin.h" +#include "picrin/gc.h" static struct pic_env * pic_new_empty_env() @@ -25,6 +26,10 @@ pic_open() pic->stbase = pic->sp = (pic_value *)malloc(sizeof(pic_value) * 1024); pic->stend = pic->stbase + 1024; + /* memory heap */ + pic->heap = (struct heap_page *)malloc(sizeof(struct heap_page)); + init_heap_page(pic->heap); + pic->global_env = pic_new_empty_env(); return pic;