source: abuse/trunk/src/lisp/lisp_gc.cpp @ 555

Last change on this file since 555 was 555, checked in by Sam Hocevar, 11 years ago

ps3: make everything compile on the PS3. Of course, nothing links yet
because so much support is missing.

File size: 7.1 KB
RevLine 
[56]1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
[494]4 *  Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
[56]5 *
6 *  This software was released into the Public Domain. As with most public
[555]7 *  domain software, no warranty is made or implied by Crack dot Com, by
8 *  Jonathan Clark, or by Sam Hocevar.
[56]9 */
[2]10
[555]11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
[2]14
[56]15#include <stdlib.h>
16#include <string.h>
[2]17
[481]18#include "lisp.h"
[491]19#include "lisp_gc.h"
[2]20#ifdef NO_LIBS
[481]21#include "fakelib.h"
[2]22#endif
23
[481]24#include "stack.h"
[2]25
[480]26/*  Lisp garbage collection: uses copy/free algorithm
27    Places to check:
[124]28      symbol
[56]29        values
[124]30    functions
31    names
[56]32      stack
33*/
[2]34
[75]35// Stack where user programs can push data and have it GCed
36grow_stack<void> l_user_stack(150);
37// Stack of user pointers
[491]38grow_stack<void *> PtrRef::stack(1500);
[2]39
[480]40size_t reg_ptr_total = 0;
41size_t reg_ptr_list_size = 0;
[75]42void ***reg_ptr_list = NULL;
[2]43
[480]44static uint8_t *cstart, *cend, *collected_start, *collected_end;
45
[2]46void register_pointer(void **addr)
47{
[480]48  if (reg_ptr_total >= reg_ptr_list_size)
[2]49  {
[480]50    reg_ptr_list_size += 0x100;
51    reg_ptr_list = (void ***)realloc(reg_ptr_list, sizeof(void **) * reg_ptr_list_size);
[2]52  }
[480]53  reg_ptr_list[reg_ptr_total++] = addr;
[2]54}
55
56void unregister_pointer(void **addr)
57{
[480]58  void ***reg_on = reg_ptr_list;
59  for (size_t i = 0; i < reg_ptr_total; i++, reg_on++)
[2]60  {
[480]61    if (*reg_on == addr)
[2]62    {
63      reg_ptr_total--;
[480]64      for (size_t j = i; j < reg_ptr_total; j++, reg_on++)
65        reg_on[0] = reg_on[1];
[2]66      return ;
67    }
68  }
[480]69  fprintf(stderr, "Unable to locate ptr to unregister");
[2]70}
71
[492]72static LObject *CollectObject(LObject *x);
[491]73
[492]74static LArray *CollectArray(LArray *x)
[2]75{
[493]76    size_t s = x->len;
[492]77    LArray *a = LArray::Create(s, NULL);
78    LObject **src = x->GetData();
79    LObject **dst = a->GetData();
[491]80    for (size_t i = 0; i < s; i++)
81        dst[i] = CollectObject(src[i]);
[2]82
[483]83    return a;
[2]84}
85
[492]86inline LList *CollectList(LList *x)
[2]87{
[492]88    LList *last = NULL, *first = NULL;
[2]89
[491]90    for (; x && item_type(x) == L_CONS_CELL; )
91    {
[492]92        LList *p = LList::Create();
93        LObject *old_car = x->car;
94        LObject *old_cdr = x->cdr;
95        LObject *old_x = x;
96        x = (LList *)CDR(x);
97        ((LRedirect *)old_x)->type = L_COLLECTED_OBJECT;
[493]98        ((LRedirect *)old_x)->ref = p;
[490]99
[491]100        p->car = CollectObject(old_car);
101        p->cdr = CollectObject(old_cdr);
102
103        if (last)
104            last->cdr = p;
105        else
106            first = p;
107        last = p;
108    }
109    if (x)
110        last->cdr = CollectObject(x);
111    return first; // we already set the collection pointers
[2]112}
113
[492]114static LObject *CollectObject(LObject *x)
[2]115{
[492]116  LObject *ret = x;
[2]117
[480]118  if (((uint8_t *)x) >= cstart && ((uint8_t *)x) < cend)
[2]119  {
120    switch (item_type(x))
121    {
[480]122      case L_BAD_CELL:
123        lbreak("error: GC corrupted cell\n");
124        break;
125      case L_NUMBER:
[492]126        ret = LNumber::Create(((LNumber *)x)->num);
[480]127        break;
128      case L_SYS_FUNCTION:
[492]129        ret = new_lisp_sys_function(((LSysFunction *)x)->min_args,
130                                    ((LSysFunction *)x)->max_args,
131                                    ((LSysFunction *)x)->fun_number);
[480]132        break;
133      case L_USER_FUNCTION:
[501]134      {
135        LUserFunction *fun = (LUserFunction *)x;
136        LList *arg = (LList *)CollectObject(fun->arg_list);
137        LList *block = (LList *)CollectObject(fun->block_list);
138        ret = new_lisp_user_function(arg, block);
[480]139        break;
[501]140      }
[480]141      case L_STRING:
[492]142        ret = LString::Create(lstring_value(x));
[480]143        break;
144      case L_CHARACTER:
[493]145        ret = LChar::Create(lcharacter_value(x));
[480]146        break;
147      case L_C_FUNCTION:
[492]148        ret = new_lisp_c_function(((LSysFunction *)x)->min_args,
149                                  ((LSysFunction *)x)->max_args,
150                                  ((LSysFunction *)x)->fun_number);
[480]151        break;
152      case L_C_BOOL:
[492]153        ret = new_lisp_c_bool(((LSysFunction *)x)->min_args,
154                              ((LSysFunction *)x)->max_args,
155                              ((LSysFunction *)x)->fun_number);
[480]156        break;
157      case L_L_FUNCTION:
[492]158        ret = new_user_lisp_function(((LSysFunction *)x)->min_args,
159                                     ((LSysFunction *)x)->max_args,
160                                     ((LSysFunction *)x)->fun_number);
[480]161        break;
162      case L_POINTER:
[493]163        ret = LPointer::Create(lpointer_value(x));
[480]164        break;
165      case L_1D_ARRAY:
[492]166        ret = CollectArray((LArray *)x);
[480]167        break;
168      case L_FIXED_POINT:
[493]169        ret = LFixedPoint::Create(lfixed_point_value(x));
[480]170        break;
171      case L_CONS_CELL:
[492]172        ret = CollectList((LList *)x);
[480]173        break;
174      case L_OBJECT_VAR:
[493]175        ret = LObjectVar::Create(((LObjectVar *)x)->index);
[480]176        break;
177      case L_COLLECTED_OBJECT:
[493]178        ret = ((LRedirect *)x)->ref;
[480]179        break;
180      default:
[553]181        lbreak("shouldn't happen. collecting bad object 0x%x\n", item_type(x));
[480]182        break;
[2]183    }
[492]184    ((LRedirect *)x)->type = L_COLLECTED_OBJECT;
[493]185    ((LRedirect *)x)->ref = ret;
[480]186  }
187  else if ((uint8_t *)x < collected_start || (uint8_t *)x >= collected_end)
[2]188  {
[480]189    if (item_type(x) == L_CONS_CELL) // still need to remap cons_cells outside of space
[2]190    {
[480]191      for (; x && item_type(x) == L_CONS_CELL; x = CDR(x))
[492]192        ((LList *)x)->car = CollectObject(((LList *)x)->car);
[2]193      if (x)
[492]194        ((LList *)x)->cdr = CollectObject(((LList *)x)->cdr);
[2]195    }
196  }
197
198  return ret;
199}
200
[492]201static void collect_symbols(LSymbol *root)
[2]202{
[493]203    if (!root)
204        return;
205
[491]206    root->value = CollectObject(root->value);
207    root->function = CollectObject(root->function);
[492]208    root->name = (LString *)CollectObject(root->name);
[2]209    collect_symbols(root->left);
210    collect_symbols(root->right);
211}
212
213static void collect_stacks()
214{
[480]215  long t = l_user_stack.son;
[2]216
[480]217  void **d = l_user_stack.sdata;
218  for (int i = 0; i < t; i++, d++)
[492]219    *d = CollectObject((LObject *)*d);
[480]220
[491]221  t = PtrRef::stack.son;
222  void ***d2 = PtrRef::stack.sdata;
[480]223  for (int i = 0; i < t; i++, d2++)
[2]224  {
[480]225    void **ptr = *d2;
[492]226    *ptr = CollectObject((LObject *)*ptr);
[2]227  }
228
[480]229  d2 = reg_ptr_list;
230  for (size_t i = 0; i < reg_ptr_total; i++, d2++)
[2]231  {
[480]232    void **ptr = *d2;
[492]233    *ptr = CollectObject((LObject *)*ptr);
[124]234  }
[2]235}
236
[554]237void collect_space(int which_space, int grow) // should be tmp or permanent
[2]238{
[480]239  int old_space = current_space;
240  cstart = space[which_space];
241  cend = free_space[which_space];
[2]242
[480]243  space_size[GC_SPACE] = space_size[which_space];
[554]244  if (grow)
245  {
246    space_size[GC_SPACE] += space_size[which_space] >> 1;
247    space_size[GC_SPACE] -= (space_size[GC_SPACE] & 7);
248  }
[480]249  uint8_t *new_space = (uint8_t *)malloc(space_size[GC_SPACE]);
250  current_space = GC_SPACE;
251  free_space[GC_SPACE] = space[GC_SPACE] = new_space;
[2]252
[480]253  collected_start = new_space;
254  collected_end = new_space + space_size[GC_SPACE];
[2]255
[493]256  collect_symbols(LSymbol::root);
[2]257  collect_stacks();
258
[480]259  // for debuging clear it out
260  memset(space[which_space], 0, space_size[which_space]);
[129]261  free(space[which_space]);
[2]262
[480]263  space[which_space] = new_space;
[554]264  space_size[which_space] = space_size[GC_SPACE];
[480]265  free_space[which_space] = new_space
266                          + (free_space[GC_SPACE] - space[GC_SPACE]);
267  current_space = old_space;
[2]268}
269
Note: See TracBrowser for help on using the repository browser.