2 |
- |
1 |
/* Copyright (C) 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises. All rights reserved.
|
|
|
2 |
|
|
|
3 |
This software is provided AS-IS with no warranty, either express or
|
|
|
4 |
implied.
|
|
|
5 |
|
|
|
6 |
This software is distributed under license and may not be copied,
|
|
|
7 |
modified or distributed except as expressly authorized under the terms
|
|
|
8 |
of the license contained in the file LICENSE in this distribution.
|
|
|
9 |
|
|
|
10 |
For more information about licensing, please refer to
|
|
|
11 |
http://www.ghostscript.com/licensing/. For information on
|
|
|
12 |
commercial licensing, go to http://www.artifex.com/licensing/ or
|
|
|
13 |
contact Artifex Software, Inc., 101 Lucas Valley Road #110,
|
|
|
14 |
San Rafael, CA 94903, U.S.A., +1(415)492-9861.
|
|
|
15 |
*/
|
|
|
16 |
|
|
|
17 |
/* $Id: ireclaim.c,v 1.7 2003/09/03 03:22:59 giles Exp $ */
|
|
|
18 |
/* Interpreter's interface to garbage collector */
|
|
|
19 |
#include "ghost.h"
|
|
|
20 |
#include "ierrors.h"
|
|
|
21 |
#include "gsstruct.h"
|
|
|
22 |
#include "iastate.h"
|
|
|
23 |
#include "icontext.h"
|
|
|
24 |
#include "interp.h"
|
|
|
25 |
#include "isave.h" /* for isstate.h */
|
|
|
26 |
#include "isstate.h" /* for mem->saved->state */
|
|
|
27 |
#include "dstack.h" /* for dsbot, dsp, dict_set_top */
|
|
|
28 |
#include "estack.h" /* for esbot, esp */
|
|
|
29 |
#include "ostack.h" /* for osbot, osp */
|
|
|
30 |
#include "opdef.h" /* for defining init procedure */
|
|
|
31 |
#include "store.h" /* for make_array */
|
|
|
32 |
|
|
|
33 |
/* Import preparation and cleanup routines. */
|
|
|
34 |
extern void ialloc_gc_prepare(gs_ref_memory_t *);
|
|
|
35 |
|
|
|
36 |
/* Forward references */
|
|
|
37 |
private void gs_vmreclaim(gs_dual_memory_t *, bool);
|
|
|
38 |
|
|
|
39 |
/* Initialize the GC hook in the allocator. */
|
|
|
40 |
private int ireclaim(gs_dual_memory_t *, int);
|
|
|
41 |
private int
|
|
|
42 |
ireclaim_init(i_ctx_t *i_ctx_p)
|
|
|
43 |
{
|
|
|
44 |
gs_imemory.reclaim = ireclaim;
|
|
|
45 |
return 0;
|
|
|
46 |
}
|
|
|
47 |
|
|
|
48 |
/* GC hook called when the allocator signals a GC is needed (space = -1), */
|
|
|
49 |
/* or for vmreclaim (space = the space to collect). */
|
|
|
50 |
private int
|
|
|
51 |
ireclaim(gs_dual_memory_t * dmem, int space)
|
|
|
52 |
{
|
|
|
53 |
bool global;
|
|
|
54 |
gs_ref_memory_t *mem;
|
|
|
55 |
|
|
|
56 |
if (space < 0) {
|
|
|
57 |
/* Determine which allocator exceeded the limit. */
|
|
|
58 |
int i;
|
|
|
59 |
|
|
|
60 |
mem = dmem->space_global; /* just in case */
|
|
|
61 |
for (i = 0; i < countof(dmem->spaces_indexed); ++i) {
|
|
|
62 |
mem = dmem->spaces_indexed[i];
|
|
|
63 |
if (mem == 0)
|
|
|
64 |
continue;
|
|
|
65 |
if (mem->gc_status.requested > 0 ||
|
|
|
66 |
((gs_ref_memory_t *)mem->stable_memory)->gc_status.requested > 0
|
|
|
67 |
)
|
|
|
68 |
break;
|
|
|
69 |
}
|
|
|
70 |
} else {
|
|
|
71 |
mem = dmem->spaces_indexed[space >> r_space_shift];
|
|
|
72 |
}
|
|
|
73 |
if_debug3('0', "[0]GC called, space=%d, requestor=%d, requested=%ld\n",
|
|
|
74 |
space, mem->space, (long)mem->gc_status.requested);
|
|
|
75 |
global = mem->space != avm_local;
|
|
|
76 |
/* Since dmem may move, reset the request now. */
|
|
|
77 |
ialloc_reset_requested(dmem);
|
|
|
78 |
gs_vmreclaim(dmem, global);
|
|
|
79 |
ialloc_set_limit(mem);
|
|
|
80 |
if (space < 0) {
|
|
|
81 |
gs_memory_status_t stats;
|
|
|
82 |
ulong allocated;
|
|
|
83 |
|
|
|
84 |
/* If the ammount still allocated after the GC is complete */
|
|
|
85 |
/* exceeds the max_vm setting, then return a VMerror */
|
|
|
86 |
gs_memory_status((gs_memory_t *) mem, &stats);
|
|
|
87 |
allocated = stats.allocated;
|
|
|
88 |
if (mem->stable_memory != (gs_memory_t *)mem) {
|
|
|
89 |
gs_memory_status(mem->stable_memory, &stats);
|
|
|
90 |
allocated += stats.allocated;
|
|
|
91 |
}
|
|
|
92 |
if (allocated >= mem->gc_status.max_vm) {
|
|
|
93 |
/* We can't satisfy this request within max_vm. */
|
|
|
94 |
return_error(e_VMerror);
|
|
|
95 |
}
|
|
|
96 |
}
|
|
|
97 |
return 0;
|
|
|
98 |
}
|
|
|
99 |
|
|
|
100 |
/* Interpreter entry to garbage collector. */
|
|
|
101 |
private void
|
|
|
102 |
gs_vmreclaim(gs_dual_memory_t *dmem, bool global)
|
|
|
103 |
{
|
|
|
104 |
/* HACK: we know the gs_dual_memory_t is embedded in a context state. */
|
|
|
105 |
i_ctx_t *i_ctx_p =
|
|
|
106 |
(i_ctx_t *)((char *)dmem - offset_of(i_ctx_t, memory));
|
|
|
107 |
gs_ref_memory_t *lmem = dmem->space_local;
|
|
|
108 |
int code = context_state_store(i_ctx_p);
|
|
|
109 |
gs_ref_memory_t *memories[5];
|
|
|
110 |
gs_ref_memory_t *mem;
|
|
|
111 |
int nmem, i;
|
|
|
112 |
|
|
|
113 |
memories[0] = dmem->space_system;
|
|
|
114 |
memories[1] = mem = dmem->space_global;
|
|
|
115 |
nmem = 2;
|
|
|
116 |
if (lmem != dmem->space_global)
|
|
|
117 |
memories[nmem++] = lmem;
|
|
|
118 |
for (i = nmem; --i >= 0;) {
|
|
|
119 |
mem = memories[i];
|
|
|
120 |
if (mem->stable_memory != (gs_memory_t *)mem)
|
|
|
121 |
memories[nmem++] = (gs_ref_memory_t *)mem->stable_memory;
|
|
|
122 |
}
|
|
|
123 |
|
|
|
124 |
/****** ABORT IF code < 0 ******/
|
|
|
125 |
for (i = nmem; --i >= 0; )
|
|
|
126 |
alloc_close_chunk(memories[i]);
|
|
|
127 |
|
|
|
128 |
/* Prune the file list so it won't retain potentially collectible */
|
|
|
129 |
/* files. */
|
|
|
130 |
|
|
|
131 |
for (i = (global ? i_vm_system : i_vm_local);
|
|
|
132 |
i < countof(dmem->spaces_indexed);
|
|
|
133 |
++i
|
|
|
134 |
) {
|
|
|
135 |
gs_ref_memory_t *mem = dmem->spaces_indexed[i];
|
|
|
136 |
|
|
|
137 |
if (mem == 0 || (i > 0 && mem == dmem->spaces_indexed[i - 1]))
|
|
|
138 |
continue;
|
|
|
139 |
if (mem->stable_memory != (gs_memory_t *)mem)
|
|
|
140 |
ialloc_gc_prepare((gs_ref_memory_t *)mem->stable_memory);
|
|
|
141 |
for (;; mem = &mem->saved->state) {
|
|
|
142 |
ialloc_gc_prepare(mem);
|
|
|
143 |
if (mem->saved == 0)
|
|
|
144 |
break;
|
|
|
145 |
}
|
|
|
146 |
}
|
|
|
147 |
|
|
|
148 |
/* Do the actual collection. */
|
|
|
149 |
|
|
|
150 |
{
|
|
|
151 |
void *ctxp = i_ctx_p;
|
|
|
152 |
gs_gc_root_t context_root;
|
|
|
153 |
|
|
|
154 |
gs_register_struct_root((gs_memory_t *)lmem, &context_root,
|
|
|
155 |
&ctxp, "i_ctx_p root");
|
|
|
156 |
GS_RECLAIM(&dmem->spaces, global);
|
|
|
157 |
gs_unregister_root((gs_memory_t *)lmem, &context_root, "i_ctx_p root");
|
|
|
158 |
i_ctx_p = ctxp;
|
|
|
159 |
dmem = &i_ctx_p->memory;
|
|
|
160 |
}
|
|
|
161 |
|
|
|
162 |
/* Update caches not handled by context_state_load. */
|
|
|
163 |
|
|
|
164 |
*systemdict = *ref_stack_index(&d_stack, ref_stack_count(&d_stack) - 1);
|
|
|
165 |
|
|
|
166 |
/* Reload the context state. */
|
|
|
167 |
|
|
|
168 |
code = context_state_load(i_ctx_p);
|
|
|
169 |
/****** ABORT IF code < 0 ******/
|
|
|
170 |
|
|
|
171 |
/* Update the cached value pointers in names. */
|
|
|
172 |
|
|
|
173 |
dicts_gc_cleanup();
|
|
|
174 |
|
|
|
175 |
/* Reopen the active chunks. */
|
|
|
176 |
|
|
|
177 |
for (i = 0; i < nmem; ++i)
|
|
|
178 |
alloc_open_chunk(memories[i]);
|
|
|
179 |
}
|
|
|
180 |
|
|
|
181 |
/* ------ Initialization procedure ------ */
|
|
|
182 |
|
|
|
183 |
const op_def ireclaim_l2_op_defs[] =
|
|
|
184 |
{
|
|
|
185 |
op_def_end(ireclaim_init)
|
|
|
186 |
};
|