on master help sign in
Blindly implement the C heap in the RTS.
1daf221Matus Tejiscak
rts/idris_gc.c+7
@@ -60,6 +60,10 @@ VAL copy(VM* vm, VAL x) {
60 memcpy(cl, x, size);
60 memcpy(cl, x, size);
61 }
61 }
62 break;
62 break;
63+ case CDATA:
64+ cl = MKCDATAc(vm, x->info.c_heap_item);
65+ c_heap_mark_item(x->info.c_heap_item);
66+ break;
63 default:
67 default:
64 break;
68 break;
65 }
69 }
@@ -135,6 +139,9 @@ void idris_gc(VM* vm) {
135
139
136 STATS_LEAVE_GC(vm->stats, vm->heap.size, vm->heap.next - vm->heap.heap)
140 STATS_LEAVE_GC(vm->stats, vm->heap.size, vm->heap.next - vm->heap.heap)
137 HEAP_CHECK(vm)
141 HEAP_CHECK(vm)
142+
143+ // finally, sweep the C heap
144+ c_heap_sweep(&vm->c_heap);
138}
145}
139
146
140void idris_gcInfo(VM* vm, int doGC) {
147void idris_gcInfo(VM* vm, int doGC) {
rts/idris_heap.c+68
@@ -5,6 +5,74 @@
5#include <stddef.h>
5#include <stddef.h>
6#include <stdio.h>
6#include <stdio.h>
7
7
8+CHeapItem * c_heap_create_item(void * data, CDataFinalizer_t * finalizer)
9+{
10+ CHeapItem * item = (CHeapItem *) malloc(sizeof(CHeapItem));
11+
12+ item->data = data;
13+ item->finalizer = finalizer;
14+ item->is_inserted = false;
15+ item->is_used = false;
16+ item->next = NULL;
17+
18+ return item;
19+}
20+
21+void c_heap_insert(CHeap * heap, CHeapItem * item)
22+{
23+ item->next = heap->first;
24+ heap->first = item;
25+}
26+
27+void c_heap_mark_item(CHeapItem * item)
28+{
29+ item->is_used = true;
30+}
31+
32+static void c_heap_free_item(CHeapItem * item)
33+{
34+ item->finalizer(item->data);
35+ free(item);
36+}
37+
38+void c_heap_sweep(CHeap * heap)
39+{
40+ CHeapItem ** prev_next = &heap->first;
41+ CHeapItem * p = heap->first;
42+ while (p != NULL)
43+ {
44+ if (p->is_used)
45+ {
46+ p->is_used = false;
47+ prev_next = &p->next;
48+ p = p->next;
49+ }
50+ else
51+ {
52+ CHeapItem * unused_item = p;
53+ p = p->next;
54+
55+ *prev_next = unused_item->next;
56+ c_heap_free_item(unused_item);
57+ }
58+ }
59+}
60+
61+void c_heap_init(CHeap * heap)
62+{
63+ heap->first = NULL;
64+}
65+
66+void c_heap_free(CHeap * heap)
67+{
68+ CHeapItem * p = heap->first;
69+ while (p != NULL)
70+ {
71+ CHeapItem * q = p;
72+ p = p->next;
73+ c_heap_free_item(q);
74+ }
75+}
8
76
9/* Used for initializing the heap. */
77/* Used for initializing the heap. */
10void alloc_heap(Heap * h, size_t heap_size, size_t growth, char * old)
78void alloc_heap(Heap * h, size_t heap_size, size_t growth, char * old)
rts/idris_heap.h+24
@@ -1,8 +1,32 @@
1#ifndef _IDRIS_HEAP_H
1#ifndef _IDRIS_HEAP_H
2#define _IDRIS_HEAP_H
2#define _IDRIS_HEAP_H
3
3
4+#include <stdbool.h>
4#include <stddef.h>
5#include <stddef.h>
5
6
7+typedef void CDataFinalizer_t(void *);
8+
9+typedef struct CHeapItem {
10+ void * data;
11+ CDataFinalizer_t * finalizer; // responsible for freeing the passed pointer, too
12+ bool is_used;
13+ bool is_inserted;
14+ struct CHeapItem * next;
15+} CHeapItem;
16+
17+typedef struct CHeap {
18+ CHeapItem * first;
19+} CHeap;
20+
21+void c_heap_init(CHeap * c_heap);
22+void c_heap_free(CHeap * c_heap);
23+void c_heap_insert(CHeap * c_heap, CHeapItem * item);
24+void c_heap_mark_item(CHeapItem * item);
25+void c_heap_sweep(CHeap * c_heap);
26+
27+// this is the function to use in C binding code
28+CHeapItem * c_heap_create_item(void * data, CDataFinalizer_t * finalizer);
29+
6typedef struct {
30typedef struct {
7 char* next; // Next allocated chunk. Should always (heap <= next < end).
31 char* next; // Next allocated chunk. Should always (heap <= next < end).
8 char* heap; // Point to bottom of heap
32 char* heap; // Point to bottom of heap
rts/idris_rts.c+23
@@ -35,6 +35,8 @@ VM* init_vm(int stack_size, size_t heap_size,
35
35
36 alloc_heap(&(vm->heap), heap_size, heap_size, NULL);
36 alloc_heap(&(vm->heap), heap_size, heap_size, NULL);
37
37
38+ c_heap_init(&vm->c_heap);
39+
38 vm->ret = NULL;
40 vm->ret = NULL;
39 vm->reg1 = NULL;
41 vm->reg1 = NULL;
40#ifdef HAS_PTHREAD
42#ifdef HAS_PTHREAD
@@ -108,6 +110,7 @@ Stats terminate(VM* vm) {
108#endif
110#endif
109 free(vm->valstack);
111 free(vm->valstack);
110 free_heap(&(vm->heap));
112 free_heap(&(vm->heap));
113+ c_heap_free(&(vm->c_heap));
111#ifdef HAS_PTHREAD
114#ifdef HAS_PTHREAD
112 pthread_mutex_destroy(&(vm -> inbox_lock));
115 pthread_mutex_destroy(&(vm -> inbox_lock));
113 pthread_mutex_destroy(&(vm -> inbox_block));
116 pthread_mutex_destroy(&(vm -> inbox_block));
@@ -264,6 +267,26 @@ char* GETSTROFF(VAL stroff) {
264 return (root->str->info.str + root->offset);
267 return (root->str->info.str + root->offset);
265}
268}
266
269
270+VAL MKCDATA(VM* vm, CHeapItem * item) {
271+ Closure* cl = allocate(sizeof(Closure), 0);
272+ SETTY(cl, CDATA);
273+ if (!item->is_inserted)
274+ {
275+ c_heap_insert(&vm->c_heap, item);
276+ }
277+ return cl;
278+}
279+
280+VAL MKCDATAc(VM* vm, CHeapItem * item) {
281+ Closure* cl = allocate(sizeof(Closure), 1);
282+ SETTY(cl, CDATA);
283+ if (!item->is_inserted)
284+ {
285+ c_heap_insert(&vm->c_heap, item);
286+ }
287+ return cl;
288+}
289+
267VAL MKPTR(VM* vm, void* ptr) {
290VAL MKPTR(VM* vm, void* ptr) {
268 Closure* cl = allocate(sizeof(Closure), 0);
291 Closure* cl = allocate(sizeof(Closure), 0);
269 SETTY(cl, PTR);
292 SETTY(cl, PTR);
rts/idris_rts.h+5−1
@@ -27,7 +27,7 @@
27typedef enum {
27typedef enum {
28 CON, INT, BIGINT, FLOAT, STRING, STROFFSET,
28 CON, INT, BIGINT, FLOAT, STRING, STROFFSET,
29 BITS8, BITS16, BITS32, BITS64, UNIT, PTR, FWD,
29 BITS8, BITS16, BITS32, BITS64, UNIT, PTR, FWD,
30− MANAGEDPTR, RAWDATA
30+ MANAGEDPTR, RAWDATA, CDATA
31} ClosureType;
31} ClosureType;
32
32
33typedef struct Closure *VAL;
33typedef struct Closure *VAL;
@@ -67,6 +67,7 @@ typedef struct Closure {
67 uint32_t bits32;
67 uint32_t bits32;
68 uint64_t bits64;
68 uint64_t bits64;
69 ManagedPtr* mptr;
69 ManagedPtr* mptr;
70+ CHeapItem* c_heap_item;
70 size_t size;
71 size_t size;
71 } info;
72 } info;
72} Closure;
73} Closure;
@@ -90,6 +91,7 @@ struct VM_t {
90 VAL* valstack_base;
91 VAL* valstack_base;
91 VAL* stack_max;
92 VAL* stack_max;
92
93
94+ CHeap c_heap;
93 Heap heap;
95 Heap heap;
94#ifdef HAS_PTHREAD
96#ifdef HAS_PTHREAD
95 pthread_mutex_t inbox_lock;
97 pthread_mutex_t inbox_lock;
@@ -207,6 +209,7 @@ VAL MKB8(VM* vm, uint8_t b);
207VAL MKB16(VM* vm, uint16_t b);
209VAL MKB16(VM* vm, uint16_t b);
208VAL MKB32(VM* vm, uint32_t b);
210VAL MKB32(VM* vm, uint32_t b);
209VAL MKB64(VM* vm, uint64_t b);
211VAL MKB64(VM* vm, uint64_t b);
212+VAL MKCDATA(VM* vm, CHeapItem * item);
210
213
211// following versions don't take a lock when allocating
214// following versions don't take a lock when allocating
212VAL MKFLOATc(VM* vm, double val);
215VAL MKFLOATc(VM* vm, double val);
@@ -214,6 +217,7 @@ VAL MKSTROFFc(VM* vm, StrOffset* off);
214VAL MKSTRc(VM* vm, char* str);
217VAL MKSTRc(VM* vm, char* str);
215VAL MKPTRc(VM* vm, void* ptr);
218VAL MKPTRc(VM* vm, void* ptr);
216VAL MKMPTRc(VM* vm, void* ptr, size_t size);
219VAL MKMPTRc(VM* vm, void* ptr, size_t size);
220+VAL MKCDATAc(VM* vm, CHeapItem * item);
217
221
218char* GETSTROFF(VAL stroff);
222char* GETSTROFF(VAL stroff);
219
223