root/src/gg_garbage.c

Revision 20d93fb737c36e2fa36fb1e9ac36734be14a77c6, 11.1 kB (checked in by redbrain <redbrain@…>, 2 years ago)

fixed return address garbage collection and a signed vs unsigned ref count issue

  • Property mode set to 100644
Line 
1/**
2 * gg_garbage.c -> Part of Crules Programming language
3 *
4 * Crules is the legal property of its developers. Please refer to the
5 * COPYRIGHT file distributed with this source distribution.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 **/
20
21#ifdef HAVE_CONFIG_H
22# include "config.h"
23#else
24# define CMAKE 1
25# include "config.h.cmake"
26#endif
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31
32#include <gmp.h>
33#include <mpfr.h>
34
35#include <crules/crules.h>
36#include <crules/opcodes.h>
37#include <crules/symbols.h>
38#include <crules/objects.h>
39#include <crules/backend.h>
40#include <crules/runtime.h>
41#include <crules/garbage.h>
42#include <crules/operators.h>
43
44#define Crl_Free_Table_Quick( x )                       \
45  if( x ) { if( x->array ) { crl_free( x->array); }     \
46    crl_free( x ); }
47
48typedef struct crl_symbol_node_t {
49  crl_symbol_obj * object;
50  struct crl_symbol_node_t *next;
51} crl_sym_node_t ;
52
53typedef struct crl_symbol_stack {
54  unsigned int length;
55  crl_sym_node_t * head;
56  crl_sym_node_t * tail;
57} crl_sym_stack_t ;
58
59/* Declare the tables */
60extern crl_stack_t * crl_parse_stk, * crl_lex_stack;
61extern crl_context_table * crl_runtime_ctx_table;
62
63static crl_stack_t * crl_runtime_gbg = NULL;
64static crl_sym_stack_t * crl_object_table = NULL;
65
66static void free_hash_table_symbols( crl_table_t ** );
67
68void crl_garbage_push_object( crl_symbol_obj * obj )
69{
70  if( obj )
71    {
72      crl_debug("pushing object <%p>!\n", (void *) obj );
73
74      if( !crl_object_table )
75        {
76          crl_object_table = (crl_sym_stack_t *)
77            crl_malloc( sizeof(crl_sym_stack_t) );
78          crl_object_table->length = 0;
79          crl_object_table->head = NULL;
80          crl_object_table->tail = NULL;
81        }
82
83      crl_object_table->length++;
84      if( !(crl_object_table->head) )
85        {
86          crl_sym_node_t *o = (crl_sym_node_t *)
87            crl_malloc( sizeof(crl_sym_node_t) );
88          o->object = obj;
89          o->next = NULL;
90
91          crl_object_table->head = o;
92        }
93
94      crl_sym_node_t * o = (crl_sym_node_t *)
95        crl_malloc( sizeof(crl_sym_node_t) );
96      o->object = obj;
97      o->next = NULL;
98
99      crl_object_table->head->next = o;
100      crl_object_table->tail = o;
101    }
102  else
103    {
104      crl_warning("invalid object <%p>!\n", (void *) obj );
105    }
106}
107
108void crl_garbage_lex_free( void )
109{
110  if( crl_lex_stack )
111    {
112      char * o;
113      while( (o= crl_dd_stack_pop( crl_lex_stack )) )
114        {
115          crl_free( o );
116        }
117      crl_dd_stack_free( crl_lex_stack );
118      crl_lex_stack= NULL;
119    }
120}
121
122void crl_garbage_invoke( void )
123{
124  if( crl_runtime_gbg )
125    {
126      crl_debug("garbage collector running...\n");
127      crl_symbol_obj *p_obj = NULL;
128
129      while( (p_obj= crl_dd_stack_pop( crl_runtime_gbg)) )
130        {
131          crl_garbage_free_obj( &p_obj );
132        }
133      crl_dd_stack_free( crl_runtime_gbg );
134      crl_runtime_gbg = NULL;
135    }
136}
137
138void crl_garbage_mark_obj__( crl_symbol_obj ** const sym )
139{
140  if( sym )
141    {
142      if( crl_runtime_gbg )
143        {
144          crl_dd_stack_push( crl_runtime_gbg, (*sym) );
145        }
146      else
147        {
148          crl_runtime_gbg= (crl_stack_t *)
149            crl_malloc(sizeof(crl_stack_t));
150          crl_dd_stack_init( &crl_runtime_gbg );
151
152          crl_dd_stack_push( crl_runtime_gbg, (*sym) );
153        }
154    }
155}
156
157void crl_garbage_invoke_sweep( crl_context_table * context )
158{
159  unsigned int ctx_l = crl_rr_context_get_table_size( context );
160  if( context )
161    {
162      crl_debug("sweeping context table for garbage length <%u>...\n", ctx_l);
163      crl_branch_context* ctx_idx = NULL; signed int idx = (ctx_l - 1);
164
165      while( idx >= 0 )
166        {
167          ctx_idx = context->array[ idx ];
168          void ** s_arr = ctx_idx->symbol_stack->array;
169
170          int i = 0; unsigned int len = (ctx_idx->symbol_stack->length);
171          crl_debug("stack length = <%u>!\n", len );
172          for( ; i<len; ++i )
173            {
174              crl_symbol_obj * o = (crl_symbol_obj *) s_arr[ i ];
175              if( o )
176                {
177                  crl_debug( "object <%p> has ref count <%u>!\n",
178                             (void *) o, o->n_ref );
179
180                  // If no references remain
181                  if( o->n_ref <= 0 )
182                    {
183                      crl_garbage_mark_obj( &o );
184                      s_arr[ i ] = NULL;
185                    }
186                }
187            }
188          idx--;
189        }
190    }
191  crl_garbage_invoke( );
192}
193
194
195/* Cleanup the program for exit! */
196bool crl_cleanup( void )
197{
198  crl_debug("cleanup.......\n");
199#ifdef DEBUG
200  crl_print_stats( );
201#endif
202
203  crl_destroy_lexer( );
204
205  crl_garbage_lex_free( );
206
207  mpfr_free_cache( );
208
209  if( crl_runtime_ctx_table )
210    {
211      crl_debug("freeing runtime context!\n");
212      crl_garbage_free_context_table( &crl_runtime_ctx_table );
213      crl_debug("done!\n");
214    }
215
216  if( crl_parse_stk )
217    {
218      crl_debug("freeing parse stk!\n");
219      crl_dd_stack_free( crl_parse_stk );
220      crl_debug("done!\n");
221    }
222
223#ifdef DEBUG
224  crl_print_stats( );
225#endif
226  return true;
227}
228
229void crl_garbage_free_obj( crl_symbol_obj ** sym )
230{
231  if( sym )
232    {
233      crl_debug("deleting object <%p>!\n", (void *) (*sym) );
234
235      if( (*sym)->identifier )
236        {
237          crl_debug("garbage symbol identifier '%s'\n", (*sym)->identifier );
238          crl_free( (*sym)->identifier );
239        }
240
241      switch( (*sym)->op_a_t )
242        {
243        case TYPE_LIST:
244          crl_fatal("not implemented yet!\n");
245          break;
246
247        case TYPE_STRING:
248          if( (*sym)->op_a.string )
249            {
250              char *xstr= (char*) (*sym)->op_a.string;
251              crl_free( xstr );
252            }
253          break;
254
255        case TYPE_SYMBOL:
256          crl_garbage_free_obj( &((*sym)->op_a.symbol_table) );
257          break;
258
259        case TYPE_OBJECT:
260          if( (*sym)->op_a.object_state )
261            {
262              crl_obj_state_t * o = (*sym)->op_a.object_state;
263              // dont free the definition its used as a reference
264              // to the definition hooks!!!
265              struct crl_type_obj_def_t *def = (*(o->definition));
266              crl_free( o->identifier );
267              if( o->self )
268                {
269                  def->destroy_hook( o->self );
270                }
271              // crl_garbage_free_context_branch( &(o->context) );
272              crl_free( o );
273            }
274          break;
275
276        case STRUCTURE_OBJECT_DEF:
277          if( (*sym)->op_a.object_def )
278            {
279              struct crl_type_obj_def_t * o = (*sym)->op_a.object_def;
280              crl_debug("freeing object definition <%s>!\n", o->identifier );
281              crl_free( o->identifier );
282              crl_garbage_free_context_branch( NULL, (o->context) );
283              if( o->binary_protocol )
284                {
285                  crl_free( o->binary_protocol );
286                }
287              crl_free( o );
288            }
289          break;
290
291        case TYPE_BUILTIN_CALLBACK:
292          if( (*sym)->op_a.callback )
293            {
294              struct crl_builtin_function_def_t * call = (*sym)->op_a.callback;
295              crl_free( call->identifier );
296              crl_free( call );
297            }
298          break;
299
300        case TYPE_PARAMETERS:
301          if( (*sym)->op_a.stack_table )
302            {
303              crl_stack_t *p = (*sym)->op_a.stack_table;
304              crl_symbol_obj * o = NULL;
305              while( (o= (crl_symbol_obj*) crl_dd_stack_pop( p ) ) )
306                {
307                  printf("freeing param!\n\n");
308                  char * i = o->op_a.string;
309                  crl_free( i );
310                  crl_free( o );
311                }
312              crl_dd_stack_free( p );
313            }
314          break;
315
316        default:
317          break;
318        }
319
320      switch( (*sym)->op_b_t )
321        {
322        case TYPE_LIST:
323          crl_fatal("not implemented yet!\n");
324          break;
325
326        case TYPE_STRING:
327          if( (*sym)->op_b.string )
328            {
329              char *xstr= (char*) (*sym)->op_b.string;
330              crl_free( xstr );
331            }
332          break;
333
334        case TYPE_SYMBOL:
335          crl_garbage_free_obj( &((*sym)->op_b.symbol_table) );
336          break;
337
338        case TYPE_PARAMETERS:
339          if( (*sym)->op_b.stack_table )
340            {
341              crl_stack_t *p = (*sym)->op_b.stack_table;
342              crl_symbol_obj * o = NULL;
343              while( (o= (crl_symbol_obj*) crl_dd_stack_pop( p )) )
344                {
345                  char * i = o->op_a.string;
346                  crl_free( i );
347                  crl_free( o );
348                }
349              crl_dd_stack_free( p );
350            }
351          break;
352
353        case TYPE_ARGUMENTS:
354          if( (*sym)->op_b.stack_table )
355            {
356              crl_stack_t *t= (*sym)->op_b.stack_table;
357              crl_symbol_obj * o= crl_dd_stack_pop( t );
358              while( o )
359                {
360                  crl_garbage_free_obj( &o );
361                  o= crl_dd_stack_pop( t );
362                }
363              crl_dd_stack_free( t );
364            }
365          break;
366
367        default:
368          break;
369        }
370
371      if( (*sym)->next )
372        crl_garbage_free_obj( &((*sym)->next) );
373
374      // free this object finally!
375      crl_free( (*sym) );
376      (*sym) = NULL;
377    }
378  else
379    {
380      // just in-case to give us warnings if this happens
381      crl_warning( "freeing null symbol at address <%p>!\n",
382                   (void*)(sym) );
383    }
384}
385
386void crl_garbage_free_hash_table( crl_table_t ** table )
387{
388  crl_debug("freeing hash table!\n");
389  free_hash_table_symbols( table );
390  crl_free( (*table) );
391}
392
393static
394void free_hash_table_symbols( crl_table_t ** table )
395{
396  if( table )
397    {
398      crl_debug("free_hash_table_symbols!\n");
399      unsigned int idx = 0;
400      crl_table_entry *array= (*table)->array;
401      if( array )
402        {
403          for( ; idx<(*table)->size; ++idx )
404            {
405              crl_symbol_obj *sym= array[ idx ].symbol;
406              if( sym ) {
407                crl_garbage_free_obj( &sym );
408              }
409            }
410          crl_free( (*table)->array );
411        }
412      (*table)->array = NULL;
413      (*table)->size = 0;
414      (*table)->nr = 0;
415    }
416  else
417    {
418      crl_error("freeing null hash table!\n");
419    }
420}
421
422void crl_garbage_free_context_branch( crl_branch_context * head,
423                                      crl_branch_context * ctx )
424{
425  if( ctx )
426    {
427      Crl_Free_Table_Quick( ctx->symbol_table );
428      Crl_Free_Table_Quick( ctx->function_table );
429      Crl_Free_Table_Quick( ctx->object_table );
430
431      void ** s_arr = ctx->symbol_stack->array;
432      unsigned int idx = 0, straggers = 0; crl_symbol_obj *it = NULL;
433      for( ; idx<ctx->symbol_stack->length; ++idx )
434        {
435          it = (crl_symbol_obj*) s_arr[ idx ];
436          if( it )
437            {
438              if( it->n_ref <= 0 )
439                {
440                  crl_debug("marking object <%p>!\n", (void*)it );
441                  crl_garbage_mark_obj( &it );
442                  s_arr[ idx ] = NULL;
443                }
444            }
445        }
446
447      idx = 0; // reset to loop over for any stragglers!
448      for( ; idx<ctx->symbol_stack->length; ++idx )
449        {
450          it = (crl_symbol_obj*) s_arr[ idx ];
451          if( it )
452            {
453              if( head )
454                {
455                  // push this into the the other ctx!
456                  crl_debug("pushing up object <%p> ref count <%i>!\n",
457                            (void*)it, it->n_ref );
458                  crl_dd_stack_push( head->symbol_stack, it );
459                  s_arr[idx] = NULL;
460                }
461              else
462                {
463                  straggers++;
464                  crl_debug("stragger object <%p> with ref count <%i>!\n",
465                            (void*)it, it->n_ref);
466                }
467            }
468        }
469      // finally free the context!
470      crl_free( ctx );
471    }
472  else {
473    crl_fatal("null context branch frame!\n");
474  }
475}
476
477void crl_garbage_free_context_table( crl_context_table ** stack )
478{
479  signed int len= crl_rr_context_get_table_size( *stack );
480  crl_debug("stack frame size :: '%i'!\n", len );
481  crl_branch_context* table = NULL;
482
483  while( (table = crl_rr_context_pop( (*stack),true )) )
484    {
485      if( table )
486        {
487          crl_garbage_free_context_branch( Crl_Ctx_Head_Branch((*stack)), table );
488        }
489    }
490
491  if( ((*stack)->array) ) {
492    crl_free( ((*stack)->array) );
493  }
494  crl_free( (*stack) );
495}
Note: See TracBrowser for help on using the browser.