33#include "ir.h"
44#include "primes.inc"
55
6+ #define vm_get_gc (vm ) ((vm_gc_t *) (vm)->gc)
7+
68struct vm_gc_objs_t ;
79struct vm_gc_table_cache_t ;
810struct vm_gc_t ;
@@ -25,181 +27,205 @@ struct vm_gc_table_cache_t {
2527
2628struct vm_gc_t {
2729 size_t last ;
30+ vm_gc_objs_t keep ;
31+ vm_gc_objs_t todo ;
2832 vm_gc_objs_t objs ;
2933};
3034
31- static inline vm_gc_objs_add (vm_gc_objs_t * restrict objs , vm_obj_t obj ) {
35+ static inline void vm_gc_objs_push (vm_gc_objs_t * restrict objs , vm_obj_t obj ) {
3236 if (objs -> len + 1 >= objs -> alloc ) {
3337 objs -> alloc = (objs -> len ) * VM_GC_FACTOR + 1 ;
3438 objs -> objs = vm_realloc (objs -> objs , sizeof (vm_obj_t ) * objs -> alloc );
3539 }
3640 objs -> objs [objs -> len ++ ] = obj ;
3741}
3842
39- static inline void vm_gc_mark_obj (vm_obj_t obj );
43+ static inline vm_obj_t vm_gc_objs_pop (vm_gc_objs_t * restrict objs ) {
44+ return objs -> objs [-- objs -> len ];
45+ }
46+
47+ static inline bool vm_gc_objs_is_empty (vm_gc_objs_t * restrict objs ) {
48+ return objs -> len == 0 ;
49+ }
4050
41- static inline void vm_gc_mark_arg (vm_ir_arg_t arg ) {
51+ static inline void vm_gc_objs_clear (vm_gc_objs_t * restrict objs ) {
52+ objs -> len = 0 ;
53+ }
54+
55+ static inline void vm_gc_objs_free (vm_gc_objs_t * restrict objs ) {
56+ vm_free (objs -> objs );
57+ * objs = (vm_gc_objs_t ) {
58+ .objs = NULL ,
59+ };
60+ }
61+
62+ static inline void vm_gc_mark_obj (vm_t * vm , vm_obj_t obj );
63+
64+ static inline void vm_gc_mark_arg (vm_t * vm , vm_ir_arg_t arg ) {
4265 if (arg .type == VM_IR_ARG_TYPE_LIT ) {
43- vm_gc_mark_obj (arg .lit );
66+ vm_gc_mark_obj (vm , arg .lit );
4467 }
4568}
4669
47- static inline void vm_gc_mark_block (vm_ir_block_t * block ) {
48- if (!block -> mark ) {
49- block -> mark = true;
70+ static inline void vm_gc_mark_block (vm_t * vm , vm_ir_block_t * block ) {
71+ if (!block -> header . mark ) {
72+ block -> header . mark = true;
5073 for (size_t j = 0 ; j < block -> len ; j ++ ) {
5174 vm_ir_instr_t * instr = & block -> instrs [j ];
5275 for (size_t k = 0 ; instr -> args [k ].type != VM_IR_ARG_TYPE_NONE ; k ++ ) {
53- vm_gc_mark_arg (instr -> args [k ]);
76+ vm_gc_mark_arg (vm , instr -> args [k ]);
5477 }
5578 }
5679 for (size_t j = 0 ; j < 2 && block -> branch .targets [j ] != NULL ; j ++ ) {
57- vm_gc_mark_block (block -> branch .targets [j ]);
80+ vm_gc_mark_block (vm , block -> branch .targets [j ]);
5881 }
5982 for (size_t k = 0 ; block -> branch .args [k ].type != VM_IR_ARG_TYPE_NONE ; k ++ ) {
60- vm_gc_mark_arg (block -> branch .args [k ]);
83+ vm_gc_mark_arg (vm , block -> branch .args [k ]);
84+ }
85+ vm_gc_mark_arg (vm , block -> branch .out );
86+ }
87+ }
88+
89+ static inline void vm_gc_mark_run (vm_t * vm ) {
90+ while (!vm_gc_objs_is_empty (& vm_get_gc (vm )-> todo )) {
91+ vm_obj_t obj = vm_gc_objs_pop (& vm_get_gc (vm )-> todo );
92+ if (vm_obj_is_string (obj )) {
93+ vm_io_buffer_t * buffer = vm_obj_get_string (obj );
94+ if (!buffer -> header .mark ) {
95+ buffer -> header .mark = true;
96+ vm_gc_objs_push (& vm_get_gc (vm )-> keep , obj );
97+ }
98+ } else if (vm_obj_is_closure (obj )) {
99+ vm_obj_closure_t * closure = vm_obj_get_closure (obj );
100+ if (!closure -> header .mark ) {
101+ closure -> header .mark = true;
102+ vm_gc_objs_push (& vm_get_gc (vm )-> keep , obj );
103+ for (size_t i = 0 ; i < closure -> len ; i ++ ) {
104+ vm_gc_mark_obj (vm , closure -> values [i ]);
105+ }
106+ }
107+ vm_gc_mark_block (vm , closure -> block );
108+ } else if (vm_obj_is_table (obj )) {
109+ vm_obj_table_t * table = vm_obj_get_table (obj );
110+ if (!table -> header .mark ) {
111+ table -> header .mark = true;
112+ vm_gc_objs_push (& vm_get_gc (vm )-> keep , obj );
113+ uint64_t len = vm_primes_table [table -> size ];
114+ vm_table_pair_t * pairs = table -> pairs ;
115+ for (size_t i = 0 ; i < len ; i ++ ) {
116+ vm_gc_mark_obj (vm , pairs [i ].key );
117+ vm_gc_mark_obj (vm , pairs [i ].value );
118+ }
119+ }
120+ } else if (vm_obj_is_block (obj )) {
121+ vm_gc_mark_block (vm , vm_obj_get_block (obj ));
61122 }
62- vm_gc_mark_arg (block -> branch .out );
63123 }
64124}
65125
126+ static inline void vm_gc_mark_obj (vm_t * vm , vm_obj_t obj ) {
127+ vm_gc_objs_push (& vm_get_gc (vm )-> todo , obj );
128+ }
66129
67- static inline void vm_gc_mark_obj ( vm_obj_t obj ) {
130+ static inline void vm_gc_maybe_reset_obj ( vm_t * vm , vm_obj_t obj ) {
68131 if (vm_obj_is_string (obj )) {
69132 vm_io_buffer_t * buffer = vm_obj_get_string (obj );
70- buffer -> mark = true;
133+ if (!buffer -> header .mark ) {
134+ vm_free (buffer -> buf );
135+ vm_free (buffer );
136+ } else {
137+ buffer -> header .mark = false;
138+ }
71139 } else if (vm_obj_is_closure (obj )) {
72140 vm_obj_closure_t * closure = vm_obj_get_closure (obj );
73- if (!closure -> mark ) {
74- closure -> mark = true;
75- for (size_t i = 0 ; i < closure -> len ; i ++ ) {
76- vm_gc_mark_obj (closure -> values [i ]);
77- }
141+ if (!closure -> header .mark ) {
142+ vm_free (closure );
143+ } else {
144+ closure -> header .mark = false;
78145 }
79- vm_gc_mark_block (closure -> block );
80146 } else if (vm_obj_is_table (obj )) {
81147 vm_obj_table_t * table = vm_obj_get_table (obj );
82- if (!table -> mark ) {
83- table -> mark = true;
84- uint64_t len = vm_primes_table [table -> size ];
85- vm_table_pair_t * pairs = table -> pairs ;
86- for (size_t i = 0 ; i < len ; i ++ ) {
87- vm_gc_mark_obj (pairs [i ].key );
88- vm_gc_mark_obj (pairs [i ].value );
89- }
148+ if (!table -> header .mark ) {
149+ vm_free (table -> pairs );
150+ vm_free (table );
151+ } else {
152+ table -> header .mark = false;
90153 }
91154 } else if (vm_obj_is_block (obj )) {
92- vm_gc_mark_block (vm_obj_get_block (obj ));
155+ vm_ir_block_t * block = vm_obj_get_block (obj );
156+ if (!block -> header .mark ) {
157+ for (size_t j = 0 ; j < block -> len ; j ++ ) {
158+ vm_ir_instr_t instr = block -> instrs [j ];
159+ vm_free (instr .args );
160+ }
161+ vm_free (block -> instrs );
162+ vm_free (block -> branch .args );
163+ vm_free (block -> code );
164+ vm_free (block );
165+ } else {
166+ block -> header .mark = false;
167+ }
93168 }
94169}
95170
96171void vm_gc_mark (vm_t * vm , vm_obj_t * top ) {
172+ vm_gc_objs_clear (& vm_get_gc (vm )-> keep );
173+
97174 for (vm_ir_blocks_t * blocks = vm -> blocks ; blocks ; blocks = blocks -> next ) {
98- vm_gc_mark_block (blocks -> block );
175+ vm_gc_mark_block (vm , blocks -> block );
99176 }
100- vm_gc_mark_obj (vm -> std );
177+ vm_gc_mark_obj (vm , vm -> std );
101178 for (vm_obj_t * head = vm -> base ; head < top ; head ++ ) {
102- vm_gc_mark_obj (* head );
179+ vm_gc_mark_obj (vm , * head );
103180 }
104- }
181+ vm_gc_mark_run ( vm );
105182
106- void vm_gc_sweep (vm_t * vm ) {
107- vm_gc_t * restrict gc = vm -> gc ;
108- size_t write = 0 ;
109- for (size_t i = 0 ; i < gc -> objs .len ; i ++ ) {
110- vm_obj_t obj = gc -> objs .objs [i ];
111- if (vm_obj_is_string (obj )) {
112- vm_io_buffer_t * buffer = vm_obj_get_string (obj );
113- if (!buffer -> mark ) {
114- vm_free (buffer -> buf );
115- vm_free (buffer );
116- } else {
117- buffer -> mark = false;
118- gc -> objs .objs [write ++ ] = obj ;
119- }
120- } else if (vm_obj_is_closure (obj )) {
121- vm_obj_closure_t * closure = vm_obj_get_closure (obj );
122- if (!closure -> mark ) {
123- vm_free (closure );
124- } else {
125- closure -> mark = false;
126- gc -> objs .objs [write ++ ] = obj ;
127- }
128- } else if (vm_obj_is_table (obj )) {
129- vm_obj_table_t * table = vm_obj_get_table (obj );
130- if (!table -> mark ) {
131- if (!table -> pairs_auto ) {
132- vm_free (table -> pairs );
133- }
134- vm_free (table );
135- } else {
136- table -> mark = false;
137- gc -> objs .objs [write ++ ] = obj ;
138- }
139- } else if (vm_obj_is_block (obj )) {
140- vm_ir_block_t * block = vm_obj_get_block (obj );
141- if (!block -> mark ) {
142- for (size_t j = 0 ; j < block -> len ; j ++ ) {
143- vm_ir_instr_t instr = block -> instrs [j ];
144- vm_free (instr .args );
145- }
146- vm_free (block -> instrs );
147- vm_free (block -> branch .args );
148- vm_free (block -> code );
149- vm_free (block );
150- } else {
151- block -> mark = false;
152- gc -> objs .objs [write ++ ] = obj ;
153- }
154- }
155- }
156- printf ("gc %zu -> %zu\n" , gc -> objs .len , write );
157- gc -> objs .len = write ;
158- size_t next = write * VM_GC_FACTOR ;
159- if (next >= gc -> last ) {
160- gc -> last = next ;
183+ printf ("%zu -> %zu\n" , vm_get_gc (vm )-> objs .len , vm_get_gc (vm )-> keep .len );
184+
185+ for (size_t i = 0 ; i < vm_get_gc (vm )-> objs .len ; i ++ ) {
186+ vm_gc_maybe_reset_obj (vm , vm_get_gc (vm )-> objs .objs [i ]);
161187 }
188+
189+ vm_gc_objs_t old_keep = vm_get_gc (vm )-> keep ;
190+ vm_gc_objs_t old_objs = vm_get_gc (vm )-> objs ;
191+ vm_get_gc (vm )-> objs = old_keep ;
192+ vm_get_gc (vm )-> keep = old_objs ;
193+
194+ vm_get_gc (vm )-> last = vm_get_gc (vm )-> objs .len * VM_GC_FACTOR ;
162195}
163196
164197vm_obj_table_t * vm_table_new (vm_t * vm ) {
165- vm_gc_t * restrict gc = vm -> gc ;
166198 vm_obj_table_t * ret = vm_malloc (sizeof (vm_obj_table_t ) + sizeof (vm_table_pair_t ) * vm_primes_table [0 ]);
167- ret -> pairs = ( vm_table_pair_t * ) & ret [ 1 ] ;
199+ ret -> pairs = vm_malloc ( sizeof ( vm_table_pair_t ) * vm_primes_table [ 0 ]) ;
168200 memset (ret -> pairs , VM_EMPTY_BYTE , sizeof (vm_table_pair_t ) * vm_primes_table [0 ]);
169201 ret -> size = 0 ;
170202 ret -> used = 0 ;
171203 ret -> len = 0 ;
172- ret -> mark = false;
173- ret -> pairs_auto = true;
204+ ret -> header .mark = false;
174205 vm_gc_add (vm , vm_obj_of_table (ret ));
175206 return ret ;
176207}
177208
178209void vm_gc_run (vm_t * vm , vm_obj_t * top ) {
179- vm_gc_t * restrict gc = vm -> gc ;
180- if (gc -> last >= gc -> objs .len ) {
210+ if (vm_get_gc (vm )-> last >= vm_get_gc (vm )-> objs .len ) {
181211 return ;
182212 }
183213 vm_gc_mark (vm , top );
184- vm_gc_sweep (vm );
185214}
186215
187216void vm_gc_init (vm_t * vm ) {
188217 vm -> gc = vm_malloc (sizeof (vm_gc_t ));
189- vm_gc_t * restrict gc = vm -> gc ;
190- * gc = (vm_gc_t ){
218+ * vm_get_gc (vm ) = (vm_gc_t ){
191219 .last = VM_GC_MIN ,
192220 };
193221}
194222
195223void vm_gc_deinit (vm_t * vm ) {
196- vm_gc_sweep (vm );
197- vm_gc_t * gc = vm -> gc ;
198- vm_free (gc -> objs .objs );
199- vm_free (vm -> gc );
224+ vm_gc_objs_free (& vm_get_gc (vm )-> objs );
225+ // vm_gc_objs_free(&gc->black);
226+ vm_free (vm_get_gc (vm ));
200227}
201228
202229void vm_gc_add (vm_t * vm , vm_obj_t obj ) {
203- vm_gc_t * restrict gc = vm -> gc ;
204- vm_gc_objs_add (& gc -> objs , obj );
230+ vm_gc_objs_push (& vm_get_gc (vm )-> objs , obj );
205231}
0 commit comments