1 |
/* |
2 |
stack - an interactive interpreter for a stack-based language |
3 |
Copyright (C) 2002 Mats Alritzson and Teddy Hogeborn |
4 |
|
5 |
This program is free software; you can redistribute it and/or modify |
6 |
it under the terms of the GNU General Public License as published by |
7 |
the Free Software Foundation; either version 2 of the License, or |
8 |
(at your option) any later version. |
9 |
|
10 |
This program is distributed in the hope that it will be useful, |
11 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 |
GNU General Public License for more details. |
14 |
|
15 |
You should have received a copy of the GNU General Public License |
16 |
along with this program; if not, write to the Free Software |
17 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 |
|
19 |
Authors: Mats Alritzson <masse@fukt.bth.se> |
20 |
Teddy Hogeborn <teddy@fukt.bth.se> |
21 |
*/ |
22 |
|
23 |
#include "stack.h" |
24 |
|
25 |
/* Mark values recursively. |
26 |
Marked values are not collected by the GC. */ |
27 |
inline void gc_mark(value *val) |
28 |
{ |
29 |
if(val==NULL || val->gc.flag.mark) |
30 |
return; |
31 |
|
32 |
val->gc.flag.mark= 1; |
33 |
|
34 |
if(val->type==tcons) { |
35 |
gc_mark(CAR(val)); |
36 |
gc_mark(CDR(val)); |
37 |
} |
38 |
} |
39 |
|
40 |
|
41 |
/* Start GC */ |
42 |
extern void gc_init(environment *env) |
43 |
{ |
44 |
stackitem *new_head= NULL, *titem; |
45 |
symbol *tsymb; |
46 |
int i; |
47 |
|
48 |
if(env->interactive) |
49 |
printf("Garbage collecting."); |
50 |
|
51 |
/* Mark values on stack */ |
52 |
gc_mark(env->head); |
53 |
|
54 |
if(env->interactive) |
55 |
printf("."); |
56 |
|
57 |
/* Mark values in hashtable */ |
58 |
for(i= 0; i<HASHTBLSIZE; i++) |
59 |
for(tsymb= env->symbols[i]; tsymb!=NULL; tsymb= tsymb->next) |
60 |
if (tsymb->val != NULL) |
61 |
gc_mark(tsymb->val); |
62 |
|
63 |
if(env->interactive) |
64 |
printf("."); |
65 |
|
66 |
env->gc_count= 0; |
67 |
|
68 |
while(env->gc_ref!=NULL) { /* Sweep unused values */ |
69 |
if(!(env->gc_ref->item->gc.no_gc)){ /* neither mark nor protect */ |
70 |
|
71 |
/* Remove content */ |
72 |
switch(env->gc_ref->item->type){ |
73 |
case string: |
74 |
free(env->gc_ref->item->content.string); |
75 |
break; |
76 |
case tcons: |
77 |
free(env->gc_ref->item->content.c); |
78 |
break; |
79 |
case port: |
80 |
case empty: |
81 |
case unknown: |
82 |
case integer: |
83 |
case tfloat: |
84 |
case func: |
85 |
case symb: |
86 |
/* Symbol strings are freed when walking the hash table */ |
87 |
break; |
88 |
} |
89 |
|
90 |
free(env->gc_ref->item); /* Remove from gc_ref */ |
91 |
titem= env->gc_ref->next; |
92 |
free(env->gc_ref); /* Remove value */ |
93 |
env->gc_ref= titem; |
94 |
continue; |
95 |
} |
96 |
|
97 |
#ifdef DEBUG |
98 |
printf("Kept value (%p)", env->gc_ref->item); |
99 |
if(env->gc_ref->item->gc.flag.mark) |
100 |
printf(" (marked)"); |
101 |
if(env->gc_ref->item->gc.flag.protect) |
102 |
printf(" (protected)"); |
103 |
switch(env->gc_ref->item->type){ |
104 |
case integer: |
105 |
printf(" integer: %d", env->gc_ref->item->content.i); |
106 |
break; |
107 |
case func: |
108 |
printf(" func: %p", env->gc_ref->item->content.func); |
109 |
break; |
110 |
case symb: |
111 |
printf(" symb: %s", env->gc_ref->item->content.sym->id); |
112 |
break; |
113 |
case tcons: |
114 |
printf(" tcons: %p\t%p", CAR(env->gc_ref->item), |
115 |
CDR(env->gc_ref->item)); |
116 |
break; |
117 |
default: |
118 |
printf(" <unknown %d>", (env->gc_ref->item->type)); |
119 |
} |
120 |
printf("\n"); |
121 |
#endif /* DEBUG */ |
122 |
|
123 |
/* Keep values */ |
124 |
env->gc_count += sizeof(value); |
125 |
if(env->gc_ref->item->type==string) |
126 |
env->gc_count += strlen(env->gc_ref->item->content.string)+1; |
127 |
|
128 |
titem= env->gc_ref->next; |
129 |
env->gc_ref->next= new_head; |
130 |
new_head= env->gc_ref; |
131 |
new_head->item->gc.flag.mark= 0; |
132 |
env->gc_ref= titem; |
133 |
} |
134 |
|
135 |
if (env->gc_limit < env->gc_count*2) |
136 |
env->gc_limit= env->gc_count*2; |
137 |
|
138 |
env->gc_ref= new_head; |
139 |
|
140 |
if(env->interactive) |
141 |
printf("done (%d bytes still allocated)\n", env->gc_count); |
142 |
|
143 |
} |
144 |
|
145 |
|
146 |
inline void gc_maybe(environment *env) |
147 |
{ |
148 |
if(env->gc_count < env->gc_limit) |
149 |
return; |
150 |
else |
151 |
return gc_init(env); |
152 |
} |
153 |
|
154 |
|
155 |
/* Protect values from GC */ |
156 |
void protect(value *val) |
157 |
{ |
158 |
if(val==NULL || val->gc.flag.protect) |
159 |
return; |
160 |
|
161 |
val->gc.flag.protect= 1; |
162 |
|
163 |
if(val->type==tcons) { |
164 |
protect(CAR(val)); |
165 |
protect(CDR(val)); |
166 |
} |
167 |
} |
168 |
|
169 |
|
170 |
/* Unprotect values from GC */ |
171 |
void unprotect(value *val) |
172 |
{ |
173 |
if(val==NULL || !(val->gc.flag.protect)) |
174 |
return; |
175 |
|
176 |
val->gc.flag.protect= 0; |
177 |
|
178 |
if(val->type==tcons) { |
179 |
unprotect(CAR(val)); |
180 |
unprotect(CDR(val)); |
181 |
} |
182 |
} |