Commit | Line | Data |
---|---|---|
c8a1bdc4 HWN |
1 | /* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002 Free Software Foundation, Inc. |
2 | * | |
3 | * This program is free software; you can redistribute it and/or modify | |
4 | * it under the terms of the GNU General Public License as published by | |
5 | * the Free Software Foundation; either version 2, or (at your option) | |
6 | * any later version. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | * GNU General Public License for more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License | |
14 | * along with this software; see the file COPYING. If not, write to | |
15 | * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |
16 | * Boston, MA 02111-1307 USA | |
17 | * | |
18 | * As a special exception, the Free Software Foundation gives permission | |
19 | * for additional uses of the text contained in its release of GUILE. | |
20 | * | |
21 | * The exception is that, if you link the GUILE library with other files | |
22 | * to produce an executable, this does not by itself cause the | |
23 | * resulting executable to be covered by the GNU General Public License. | |
24 | * Your use of that executable is in no way restricted on account of | |
25 | * linking the GUILE library code into it. | |
26 | * | |
27 | * This exception does not however invalidate any other reasons why | |
28 | * the executable file might be covered by the GNU General Public License. | |
29 | * | |
30 | * This exception applies only to the code released by the | |
31 | * Free Software Foundation under the name GUILE. If you copy | |
32 | * code from other Free Software Foundation releases into a copy of | |
33 | * GUILE, as the General Public License permits, the exception does | |
34 | * not apply to the code that you add in this way. To avoid misleading | |
35 | * anyone as to the status of such modified files, you must delete | |
36 | * this exception notice from them. | |
37 | * | |
38 | * If you write modifications of your own for GUILE, it is your choice | |
39 | * whether to permit this exception to apply to your modifications. | |
40 | * If you do not wish that, delete this exception notice. */ | |
41 | ||
42 | ||
be3ff021 HWN |
43 | #include <stdio.h> |
44 | ||
c8a1bdc4 HWN |
45 | #include "libguile/_scm.h" |
46 | #include "libguile/eval.h" | |
47 | #include "libguile/stime.h" | |
48 | #include "libguile/stackchk.h" | |
49 | #include "libguile/struct.h" | |
50 | #include "libguile/smob.h" | |
51 | #include "libguile/unif.h" | |
52 | #include "libguile/async.h" | |
53 | #include "libguile/ports.h" | |
54 | #include "libguile/root.h" | |
55 | #include "libguile/strings.h" | |
56 | #include "libguile/vectors.h" | |
57 | #include "libguile/weaks.h" | |
58 | #include "libguile/hashtab.h" | |
59 | #include "libguile/tags.h" | |
60 | #include "libguile/private-gc.h" | |
61 | #include "libguile/validate.h" | |
62 | #include "libguile/deprecation.h" | |
63 | #include "libguile/gc.h" | |
64 | ||
65 | ||
66 | #include "libguile/private-gc.h" | |
67 | ||
68 | long int scm_i_deprecated_memory_return; | |
69 | ||
70 | ||
71 | /* | |
72 | Init all the free cells in CARD, prepending to *FREE_LIST. | |
73 | ||
74 | Return: number of free cells found in this card. | |
75 | ||
76 | It would be cleaner to have a separate function sweep_value(), but | |
77 | that is too slow (functions with switch statements can't be | |
78 | inlined). | |
79 | ||
80 | */ | |
81 | ||
82 | int | |
1383773b | 83 | scm_i_sweep_card (scm_t_cell * p, SCM *free_list, scm_t_heap_segment*seg) |
c8a1bdc4 HWN |
84 | #define FUNC_NAME "sweep_card" |
85 | { | |
86 | scm_t_c_bvec_long *bitvec = SCM_GC_CARD_BVEC(p); | |
87 | scm_t_cell * end = p + SCM_GC_CARD_N_CELLS; | |
1383773b | 88 | int span = seg->span; |
c8a1bdc4 HWN |
89 | int offset =SCM_MAX (SCM_GC_CARD_N_HEADER_CELLS, span); |
90 | int free_count = 0; | |
91 | ||
eab1b259 HWN |
92 | ++ scm_gc_running_p; |
93 | ||
c8a1bdc4 HWN |
94 | /* |
95 | I tried something fancy with shifting by one bit every word from | |
96 | the bitvec in turn, but it wasn't any faster, but quite bit | |
97 | hairier. | |
98 | */ | |
99 | for (p += offset; p < end; p += span, offset += span) | |
100 | { | |
101 | SCM scmptr = PTR2SCM(p); | |
102 | if (SCM_C_BVEC_GET (bitvec, offset)) | |
103 | continue; | |
104 | ||
105 | switch (SCM_TYP7 (scmptr)) | |
106 | { | |
107 | case scm_tcs_struct: | |
108 | { | |
109 | /* Structs need to be freed in a special order. | |
110 | * This is handled by GC C hooks in struct.c. | |
111 | */ | |
112 | SCM_SET_STRUCT_GC_CHAIN (p, scm_structs_to_free); | |
113 | scm_structs_to_free = scmptr; | |
114 | } | |
115 | continue; | |
116 | ||
117 | case scm_tcs_cons_imcar: | |
118 | case scm_tcs_cons_nimcar: | |
119 | case scm_tcs_closures: | |
120 | case scm_tc7_pws: | |
121 | break; | |
122 | case scm_tc7_wvect: | |
123 | case scm_tc7_vector: | |
124 | { | |
125 | unsigned long int length = SCM_VECTOR_LENGTH (scmptr); | |
126 | if (length > 0) | |
127 | { | |
128 | scm_gc_free (SCM_VECTOR_BASE (scmptr), | |
129 | length * sizeof (scm_t_bits), | |
130 | "vector"); | |
131 | } | |
132 | break; | |
133 | } | |
134 | #ifdef CCLO | |
135 | case scm_tc7_cclo: | |
136 | scm_gc_free (SCM_CCLO_BASE (scmptr), | |
137 | SCM_CCLO_LENGTH (scmptr) * sizeof (SCM), | |
138 | "compiled closure"); | |
139 | break; | |
140 | #endif | |
141 | #ifdef HAVE_ARRAYS | |
142 | case scm_tc7_bvect: | |
143 | { | |
144 | unsigned long int length = SCM_BITVECTOR_LENGTH (scmptr); | |
145 | if (length > 0) | |
146 | { | |
147 | scm_gc_free (SCM_BITVECTOR_BASE (scmptr), | |
148 | (sizeof (long) | |
149 | * ((length+SCM_LONG_BIT-1) / SCM_LONG_BIT)), | |
150 | "vector"); | |
151 | } | |
152 | } | |
153 | break; | |
154 | case scm_tc7_byvect: | |
155 | case scm_tc7_ivect: | |
156 | case scm_tc7_uvect: | |
157 | case scm_tc7_svect: | |
158 | #ifdef HAVE_LONG_LONGS | |
159 | case scm_tc7_llvect: | |
160 | #endif | |
161 | case scm_tc7_fvect: | |
162 | case scm_tc7_dvect: | |
163 | case scm_tc7_cvect: | |
164 | scm_gc_free (SCM_UVECTOR_BASE (scmptr), | |
165 | (SCM_UVECTOR_LENGTH (scmptr) | |
166 | * scm_uniform_element_size (scmptr)), | |
167 | "vector"); | |
168 | break; | |
169 | #endif | |
170 | case scm_tc7_string: | |
171 | scm_gc_free (SCM_STRING_CHARS (scmptr), | |
172 | SCM_STRING_LENGTH (scmptr) + 1, "string"); | |
173 | break; | |
174 | case scm_tc7_symbol: | |
175 | scm_gc_free (SCM_SYMBOL_CHARS (scmptr), | |
176 | SCM_SYMBOL_LENGTH (scmptr) + 1, "symbol"); | |
177 | break; | |
178 | case scm_tc7_variable: | |
179 | break; | |
180 | case scm_tcs_subrs: | |
181 | /* the various "subrs" (primitives) are never freed */ | |
182 | continue; | |
183 | case scm_tc7_port: | |
184 | if SCM_OPENP (scmptr) | |
185 | { | |
186 | int k = SCM_PTOBNUM (scmptr); | |
187 | size_t mm; | |
188 | #if (SCM_DEBUG_CELL_ACCESSES == 1) | |
189 | if (!(k < scm_numptob)) | |
be3ff021 HWN |
190 | { |
191 | fprintf (stderr, "undefined port type"); | |
192 | abort(); | |
193 | } | |
c8a1bdc4 HWN |
194 | #endif |
195 | /* Keep "revealed" ports alive. */ | |
196 | if (scm_revealed_count (scmptr) > 0) | |
197 | continue; | |
198 | ||
199 | /* Yes, I really do mean scm_ptobs[k].free */ | |
200 | /* rather than ftobs[k].close. .close */ | |
201 | /* is for explicit CLOSE-PORT by user */ | |
202 | mm = scm_ptobs[k].free (scmptr); | |
203 | ||
204 | if (mm != 0) | |
205 | { | |
206 | #if SCM_ENABLE_DEPRECATED == 1 | |
207 | scm_c_issue_deprecation_warning | |
208 | ("Returning non-0 from a port free function is " | |
209 | "deprecated. Use scm_gc_free et al instead."); | |
210 | scm_c_issue_deprecation_warning_fmt | |
211 | ("(You just returned non-0 while freeing a %s.)", | |
212 | SCM_PTOBNAME (k)); | |
213 | scm_i_deprecated_memory_return += mm; | |
214 | #else | |
215 | abort (); | |
216 | #endif | |
217 | } | |
218 | ||
219 | SCM_SETSTREAM (scmptr, 0); | |
220 | scm_remove_from_port_table (scmptr); | |
221 | scm_gc_ports_collected++; | |
222 | SCM_CLR_PORT_OPEN_FLAG (scmptr); | |
223 | } | |
224 | break; | |
225 | case scm_tc7_smob: | |
226 | switch SCM_TYP16 (scmptr) | |
227 | { | |
228 | case scm_tc_free_cell: | |
229 | case scm_tc16_real: | |
230 | break; | |
231 | #ifdef SCM_BIGDIG | |
232 | case scm_tc16_big: | |
233 | scm_gc_free (SCM_BDIGITS (scmptr), | |
234 | ((SCM_NUMDIGS (scmptr) * SCM_BITSPERDIG | |
235 | / SCM_CHAR_BIT)), "bignum"); | |
236 | break; | |
237 | #endif /* def SCM_BIGDIG */ | |
238 | case scm_tc16_complex: | |
239 | scm_gc_free (SCM_COMPLEX_MEM (scmptr), 2*sizeof (double), | |
240 | "complex"); | |
241 | break; | |
242 | default: | |
243 | { | |
244 | int k; | |
245 | k = SCM_SMOBNUM (scmptr); | |
246 | #if (SCM_DEBUG_CELL_ACCESSES == 1) | |
247 | if (!(k < scm_numsmob)) | |
be3ff021 HWN |
248 | { |
249 | fprintf (stderr, "undefined smob type"); | |
250 | abort(); | |
251 | } | |
c8a1bdc4 HWN |
252 | #endif |
253 | if (scm_smobs[k].free) | |
254 | { | |
255 | size_t mm; | |
256 | mm = scm_smobs[k].free (scmptr); | |
257 | if (mm != 0) | |
258 | { | |
259 | #if SCM_ENABLE_DEPRECATED == 1 | |
260 | scm_c_issue_deprecation_warning | |
261 | ("Returning non-0 from a smob free function is " | |
262 | "deprecated. Use scm_gc_free et al instead."); | |
263 | scm_c_issue_deprecation_warning_fmt | |
264 | ("(You just returned non-0 while freeing a %s.)", | |
265 | SCM_SMOBNAME (k)); | |
266 | scm_i_deprecated_memory_return += mm; | |
267 | #else | |
268 | abort(); | |
269 | #endif | |
270 | } | |
271 | } | |
272 | break; | |
273 | } | |
274 | } | |
275 | break; | |
276 | default: | |
be3ff021 HWN |
277 | fprintf (stderr, "unknown type"); |
278 | abort(); | |
c8a1bdc4 HWN |
279 | } |
280 | ||
281 | ||
282 | SCM_SET_CELL_TYPE (p, scm_tc_free_cell); | |
283 | SCM_SET_FREE_CELL_CDR (p, PTR2SCM (*free_list)); | |
284 | *free_list = PTR2SCM (p); | |
285 | free_count ++; | |
286 | } | |
eab1b259 HWN |
287 | |
288 | --scm_gc_running_p; | |
c8a1bdc4 HWN |
289 | return free_count; |
290 | } | |
291 | #undef FUNC_NAME | |
292 | ||
293 | ||
294 | /* | |
295 | Like sweep, but no complicated logic to do the sweeping. | |
296 | */ | |
297 | int | |
1383773b HWN |
298 | scm_i_init_card_freelist (scm_t_cell * card, SCM *free_list, |
299 | scm_t_heap_segment*seg) | |
c8a1bdc4 | 300 | { |
1383773b | 301 | int span = seg->span; |
c8a1bdc4 HWN |
302 | scm_t_cell *end = card + SCM_GC_CARD_N_CELLS; |
303 | scm_t_cell *p = end - span; | |
304 | ||
1383773b HWN |
305 | scm_t_c_bvec_long * bvec_ptr = (scm_t_c_bvec_long* ) seg->bounds[1]; |
306 | int idx = (card - seg->bounds[0]) / SCM_GC_CARD_N_CELLS; | |
307 | ||
308 | bvec_ptr += idx *SCM_GC_CARD_BVEC_SIZE_IN_LONGS; | |
309 | SCM_GC_CELL_BVEC (card) = bvec_ptr; | |
310 | ||
c8a1bdc4 HWN |
311 | /* |
312 | ASSUMPTION: n_header_cells <= 2. | |
313 | */ | |
314 | for (; p > card; p -= span) | |
315 | { | |
316 | SCM_SET_CELL_TYPE (p, scm_tc_free_cell); | |
317 | SCM_SET_FREE_CELL_CDR (p, PTR2SCM (*free_list)); | |
318 | *free_list = PTR2SCM (p); | |
319 | } | |
320 | ||
321 | return SCM_GC_CARD_N_CELLS - SCM_MAX(span, SCM_GC_CARD_N_HEADER_CELLS); | |
322 | } | |
323 | ||
324 | ||
eab1b259 | 325 | |
c8a1bdc4 HWN |
326 | #if 0 |
327 | /* | |
328 | These functions are meant to be called from GDB as a debug aid. | |
329 | ||
1383773b | 330 | I've left them as a convenience for future generations. --hwn. |
c8a1bdc4 HWN |
331 | */ |
332 | ||
333 | ||
334 | int scm_gc_marked_p (SCM obj); | |
335 | scm_t_cell * scm_gc_get_card (SCM obj); | |
336 | long * scm_gc_get_bvec (SCM obj); | |
337 | ||
338 | typedef struct scm_t_list_cell_struct { | |
339 | scm_t_bits car; | |
340 | struct scm_t_list_cell_struct * cdr; | |
341 | } scm_t_list_cell; | |
342 | ||
eab1b259 HWN |
343 | |
344 | typedef struct scm_t_double_cell | |
345 | { | |
346 | scm_t_bits word_0; | |
347 | scm_t_bits word_1; | |
348 | scm_t_bits word_2; | |
349 | scm_t_bits word_3; | |
350 | } scm_t_double_cell; | |
351 | ||
352 | ||
c8a1bdc4 HWN |
353 | int |
354 | scm_gc_marked_p (SCM obj) | |
355 | { | |
356 | return SCM_GC_MARK_P(obj); | |
357 | } | |
358 | ||
359 | scm_t_cell * | |
360 | scm_gc_get_card (SCM obj) | |
361 | { | |
362 | return SCM_GC_CELL_CARD(obj); | |
363 | } | |
364 | ||
365 | long * | |
366 | scm_gc_get_bvec (SCM obj) | |
367 | { | |
368 | return SCM_GC_CARD_BVEC(SCM_GC_CELL_CARD(obj)); | |
369 | } | |
370 | #endif |